master
kikimor 8 months ago
parent f6c78a20a3
commit 0ffd79cee9

@ -6,51 +6,50 @@
<component name="ChangeListManager">
<list default="true" id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="commit unversioned files ;)">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/mixins/LineFiltweFormMixin.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/mixins/LineFiltweFormMixin.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/mixins/crudListViewMixin.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/mixins/crudListViewMixin.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/settings.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/settings.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/forms.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/forms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/views/client_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/views/client_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/booking/views/employee_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/booking/views/employee_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/forms/company.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/forms/company.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/forms/line.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/forms/line.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/utils/utils.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/utils/utils.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/views/barrier_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/views/barrier_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/views/client_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/views/client_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/views/employee_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/views/employee_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/views/shared_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/views/shared_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/forms.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/forms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/services.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/services.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/views/barrier_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/views/barrier_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/containers/views/employee_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/containers/views/employee_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/populate_database.txt" beforeDir="false" afterPath="$PROJECT_DIR$/populate_database.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/preinfo/forms.py" beforeDir="false" afterPath="$PROJECT_DIR$/preinfo/forms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/damages_api/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/damages_api/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/payments/forms.py" beforeDir="false" afterPath="$PROJECT_DIR$/payments/forms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/payments/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/payments/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/payments/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/payments/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/payments/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/payments/views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/preinfo/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/preinfo/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/preinfo/views/client_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/preinfo/views/client_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/preinfo/views/employee_views.py" beforeDir="false" afterPath="$PROJECT_DIR$/preinfo/views/employee_views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/js/crud-list.js" beforeDir="false" afterPath="$PROJECT_DIR$/static/js/crud-list.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/base.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/base.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/dashboard-content.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/dashboard-content.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/forms.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/forms.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/sidebar.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/sidebar.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/styles.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/styles.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/static/styles/tables.css" beforeDir="false" afterPath="$PROJECT_DIR$/static/styles/tables.css" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/barrier/barrier-base.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/barrier/barrier-base.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/barrier/barrier-dashboard.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/barrier/barrier-dashboard.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/chatgpt/round table.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/chatgpt/round table.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-base.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-base.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-dashboard-content.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-dashboard-content.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-sidebar.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-sidebar.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/booking-edit.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/booking-edit.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/booking-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/booking-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/preinfo-create.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/preinfo-create.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/preinfo-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/preinfo-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/container-expedition.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/container-expedition.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/container-receive.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/container-receive.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/line-create.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/line-create.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/line-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/line-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client/line-update.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client/line-update.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee-base.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee-base.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee-dashboard-content.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee-dashboard-content.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee-sidebar.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee-sidebar.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/booking-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/booking-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/company-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/company-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/containers-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/containers-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/line-create.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/line-create.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/line-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/line-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/line-update.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/line-update.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/payment-create.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/payment-create.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/payment-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/payment-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/employee/preinfo-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/employee/preinfo-list.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/list-crud.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/list-crud.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/registration/user-list.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/registration/user-list.html" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -65,9 +64,9 @@
<option name="RECENT_TEMPLATES">
<list>
<option value="JavaScript File" />
<option value="Python Script" />
<option value="HTML File" />
<option value="CSS File" />
<option value="HTML File" />
<option value="Python Script" />
</list>
</option>
</component>
@ -89,10 +88,11 @@
"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/templates/client",
"last_opened_file_path": "C:/dev_projects/python/Django/DepoT/templates/employee",
"list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
@ -109,17 +109,18 @@
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<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" />
<recent name="C:\dev_projects\python\Django\DepoT\static\styles" />
</key>
<key name="MoveFile.RECENT_KEYS">
<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" />
<recent name="C:\dev_projects\python\Django\DepoT\containers\views" />
<recent name="C:\dev_projects\python\Django\DepoT\preinfo\views" />
<recent name="C:\dev_projects\python\Django\DepoT\templates\barrier" />
</key>
</component>
<component name="RunManager">
@ -167,7 +168,7 @@
<updated>1750784740296</updated>
<workItem from="1750784741367" duration="240087000" />
<workItem from="1752078951079" duration="106000" />
<workItem from="1752079161329" duration="40180000" />
<workItem from="1752079161329" duration="97669000" />
</task>
<task id="LOCAL-00001" summary="Add IntelliJ IDEA project configuration files&#10;&#10;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" />
@ -282,16 +283,36 @@
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/containers/views/employee_views.py</url>
<line>110</line>
<option name="timeStamp" value="31" />
</line-breakpoint>
<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$/damages_api/views.py</url>
<line>15</line>
<option name="timeStamp" value="62" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/damages_api/views.py</url>
<line>39</line>
<option name="timeStamp" value="63" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/common/utils/owncloud_utls.py</url>
<line>29</line>
<option name="timeStamp" value="64" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/payments/views.py</url>
<line>40</line>
<option name="timeStamp" value="65" />
</line-breakpoint>
</breakpoints>
<default-breakpoints>
<breakpoint type="python-exception">

@ -25,7 +25,7 @@ SECRET_KEY = "django-insecure-g%187p84o9^rr)3#9@r3n^o2v1i%@6=+puxm7hlodg+kbsk%n#
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
ALLOWED_HOSTS = ['192.168.24.43', '127.0.0.1', 'localhost', ]
# Application definition
@ -36,6 +36,7 @@ PROJECT_APPS = [
"common",
"containers",
'preinfo',
'payments',
]
@ -46,6 +47,8 @@ INSTALLED_APPS = [
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"damages_api",
] + PROJECT_APPS
MIDDLEWARE = [
@ -147,7 +150,19 @@ 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"
import environ
env = environ.Env()
import os
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))
OWNCLOUD_URL = env('OWNCLOUD_URL')
OWNCLOUD_USER = env('OWNCLOUD_USER')
OWNCLOUD_PASSWORD = env('OWNCLOUD_PASSWORD')
OWNCLOUD_DAMAGES_FOLDER = env('OWNCLOUD_DAMAGES_FOLDER')

@ -25,4 +25,6 @@ urlpatterns = [
path('preinfo/', include('preinfo.urls')),
path('container/', include('containers.urls')),
path('booking/', include('booking.urls')),
path('payment/', include('payments.urls')),
path('damages/', include('damages_api.urls')),
]

@ -1,9 +1,13 @@
from django.urls import path
from django.urls import path, include
from django.contrib.auth import views as auth_views
from accounts import views
urlpatterns = [
path('login/', views.DepotLoginView.as_view(), name='login'),
path('relogin/', auth_views.logout_then_login, name='relogin'),
path('register/', views.RegisterView.as_view(), name='register'),
path('user/', include([
path('', views.UserListView.as_view(), name='user_list'),
path('register/', views.RegisterView.as_view(), name='user_register'),
path('<int:pk>/update/', views.UserUpdateView.as_view(), name='user_update'),
])),
]

@ -86,13 +86,73 @@ class RegisterView(AccessMixin, FormView):
return form
class UserListView(ListView):
template_name = 'registration/register.html'
# form_class = RegisterForm
template_name = 'registration/user-list.html'
model = get_user_model()
success_url = reverse_lazy('dashboard')
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
class UserEditView(UpdateView):
class UserUpdateView(UpdateView):
template_name = 'registration/register.html'
form_class = RegisterForm
model = get_user_model()
success_url = reverse_lazy('dashboard')
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

@ -6,5 +6,11 @@ from booking.models import Booking
class BookingListView(ListView):
template_name = 'employee/booking-list.html'
model = Booking
context_object_name = 'bookings'
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

@ -0,0 +1,17 @@
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):
...

@ -0,0 +1,17 @@
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,7 +1,9 @@
from django.urls import path, include
from common.views.barrier_views import BarrierDashboardView
from common.views.employee_views import EmployeeDashboardView
from common.views.client_views import ClientDashboardView
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'),
@ -10,5 +12,25 @@ urlpatterns = [
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('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('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'),
])),
]

@ -8,7 +8,7 @@ def filter_queryset_by_user(queryset, user):
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}')
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()}")

@ -1,5 +1,13 @@
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import render
from django.views.generic import TemplateView
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):
@ -11,3 +19,122 @@ class ClientDashboardView(TemplateView):
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,6 +1,11 @@
from django.views.generic import TemplateView
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
@ -21,3 +26,97 @@ class EmployeeDashboardView(TemplateView):
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
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
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)

@ -73,3 +73,17 @@ class ContainerHistory(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,11 +1,12 @@
from django.urls import include, path
from containers.views.employee_views import ContainersListView
from containers.views.employee_views import ContainersListView, ReportContainersUnpaidListView
from containers.views.barrier_views import ContainerReceive, ContainerExpedition, ContainerSearchView
urlpatterns = [
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/<int:pk>/', include([
path('receive/', ContainerReceive.as_view(), name='container_receive'),
path('expedition/', ContainerExpedition.as_view(), name='container_expedition'),

@ -1,13 +1,52 @@
from django.views.generic import ListView
from common.models import CompanyModel
from containers.models import Container
class ContainersListView(ListView):
template_name = 'employee/containers-list.html'
model = Container
context_object_name = 'containers'
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):
return Container.objects.filter(expedited=False).order_by('-received_on')
class ReportContainersUnpaidListView(ListView):
template_name = 'employee/payment-list.html'
model = Container
context_object_name = 'objects'
paginate_by = 30 # Number of payments 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
context['companies'] = CompanyModel.objects.all().order_by('name')
return context
def get_queryset(self):
queryset = self.model.objects.filter(expedited=True)
# Get date from request parameters
date = self.request.GET.get('date')
if date:
queryset = queryset.filter(expedited_on__date__lte=date)
# Get company from request parameters
company = self.request.GET.get('company')
if company:
queryset = queryset.filter(line__company_id=company)
# Add payment filter to show only unpaid containers
queryset = queryset.filter(payment_containers__isnull=True)
return queryset.order_by('-expedited_on')

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

@ -0,0 +1,6 @@
from django.apps import AppConfig
class DamagesApiConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "damages_api"

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,7 @@
from django.urls import path
from damages_api.views import Damages
urlpatterns = [
path('<int:depot_id>', Damages.as_view(), name='damages_list'),
]

@ -0,0 +1,43 @@
import base64
import os
import tempfile
from datetime import datetime
from django.core.exceptions import BadRequest
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from common.utils.owncloud_utls import Owncloud
from containers.models import ContainerPhotos
class Damages(APIView):
def post(self, request, depot_id):
data = request.get_json()
photo = data.pop("photo")
extension = data.pop("photo_extension")
with tempfile.NamedTemporaryFile(suffix=f'.{extension}', delete=False) as temp_file:
try:
temp_file.write(base64.b64decode(photo.encode("utf-8")))
temp_file.flush()
own_filename = Owncloud.upload_damage_photo(temp_file.name, depot_id)
container_photo = ContainerPhotos()
container_photo.container.pk = depot_id
container_photo.photo = own_filename
container_photo.uploaded_on = datetime.now()
container_photo.uploaded_by = request.user
container_photo.save()
except Exception as ex:
raise BadRequest("Invalid photo encoding")
finally:
os.unlink(temp_file.name)
return Response(status=status.HTTP_201_CREATED)
def get(self, request, depot_id):
return Owncloud.get_damages(depot_id)

@ -0,0 +1,19 @@
from django.forms import ModelForm, CheckboxSelectMultiple
from containers.models import Container
from payments.models import Payment
class PaymentCreateForm(ModelForm):
class Meta:
model = Payment
fields = ['total_amount', 'company', 'description']
widgets = {
'containers': CheckboxSelectMultiple(),
}
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# self.fields['containers'].queryset = Container.objects.all()
# self.fields['containers'].label_from_instance = lambda obj: f"{obj.name} ({obj.company.name})"

@ -23,3 +23,28 @@ class PaymentItem(models.Model):
container = models.ForeignKey(Container, related_name='payment_containers', on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=10, decimal_places=2)
class ContainerTariffPeriod(models.Model):
CONTAINER_SIZE_CHOICES = [
('20', '20 feet'),
('40', '40/45 feet'),
]
container_size = models.CharField(max_length=2, choices=CONTAINER_SIZE_CHOICES)
from_days = models.PositiveIntegerField()
to_days = models.PositiveIntegerField(null=True, blank=True) # null for last period (16+ days)
daily_rate = models.DecimalField(max_digits=6, decimal_places=2)
class Meta:
unique_together = ['container_size', 'from_days']
ordering = ['container_size', 'from_days']
class AdditionalFees(models.Model):
reefer_daily_supplement = models.DecimalField(max_digits=6, decimal_places=2, default=3.00)
sweeping_fee = models.DecimalField(max_digits=6, decimal_places=2, default=35.00)
fumigation_fee = models.DecimalField(max_digits=6, decimal_places=2, default=75.00)
class Meta:
verbose_name = 'Additional Fees'
verbose_name_plural = 'Additional Fees'

@ -0,0 +1,7 @@
from django.urls import path
from payments.views import PaymentCreateView
urlpatterns = [
path("create/", PaymentCreateView.as_view(), name="payments_create"),
]

@ -1,3 +1,47 @@
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView, CreateView
from common.models import CompanyModel
from containers.models import Container
from payments.forms import PaymentCreateForm
from payments.models import Payment
# Create your views here.
class PaymentCreateView(CreateView):
model = Payment
form_class = PaymentCreateForm
template_name = 'employee/payment-create.html'
success_url = reverse_lazy('payment-list')
def form_valid(self, form):
container_ids = self.request.POST.getlist('containers')
payment = form.save(commit=False)
payment.save()
payment.containers.set(container_ids)
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
container_ids = self.request.GET.get('containers', '').split(',')
# Filter only valid IDs (non-empty strings that can be converted to int)
container_ids = [int(id) for id in container_ids if id.strip().isdigit()]
if container_ids:
# Get selected containers
context['containers'] = Container.objects.filter(
id__in=container_ids,
expedited=True,
payment_containers__isnull=True
).order_by('-expedited_on')
return context
def get_form(self, form_class=None):
form = super().get_form(form_class)
company_pk = self.request.GET.get('company', '')
form.fields['company'].initial = company_pk
# container_ids = [int(id) for id in container_ids if id.strip().isdigit()]
# form.fields['containers'].initial = container_ids
return form

@ -6,7 +6,7 @@ urlpatterns = [
path('client/', include([
path('', ClientPreinfoView.as_view(), name='client_preinfo'),
path('create/', ClientPreinfoCreateView.as_view(), name='client_preinfo_create'),
path('update/<int:pk>/', ClientPreinfoUpdateView.as_view(), name='client_preinfo_update'),
path('<int:pk>/update/', ClientPreinfoUpdateView.as_view(), name='client_preinfo_update'),
])),
path('check-preinfo/', check_preinfo, name='check_preinfo'),
path('preinfo-search/', PreinfoSearchView.as_view(), name='preinfo_search'),

@ -1,17 +1,5 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.forms import forms
from django.forms.widgets import HiddenInput
from django.http import JsonResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy
from django.utils import timezone
from django.views import View
from django.views.generic import TemplateView, FormView, CreateView, ListView
from DepoT.mixins.crudListViewMixin import CRUDListViewMixin
from common.models import ContainerTypeModel, LinesModel
from common.utils.utils import filter_queryset_by_user, get_preinfo_by_number
from preinfo.forms import PreinfoBaseForm, PreinfoCreateForm, PreinfoEditForm
from preinfo.models import Preinfo

@ -1,36 +1,73 @@
document.addEventListener('DOMContentLoaded', function() {
const editBtn = document.getElementById('editBtn');
const deleteBtn = document.getElementById('deleteBtn');
const objectIdInput = document.getElementById('objectIdInput');
const rows = document.querySelectorAll('.selectable-row');
const table = document.getElementById('objectTable');
if (!table) return;
if (editBtn) {
editBtn.setAttribute('disabled', '');
const selectionMode = table.dataset.selectionMode || 'single';
const toggleSelectAllBtn = document.getElementById('toggleSelectAllBtn');
if (table.dataset.selectionMode === 'multiple') {
toggleSelectAllBtn.style.display = 'inline-block';
}
if (deleteBtn) {
deleteBtn.setAttribute('disabled', '');
table.addEventListener('click', function(e) {
const row = e.target.closest('.selectable-row');
if (!row) return;
const checkbox = row.querySelector('input[type="checkbox"]');
if (!checkbox) return;
if (selectionMode === 'single') {
// Deselect all other rows
table.querySelectorAll('.selected-row').forEach(selectedRow => {
if (selectedRow !== row) {
selectedRow.classList.remove('selected-row');
selectedRow.querySelector('input[type="checkbox"]').checked = false;
}
});
}
rows.forEach(row => {
row.addEventListener('click', function() {
// Remove previous selection
document.querySelector('.selected-row')?.classList.remove('selected-row');
// Toggle current row
row.classList.toggle('selected-row');
checkbox.checked = !checkbox.checked;
// Select current row
this.classList.add('selected-row');
// Update buttons state
const selectedRows = table.querySelectorAll('.selected-row');
document.querySelectorAll('[data-requires-selection]').forEach(button => {
button.disabled = selectedRows.length === 0;
});
// Handle edit/delete buttons from original crud-list.js
const objectId = row.dataset.id;
const editBtn = document.getElementById('editBtn');
const deleteBtn = document.getElementById('deleteBtn');
const objectId = this.dataset.id;
if (editBtn) {
editBtn.removeAttribute('disabled'); // Remove disabled attribute completely
editBtn.href = editBtn.dataset.url.replace('0', objectId);
editBtn.removeAttribute('disabled');
editBtn.href = editBtn.dataset.url?.replace('0', objectId);
}
if (deleteBtn) {
deleteBtn.removeAttribute('disabled');
}
});
let allSelected = false;
toggleSelectAllBtn.addEventListener('click', function() {
const rows = table.querySelectorAll('.selectable-row');
allSelected = !allSelected;
// Check the hidden radio button
const radio = this.querySelector('input[type="radio"]');
radio.checked = true;
rows.forEach(row => {
const checkbox = row.querySelector('input[type="checkbox"]');
checkbox.checked = allSelected;
row.classList.toggle('selected-row', allSelected);
});
// Update other buttons state
document.querySelectorAll('[data-requires-selection]').forEach(button => {
button.disabled = !allSelected;
});
// Update button text
this.textContent = allSelected ? 'Unselect All' : 'Select All';
});
});

@ -246,3 +246,36 @@ button[type="submit"]:hover {
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
overflow: hidden; /* Ensure content doesn't overflow */
}
.filter-form {
background-color: #f8f9fa;
padding: 1rem;
border-radius: 0.25rem;
margin-bottom: 1rem;
}
.filter-form form {
display: flex;
align-items: center;
gap: 1rem;
max-width: none;
width: 100%;
}
.filter-form .form-group {
display: flex;
align-items: center;
margin-bottom: 0;
}
.filter-form .form-control {
width: auto;
min-width: 200px;
}
.me-2 {
margin-right: 0.5rem;
}
.filter-form span {
display: flex;
align-items: center;
width: 100%;
}

@ -105,3 +105,11 @@
.logout:hover {
border: 1px solid #a57d52;
}
a.nav-item,
a.nav-item:visited,
a.nav-item:hover,
a.nav-item:active {
color: inherit; /* or specify your desired color */
text-decoration: none;
}

@ -97,6 +97,21 @@ tbody tr {
border-bottom: 1px solid #eee;
}
.dashboard-table,
table td {
text-align: center;
}
.dashboard-table,
table td.td-left {
text-align: left;
}
.dashboard-table,
table td.td-right {
text-align: right;
}
/*Rename dashboard-table to match exactly with your HTML */
.dashboard-table,
@ -126,7 +141,6 @@ tfoot {
table th,
table td {
padding: 8px;
text-align: center;
border-right: 1px solid #E1C6A8; /* Add vertical borders */
border-bottom: 1px solid #E1C6A8; /* Add horizontal borders */
}
@ -194,3 +208,4 @@ table tr:last-child td {
color: #990000;
}

@ -19,26 +19,6 @@
</aside>
<main class="content-area">
{# <header class="top-nav">#}
{# <div class="nav-container">#}
{# <div class="nav-left">#}
{# <h2 class="page-title">Dashboard</h2>#}
{# </div>#}
{# <div class="nav-right">#}
{# <button class="icon-button">#}
{# <svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">#}
{# <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />#}
{# </svg>#}
{# </button>#}
{# <button class="icon-button">#}
{# <svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">#}
{# <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />#}
{# </svg>#}
{# </button>#}
{# </div>#}
{# </div>#}
{# </header>#}
<div class="content">
{% block content %}
{% endblock content %}

@ -8,6 +8,8 @@
{% url 'client_preinfo' as client_preinfo_url %}
{% url 'client_booking' as client_booking_url %}
{% url 'register' as register_url %}
{% url 'client_company' as client_company_url %}
{% url 'client_line' as client_line_url %}
<nav class="nav-menu">
<div class="section-title">Main</div>
@ -39,8 +41,8 @@
</svg>
Reports
</a>
{% if request.user.UserType == 'CA' %}
<div class="section-title account">Account</div>
{% if request.user.UserType == 'CA' or 1 == 1 %}
<div class="section-title account">Nomenclatures</div>
<a href="{{ register_url }}" class="nav-item {% if request.path == register_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
@ -48,6 +50,15 @@
</svg>
Accounts
</a>
<a href="{{ client_line_url }}" class="nav-item {% if request.path == client_line_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Lines
</a>
{% endif %}
</nav>
<div class="user-profile">

@ -1,4 +1,4 @@
{% extends 'employee-base.html' %}
{% extends 'client-base.html' %}
{% load static %}
{% block content %}

@ -3,14 +3,12 @@
{% block table_header %}
<th style="display: none;">Select</th>
<th>Company name</th>
<th>Line name</th>
<th>Short name</th>
<th>Description</th>
{% endblock table_header %}
{% block table_data %}
<td>{{ object.company }}</td>
<td>{{ object.name }}</td>
<td>{{ object.short_name }}</td>
<td>{{ object.description }}</td>

@ -1,4 +1,4 @@
{% extends 'employee-base.html' %}
{% extends 'client-base.html' %}
{% load static %}
{% block content %}

@ -4,193 +4,26 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Employee Dashboard | Container Depot</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
}
.sidebar {
background: linear-gradient(180deg, #0f4c81 0%, #1a6baf 100%);
transition: all 0.3s;
}
.content-area {
transition: all 0.3s;
}
.nav-item {
transition: all 0.2s;
}
.nav-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.nav-item.active {
background-color: rgba(255, 255, 255, 0.2);
border-left: 4px solid white;
}
.card {
transition: all 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.tab {
transition: all 0.2s;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.form-section {
animation: slideIn 0.5s ease-in-out;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
<title>Depot Employee Dashboard | Container Depot</title>
<link rel="stylesheet" href="{% static 'styles/tables.css' %}">
<link rel="stylesheet" href="{% static 'styles/forms.css' %}">
<link rel="stylesheet" href="{% static 'styles/sidebar.css' %}">
<link rel="stylesheet" href="{% static 'styles/base.css' %}">
<link rel="stylesheet" href="{% static 'styles/dashboard-content.css' %}">
</head>
<body class="flex h-screen overflow-hidden">
<!-- Sidebar -->
<body>
<aside class="sidebar">
{% include 'employee-sidebar.html' %}
<!-- Main Content -->
<main class="content-area flex-1 overflow-y-auto">
<!-- Top Navigation -->
<header class="bg-white shadow-sm">
<div class="flex items-center justify-between px-6 py-4">
<div class="flex items-center">
<h2 class="text-xl font-semibold text-gray-800">Dashboard</h2>
</div>
<div class="flex items-center space-x-4">
<button class="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
</button>
<button class="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</button>
</div>
</div>
</header>
</aside>
<!-- Dashboard Content -->
<div class="p-6">
<main class="content-area">
<div class="content">
{% block content %}
{# {% include 'client-dashboard-content.html' %}#}
{# {% include 'client-preinfo-content.html' %}#}
{# {% include 'client-orders-content.html' %}#}
{% endblock content %}
</div>
</main>
{# <script>#}
{# // Tab Navigation#}
{# const dashboardContent = document.getElementById('dashboardContent');#}
{# const preinfoContent = document.getElementById('preinfoContent');#}
{# const ordersContent = document.getElementById('ordersContent');#}
{# #}
{# const preinfoNav = document.getElementById('preinfoNav');#}
{# const ordersNav = document.getElementById('ordersNav');#}
{# #}
{# preinfoNav.addEventListener('click', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // Update content visibility#}
{# dashboardContent.classList.remove('active');#}
{# preinfoContent.classList.add('active');#}
{# ordersContent.classList.remove('active');#}
{# #}
{# // Update navigation styling#}
{# document.querySelector('.nav-item.active').classList.remove('active');#}
{# preinfoNav.classList.add('active');#}
{# #}
{# // Update header title#}
{# document.querySelector('header h2').textContent = 'Container Preinfo';#}
{# });#}
{# #}
{# ordersNav.addEventListener('click', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // Update content visibility#}
{# dashboardContent.classList.remove('active');#}
{# preinfoContent.classList.remove('active');#}
{# ordersContent.classList.add('active');#}
{# #}
{# // Update navigation styling#}
{# document.querySelector('.nav-item.active').classList.remove('active');#}
{# ordersNav.classList.add('active');#}
{# #}
{# // Update header title#}
{# document.querySelector('header h2').textContent = 'Expedition Orders';#}
{# });#}
{# #}
{# // Damage checkbox toggle#}
{# const damageCheck = document.getElementById('damageCheck');#}
{# const damageDetails = document.getElementById('damageDetails');#}
{# #}
{# damageCheck.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# damageDetails.classList.remove('hidden');#}
{# } else {#}
{# damageDetails.classList.add('hidden');#}
{# }#}
{# });#}
{# #}
{# // Order type toggle#}
{# const specificContainer = document.getElementById('specificContainer');#}
{# const anyContainer = document.getElementById('anyContainer');#}
{# const specificContainerFields = document.getElementById('specificContainerFields');#}
{# const anyContainerFields = document.getElementById('anyContainerFields');#}
{# #}
{# specificContainer.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# specificContainerFields.classList.remove('hidden');#}
{# anyContainerFields.classList.add('hidden');#}
{# }#}
{# });#}
{# #}
{# anyContainer.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# specificContainerFields.classList.add('hidden');#}
{# anyContainerFields.classList.remove('hidden');#}
{# }#}
{# });#}
{# #}
{# // Form submissions#}
{# document.getElementById('preinfoForm').addEventListener('submit', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // In a real app, this would send data to the server#}
{# alert('Preinfo submitted successfully!');#}
{# this.reset();#}
{# });#}
{# #}
{# document.getElementById('orderForm').addEventListener('submit', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // In a real app, this would send data to the server#}
{# alert('Expedition order submitted successfully!');#}
{# this.reset();#}
{# });#}
{# #}
{# // Add more container button#}
{# document.getElementById('addMoreContainer').addEventListener('click', function() {#}
{# alert('In a real app, this would add fields for another container');#}
{# });#}
{# </script>#}
{#<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'947f86ac452d3130',t:'MTc0ODYyMTY4Mi4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>#}
</body>
</html>

@ -1,162 +1,111 @@
{% extends 'employee-base.html' %}
{% block content %}
<div id="dashboardContent" class="tab-content active">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-blue-100 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<div class="dashboard-wrapper">
<div class="stats-grid">
<div class="dashboard-card">
<div class="card-content">
<div class="icon-circle">
<svg xmlns="http://www.w3.org/2000/svg" class="dashboard-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Active Containers</h3>
<p class="text-3xl font-bold text-gray-900">{{ containers }}</p>
<p class="text-sm text-green-600">+3 since last week</p>
<div class="stat-info">
<h3>Active Containers</h3>
<p class="stat-number">{{ containers }}</p>
<p class="stat-change">+3 since last week</p>
</div>
</div>
</div>
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-green-100 text-green-600">
<div class="dashboard-card">
<div class="card-content">
<div class="icon-circle">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Preinfo Sent</h3>
<p class="text-3xl font-bold text-gray-900">{{ preinfos }}</p>
<p class="text-sm text-green-600">+5 since last week</p>
<div class="stat-info">
<h3>Active preinfos</h3>
<p class="stat-number">{{ preinfos }}</p>
<p class="stat-change">+7 since last week</p>
</div>
</div>
</div>
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-orange-100 text-orange-600">
<div class="dashboard-card">
<div class="card-content">
<div class="icon-circle">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Bookings</h3>
<p class="text-3xl font-bold text-gray-900">{{ bookings }}</p>
<p class="text-sm text-orange-600">2 require attention</p>
<div class="stat-info">
<h3>Active bookings</h3>
<p class="stat-number">{{ bookings }}</p>
<p class="stat-change">+8 since last week</p>
</div>
</div>
</div>
<!-- Other two cards similar structure -->
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Recent Container Activity</h3>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<div class="tables-grid">
<div class="dashboard-card">
<div class="card-header">
<h3>Recent Container Activity</h3>
</div>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th>Container</th>
<th>Type</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU1234567</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">40HC</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Received</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-15</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU7654321</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">20DV</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">Preinfo</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-14</td>
</tr>
<tbody>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU2468135</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">40DV</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-orange-100 text-orange-800">Order</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-13</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU1357924</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">20RF</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">Expedited</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-12</td>
<td>MSCU1234567</td>
<td>40HC</td>
<td><span class="status-tag status-received">Received</span></td>
<td>2023-06-15</td>
</tr>
<!-- Other rows similar structure -->
</tbody>
</table>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Payment Status</h3>
<div class="dashboard-card">
<div class="card-header">
<h3>Recent payments</h3>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<div class="card-body">
<table class="table">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Invoice</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th>
<th>Container</th>
<th>Type</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0042</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$1,250.00</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Paid</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-10</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0041</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$875.50</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-yellow-100 text-yellow-800">Pending</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-20</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0040</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$2,100.00</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">Overdue</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-05</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0039</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$950.25</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Paid</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-05-28</td>
</tr>
<tbody>
{# {% for container in containers %}#}
{# <tr>#}
{# <td>{{ container.number }}</td>#}
{# <td>container.container_type</td>#}
{# <td><span class="status-tag status-received">Received</span></td>#}
{# <td>{{ container.received_date }}</td>#}
{# </tr>#}
{# {% endfor %}#}
<!-- Other rows similar structure -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

@ -1,83 +1,93 @@
{% load static %}
<aside class="sidebar w-64 h-full text-white flex flex-col">
<div class="p-5 border-b border-blue-700">
<h1 class="text-xl font-bold">Container Depot</h1>
<p class="text-sm text-blue-200">Employee Portal</p>
<aside class="sidebar">
<div class="header">
<h1>Container Depot</h1>
<p class="subtitle">Line Operator Portal</p>
</div>
{% url 'employee_dashboard' as dashboard_url %}
{% url 'employee_containers' as employee_containers_url %}
{% url 'employee_bookings' as employee_bookings_url %}
{% url 'employee_preinfo' as employee_preinfo_url %}
{% url 'register' as register_url %}
{% url 'employee_company' as employee_company_url %}
{% url 'employee_line' as employee_line_url %}
{% url 'user_list' as user_list_url %}
{% url 'not_paid' as not_paid_list_url %}
<nav class="flex-grow py-4">
<div class="px-4 py-2 text-xs text-blue-300 uppercase tracking-wider">Main</div>
<a href="{% url 'dashboard' %}" class="nav-item active flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<nav class="nav-menu">
<div class="section-title">Main</div>
<a href="{{ dashboard_url }}" class="nav-item {% if request.path == dashboard_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
Dashboard
</a>
<a href="{% url 'employee_containers' %}" id="preinfoNav" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<a href="{{ employee_containers_url }}" class="nav-item {% if request.path == employee_containers_url %}active{% endif %}" id="preinfoNav">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
Available Containers
Containers
</a>
<a href="{% url 'employee_bookings' %}" id="ordersNav" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<a href="{{ employee_preinfo_url }}" class="nav-item {% if request.path == employee_preinfo_url %}active{% endif %}" id="preinfoNav">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
Container Preinfo
</a>
<a href="{{ employee_bookings_url }}" class="nav-item {% if request.path == employee_bookings_url %}active{% endif %}" id="ordersNav">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Bookings
</a>
<a href="{% url 'employee_preinfo' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
<div class="section-title account">Reports</div>
<a href="{{ not_paid_list_url }}" class="nav-item {% if request.path == not_paid_list_url %}active{% endif %}" id="ordersNav">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<g>
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm-1.95-9H15v2h-4.95a2.5 2.5 0 0 0 4.064 1.41l1.7 1.133A4.5 4.5 0 0 1 8.028 13H7v-2h1.027a4.5 4.5 0 0 1 7.788-2.543L14.114 9.59A2.5 2.5 0 0 0 10.05 11z"/>
</g>
</svg>
Preinfos
Reports
</a>
{% if request.user.UserType.ADMIN %}
<div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>
<a href="{% url 'register' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
{% if request.user.UserType == 'CA' or 1 == 1 %}
<div class="section-title account">Nomenclatures</div>
<a href="{{ user_list_url }}" class="nav-item {% if request.path == user_list_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Accounts
</a>
{# <div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>#}
<a href="{% url 'register' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<a href="{{ employee_company_url }}" class="nav-item {% if request.path == employee_company_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Companies
</a>
<a href="{% url 'register' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<a href="{{ employee_line_url }}" class="nav-item {% if request.path == employee_line_url %}active{% endif %}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Lines
</a>
{% endif %}
</nav>
<div class="p-4 border-t border-blue-700">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">
LO
</div>
<div class="ml-3">
<p class="text-sm font-medium">{{ request.user }}</p>
<p class="text-xs text-blue-300">{{ request.user.company }}</p>
<div class="user-profile">
<div class="avatar">LO</div>
<div class="user-info">
<p class="username">{{ request.user }}</p>
</div>
<a href="{% url 'login' %}" class="ml-auto text-white" >
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<a href="{% url 'login' %}" class="logout">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
</a>
</div>
</div>
</aside>
</aside>

@ -1,40 +1,43 @@
{% extends 'employee-base.html' %}
{% extends 'list-crud.html' %}
{% load static %}
{% block content %}
<table>
<tr>
<th>Status</th>
{% block table_header %}
<th style="display: none;">Select</th>
<th>Line</th>
<th>Booking №</th>
<th>Vehicles</th>
<th>Container number</th>
<th>Container type</th>
<th>Container count</th>
<th>Line</th>
<th>Carrier</th>
<th>Containers expedited</th>
<th>Container №</th>
<th>Containers count</th>
<th>Containers left</th>
<th>Vehicles</th>
<th>Vehicles left</th>
</tr>
<th>Created on</th>
<th>Created by</th>
{% endblock table_header %}
{% block table_data %}
<td>{{ object.line.short_name }}</td>
<td>{{ object.number }}</td>
<td>{{ object.container_type }}</td>
<td>{{ object.container_number }}</td>
<td>{{ object.container_count }}</td>
<td>{{ object.containers_left }}</td>
<td>{{ object.vehicles }}</td>
<td>{{ object.vehicles_left }}</td>
<td>{{ object.created_on }}</td>
<td>{{ object.created_by.username }}</td>
{% endblock %}
{% for booking in bookings %}
<tr>
<td>{{ booking.status }}</td>
<td>{{ booking.number }}</td>
<td>{{ booking.vehicles }}</td>
<td>{{ booking.container_number }}</td>
<td>{{ booking.container_type }}</td>
<td>{{ booking.container_count }}</td>
<td>{{ booking.line.short_name }}</td>
<td>{{ booking.carrier }}</td>
<td>{{ booking.container_expedited_count }}</td>
<td>{{ booking.vehicles_left }}</td>
<td>
{# <a href="{% url 'employee:preinfo_edit' preinfo.id %}">Edit</a> |#}
{# <a href="{% url 'employee:preinfo_delete' preinfo.id %}">Delete</a>#}
</td>
</tr>
{% block buttons %}
{# <a href="{% url 'employee_booking_create' %}" class="btn btn-primary">Create booking</a>#}
{# <a href="#" id="editBtn" data-url="{% url 'client_booking_update' pk=0 %}" class="btn btn-primary" disabled>Edit Preinfo</a>#}
{# <button id="deleteButton" class="btn btn-danger">Delete Preinfo</button>#}
{% endblock buttons %}
{% endfor %}
{% block create_modal_header %}
<h2>Create Booking</h2>
{% endblock %}
</table>
{% endblock content %}
{% block modal_header %}
<h2>Edit Booking</h2>
{% endblock modal_header %}

@ -15,8 +15,8 @@
{% endblock %}
{% block buttons %}
<a href="{% url 'company_create' %}" class="btn btn-primary">Create company</a>
<a href="#" id="editBtn" data-url="{% url 'company_update' pk=0 %}" class="btn btn-primary" disabled>Edit Preinfo</a>
<a href="{% url 'employee_company_create' %}" class="btn btn-primary">Create company</a>
<a href="#" id="editBtn" data-url="{% url 'employee_company_update' pk=0 %}" class="btn btn-primary" disabled>Edit Preinfo</a>
<button id="deleteButton" class="btn btn-danger">Delete Preinfo</button>
{% endblock buttons %}

@ -1,9 +1,7 @@
{% extends 'employee-base.html' %}
{% extends 'list-crud.html' %}
{% load static %}
{% block content %}
<table>
<tr>
{% block table_header %}
<th>Container №</th>
<th>Container type</th>
<th>Line</th>
@ -12,25 +10,26 @@
<th>Swept</th>
<th>Washed</th>
<th>Booking</th>
</tr>
{% endblock table_header %}
{% for container in containers %}
<tr>
<td>{{ container.number }}</td>
<td>{{ container.container_type }}</td>
<td>{{ container.line.short_name }}</td>
<td>{{ container.received_on }}</td>
<td>{{ container.position }}</td>
<td>{{ container.swept }}</td>
<td>{{ container.washed }}</td>
<td>{{ container.booking.id }}</td>
<td>
{# <a href="{% url 'employee:preinfo_edit' preinfo.id %}">Edit</a> |#}
{# <a href="{% url 'employee:preinfo_delete' preinfo.id %}">Delete</a>#}
</td>
</tr>
{% block table_data %}
<td>{{ object.number }}</td>
<td>{{ object.container_type }}</td>
<td>{{ object.line.short_name }}</td>
<td>{{ object.received_on }}</td>
<td>{{ object.position }}</td>
<td>{{ object.swept }}</td>
<td>{{ object.washed }}</td>
<td>{{ object.booking.number }}</td>
{% endblock %}
{% endfor %}
{% block buttons %}
{% endblock buttons %}
</table>
{% endblock content %}
{% block create_modal_header %}
<h2>Create Container</h2>
{% endblock %}
{% block modal_header %}
<h2>Edit Container</h2>
{% endblock modal_header %}

@ -1,4 +1,4 @@
{% extends 'client-base.html' %}
{% extends 'employee-base.html' %}
{% load static %}
{% block content %}

@ -3,20 +3,22 @@
{% block table_header %}
<th style="display: none;">Select</th>
<th>Company</th>
<th>Line name</th>
<th>Short name</th>
<th>Description</th>
{% endblock table_header %}
{% block table_data %}
<td>{{ object.company }}</td>
<td>{{ object.name }}</td>
<td>{{ object.short_name }}</td>
<td>{{ object.description }}</td>
{% endblock %}
{% block buttons %}
<a href="{% url 'client_line_create' %}" class="btn btn-primary">Create line</a>
<a href="#" id="editBtn" data-url="{% url 'client_line_update' pk=0 %}" class="btn btn-primary" disabled>Edit Preinfo</a>
<a href="{% url 'employee_line_create' %}" class="btn btn-primary">Create line</a>
<a href="#" id="editBtn" data-url="{% url 'employee_line_update' pk=0 %}" class="btn btn-primary" disabled>Edit Preinfo</a>
<button id="deleteButton" class="btn btn-danger">Delete Preinfo</button>
{% endblock buttons %}

@ -1,4 +1,4 @@
{% extends 'client-base.html' %}
{% extends 'employee-base.html' %}
{% load static %}
{% block content %}

@ -1,10 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
{% extends "employee-base.html" %}
{% block content %}
{% csrf_token %}
{{ form.as_p }}
<div class="selected-containers">
<h3>Selected Containers</h3>
<table class="table">
<thead>
<tr>
<th>Container Number</th>
<th>Type</th>
<th>Company</th>
<th>Received Date</th>
<th>Expedited Date</th>
</tr>
</thead>
<tbody>
{% for container in containers %}
<tr>
<td>{{ container.number }}</td>
<td>{{ container.container_type }}</td>
<td>{{ container.line.company.short_name }}</td>
<td>{{ container.received_on|date:"Y-m-d" }}</td>
<td>{{ container.expedited_on|date:"Y-m-d" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

@ -1,10 +1,78 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$</title>
</head>
<body>
$END$
</body>
</html>
{% extends 'list-crud.html' %}
{% load static %}
{% block filter %}
<div class="filter-form">
<form method="GET">
<span style="display: flex; align-items: center; width: 100%;">
<label for="date" style="margin-right: 8px;">Date:</label>
<input type="date" id="date" name="date" value="{{ request.GET.date }}" style="margin-right: 20px;">
<label for="company" style="margin-right: 8px;">Company:</label>
<select id="company" name="company" style="margin-right: 20px;">
<option value="">Select company</option>
{% for company in companies %}
<option value="{{ company.id }}" {% if request.GET.company|add:'0' == company.id %}selected{% endif %}>
{{ company.name }}
</option>
{% endfor %}
</select>
<button type="submit">Search</button>
</span>
</form>
</div>
{% endblock %}
{% block selection %}
"multiple"
{% endblock selection %}
{% block table_header %}
<th>Container Number</th>
<th>Type</th>
<th>Company</th>
<th>Expedited Date</th>
{% endblock table_header %}
{% block table_data %}
<td class="td-left">{{ object.number }}</td>
<td>{{ object.container_type }}</td>
<td class="td-left">{{ object.line.company.short_name }}</td>
<td>{{ object.expedited_on|date:"Y-m-d h:m:s" }}</td>
{% endblock table_data %}
{% block buttons %}
<button id="createPaymentBtn" class="btn btn-primary" data-requires-selection disabled>Create Payment</button>
{% endblock buttons %}
{% block create_modal_header %}
<h2>Create Container</h2>
{% endblock %}
{% block modal_header %}
<h2>Edit Container</h2>
{% endblock modal_header %}
{% block custom_js %}
<script>
document.getElementById('createPaymentBtn').addEventListener('click', function() {
const selectedIds = Array.from(document.querySelectorAll('.selected-row'))
.map(row => row.dataset.id);
const dateInput = document.getElementById('date').value;
const companySelect = document.getElementById('company').value;
if (selectedIds.length > 0) {
const params = new URLSearchParams({
containers: selectedIds.join(','),
date: dateInput,
company: companySelect
});
window.location.href = '{% url "payments_create" %}?' + params.toString();
}
});
</script>
{% endblock custom_js %}

@ -1,25 +1,16 @@
{% extends base_template %}
{% load static %}
{% block content %}
{# <div class="pagination">#}
{# <span class="step-links">#}
{# {% if page_obj.has_previous %}#}
{# <a href="?page=1">&laquo; first</a>#}
{# <a href="?page={{ page_obj.previous_page_number }}">previous</a>#}
{# {% endif %}#}
{##}
{# <span class="current">#}
{# Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.#}
{# </span>#}
{##}
{# {% if page_obj.has_next %}#}
{# <a href="?page={{ page_obj.next_page_number }}">next</a>#}
{# <a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>#}
{# {% endif %}#}
{# </span>#}
{# </div>#}
<table id="objectTable" class="table">
{% block filter %}
{% endblock filter %}
<table id="objectTable" class="table" data-selection-mode=
{% block selection %}
"single"
{% endblock selection%}>
<thead>
<tr>
{% block table_header %}
@ -29,7 +20,7 @@
<tbody>
{% for object in objects %}
<tr class="selectable-row" data-id="{{ object.id }}">
<td style="display: none;"><input type="radio" name="object_select" value="{{ object.id }}"></td>
<td style="display: none;"><input type="checkbox" name="object_select" value="{{ object.id }}"></td>
{% block table_data %}
{% endblock table_data %}
</tr>
@ -42,22 +33,18 @@
<div class="footer-left">
{% block buttons %}
{% endblock buttons %}
{# <button>Добави</button>#}
{# <button>Изтрий</button>#}
{# <button>Редактирай</button>#}
<button id="toggleSelectAllBtn" class="btn btn-secondary" style="display: none;">Select All</button>
</div>
<div class="footer-right">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
{# <button>&laquo; Назад</button>#}
<span class="page-number">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
{# <button>Напред &raquo;</button>#}
</div>
</div>
</td>
@ -65,7 +52,6 @@
</tfoot>
</table>
<script>
const table = document.getElementById('objectTable');
const headerCells = table.querySelector('thead tr').children.length;
@ -74,11 +60,6 @@
{#footerCell.style.textAlign = 'center';#}
</script>
{# <div class="buttons-container">#}
{# {% block buttons %}#}
{# {% endblock buttons %}#}
{# </div>#}
{% block custom_styles %}
<style>
.selectable-row {
@ -93,8 +74,11 @@
}
</style>
{% endblock custom_styles %}
{% block extra_js %}
<script src="{% static 'js/crud-list.js' %}"></script>
{% endblock extra_js %}
{% block custom_js %}{% endblock custom_js %}
{% block custom_js %}
{% endblock custom_js %}
{% endblock content %}

@ -1,10 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>$Title$</title>
</head>
<body>
$END$
</body>
</html>
{% extends 'list-crud.html' %}
{% load static %}
{% block table_header %}
<th>Username</th>
<th>User Type</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Phone</th>
<th>Company</th>
<th>Line</th>
{% endblock table_header %}
{% block table_data %}
<td class="td-left">{{ object.username }}</td>
<td class="td-left">{{ object.get_user_type_display }}</td>
<td class="td-left">{{ object.first_name }}</td>
<td class="td-left">{{ object.last_name }}</td>
<td class="td-left">{{ object.email }}</td>
<td class="td-left">{{ object.phone }}</td>
<td class="td-left">{{ object.company }}</td>
<td class="td-left">{{ object.line }}</td>
{% endblock %}
{% block buttons %}
<a href="{% url 'user_register' %}" class="btn btn-primary" type="button">Create user</a>
<a href="#" id="editBtn" data-url="{% url 'user_update' pk=0 %}" class="btn btn-primary" type="button" disabled>Edit user</a>
<button id="deleteButton" class="btn btn-danger">Delete user</button>
{% endblock buttons %}
{% block create_modal_header %}
<h2>Create User</h2>
{% endblock %}
{% block modal_header %}
<h2>Edit Container</h2>
{% endblock modal_header %}
Loading…
Cancel
Save