mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-12 17:49:41 +00:00
Compare commits
5 Commits
combine-pr
...
458a734331
| Author | SHA1 | Date | |
|---|---|---|---|
| 458a734331 | |||
| b1646d556c | |||
| f8624d3b7a | |||
| f6836fdab6 | |||
| b3949f2903 |
@@ -61,6 +61,7 @@ INSTALLED_APPS = (
|
|||||||
'users',
|
'users',
|
||||||
'RIGS',
|
'RIGS',
|
||||||
'assets',
|
'assets',
|
||||||
|
'training',
|
||||||
|
|
||||||
'debug_toolbar',
|
'debug_toolbar',
|
||||||
'registration',
|
'registration',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ urlpatterns = [
|
|||||||
path('', include('versioning.urls')),
|
path('', include('versioning.urls')),
|
||||||
path('', include('RIGS.urls')),
|
path('', include('RIGS.urls')),
|
||||||
path('assets/', include('assets.urls')),
|
path('assets/', include('assets.urls')),
|
||||||
|
path('training/', include('training.urls')),
|
||||||
|
|
||||||
path('', login_required(views.Index.as_view()), name='index'),
|
path('', login_required(views.Index.as_view()), name='index'),
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from reversion.admin import VersionAdmin
|
|||||||
from RIGS import models
|
from RIGS import models
|
||||||
from users import forms as user_forms
|
from users import forms as user_forms
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
admin.site.register(models.VatRate, VersionAdmin)
|
admin.site.register(models.VatRate, VersionAdmin)
|
||||||
admin.site.register(models.Event, VersionAdmin)
|
admin.site.register(models.Event, VersionAdmin)
|
||||||
admin.site.register(models.EventItem, VersionAdmin)
|
admin.site.register(models.EventItem, VersionAdmin)
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ class Command(BaseCommand):
|
|||||||
call_command('generateSampleUserData')
|
call_command('generateSampleUserData')
|
||||||
call_command('generateSampleRIGSData')
|
call_command('generateSampleRIGSData')
|
||||||
call_command('generateSampleAssetsData')
|
call_command('generateSampleAssetsData')
|
||||||
|
call_command('generateSampleTrainingData')
|
||||||
|
|||||||
BIN
RIGS/static/imgs/assets.jpg
Normal file
BIN
RIGS/static/imgs/assets.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
RIGS/static/imgs/rigs.jpg
Normal file
BIN
RIGS/static/imgs/rigs.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 278 KiB |
BIN
RIGS/static/imgs/tappytaptap.gif
Normal file
BIN
RIGS/static/imgs/tappytaptap.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 MiB |
BIN
RIGS/static/imgs/training.jpg
Normal file
BIN
RIGS/static/imgs/training.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 852 KiB |
@@ -1,5 +1,6 @@
|
|||||||
{% extends 'base_rigs.html' %}
|
{% extends 'base_rigs.html' %}
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block title %}RIGS{% endblock %}
|
{% block title %}RIGS{% endblock %}
|
||||||
|
|
||||||
@@ -7,8 +8,9 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small> G<small class="text-muted">athering</small> S<small class="text-muted">ystem</small></h1>
|
<h1 class="col-sm-12 pb-3">R<small class="text-muted">ig</small> I<small class="text-muted">nformation</small> G<small class="text-muted">athering</small> S<small class="text-muted">ystem</small></h1>
|
||||||
<h2 class="col-sm-12 pb-3">Welcome back {{ user.get_full_name }}, there {%if rig_count == 1 %}is one rig coming up{%else%}are {{ rig_count|apnumber }} rigs coming up.{%endif%}</h2>
|
<h2 class="col-sm-12 pb-3">Welcome back {{ user.get_full_name }}, there {%if rig_count == 1 %}is one rig coming up{%else%}are {{ rig_count|apnumber }} rigs coming up.{%endif%}</h2>
|
||||||
<div class="col-sm mb-3">
|
<div class="col-sm-4 mb-3">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
<img class="card-img-top" src="{% static 'imgs/rigs.jpg' %}" alt="" style="height: 150px; object-fit: cover;">
|
||||||
<h4 class="card-header">Rigboard</h4>
|
<h4 class="card-header">Rigboard</h4>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<a class="list-group-item list-group-item-action" href="{% url 'rigboard' %}"><span class="fas fa-list align-middle"></span><span class="align-middle"> Rigboard</span></a>
|
<a class="list-group-item list-group-item-action" href="{% url 'rigboard' %}"><span class="fas fa-list align-middle"></span><span class="align-middle"> Rigboard</span></a>
|
||||||
@@ -17,6 +19,12 @@
|
|||||||
<a class="list-group-item list-group-item-action" href="{% url 'event_create' %}"><span class="fas fa-plus align-middle"></span><span class="align-middle"> New Event</span></a>
|
<a class="list-group-item list-group-item-action" href="{% url 'event_create' %}"><span class="fas fa-plus align-middle"></span><span class="align-middle"> New Event</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 mb-3">
|
||||||
|
<div class="card">
|
||||||
|
{% now "m-d" as todays_date %}
|
||||||
|
<img class="card-img-top" src="{% if todays_date == '04-01' %}{% static 'imgs/tappytaptap.gif' %}{%else%}{% static 'imgs/assets.jpg' %}{%endif%}" alt="" style="height: 150px; object-fit: cover;">
|
||||||
<h4 class="card-header">Asset Database</h4>
|
<h4 class="card-header">Asset Database</h4>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<a class="list-group-item list-group-item-action" href="{% url 'asset_index' %}"><span class="fas fa-tag align-middle"></span><span class="align-middle"> Asset List</span></a>
|
<a class="list-group-item list-group-item-action" href="{% url 'asset_index' %}"><span class="fas fa-tag align-middle"></span><span class="align-middle"> Asset List</span></a>
|
||||||
@@ -28,6 +36,21 @@
|
|||||||
<a class="list-group-item list-group-item-action" href="{% url 'supplier_create' %}"><span class="fas fa-plus align-middle"></span><span class="align-middle"> New Supplier</span></a>
|
<a class="list-group-item list-group-item-action" href="{% url 'supplier_create' %}"><span class="fas fa-plus align-middle"></span><span class="align-middle"> New Supplier</span></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 mb-3">
|
||||||
|
<div class="card">
|
||||||
|
<img class="card-img-top" src="{% static 'imgs/training.jpg' %}" alt="" style="height: 150px; object-fit: cover;">
|
||||||
|
<h4 class="card-header">Training Database</h4>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
<a class="list-group-item list-group-item-action" href="{% url 'trainee_detail' %}"><span class="fas fa-file-signature align-middle"></span><span class="align-middle"> My Training Record</span></a>
|
||||||
|
<a class="list-group-item list-group-item-action" href="{% url 'item_list' %}"><span class="fas fa-eye align-middle"></span><span class="align-middle"> View Training Items</span></a>
|
||||||
|
<a class="list-group-item list-group-item-action" href=""><span class="fas fa-plus align-middle"></span><span class="align-middle"> Log Training Session</span></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm mb-3">
|
||||||
|
<div class="card">
|
||||||
<h4 class="card-header">Quick Links</h4>
|
<h4 class="card-header">Quick Links</h4>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<a class="list-group-item list-group-item-action" href="https://forum.nottinghamtec.co.uk" target="_blank" rel="noopener noreferrer"><span class="fas fa-comment-alt text-info align-middle"></span><span class="align-middle"> TEC Forum</span></a>
|
<a class="list-group-item list-group-item-action" href="https://forum.nottinghamtec.co.uk" target="_blank" rel="noopener noreferrer"><span class="fas fa-comment-alt text-info align-middle"></span><span class="align-middle"> TEC Forum</span></a>
|
||||||
|
|||||||
0
training/__init__.py
Normal file
0
training/__init__.py
Normal file
8
training/admin.py
Normal file
8
training/admin.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from training import models
|
||||||
|
from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
|
admin.site.register(models.Trainee, VersionAdmin)
|
||||||
|
admin.site.register(models.TrainingLevel, VersionAdmin)
|
||||||
|
admin.site.register(models.TrainingCategory, VersionAdmin)
|
||||||
|
admin.site.register(models.TrainingItem, VersionAdmin)
|
||||||
5
training/apps.py
Normal file
5
training/apps.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingConfig(AppConfig):
|
||||||
|
name = 'training'
|
||||||
0
training/management/commands/__init__.py
Normal file
0
training/management/commands/__init__.py
Normal file
45
training/management/commands/generateSampleTrainingData.py
Normal file
45
training/management/commands/generateSampleTrainingData.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import datetime
|
||||||
|
import random
|
||||||
|
|
||||||
|
from django.contrib.auth.models import Group, Permission
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.db import transaction
|
||||||
|
from django.utils import timezone
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
from training import models
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Adds sample data to use for testing'
|
||||||
|
can_import_settings = True
|
||||||
|
|
||||||
|
categories = []
|
||||||
|
items = []
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
if not (settings.DEBUG or settings.STAGING):
|
||||||
|
raise CommandError('You cannot run this command in production')
|
||||||
|
|
||||||
|
random.seed('otherwise it is done by time, which could lead to inconsistant tests')
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
self.setup_categories()
|
||||||
|
self.setup_items()
|
||||||
|
|
||||||
|
def setup_categories(self):
|
||||||
|
names = [(1, "Basic"), (2, "Sound"), (3, "Lighting"), (4, "Rigging"), (5, "Power"), (6, "Haulage")]
|
||||||
|
|
||||||
|
for i, name in names:
|
||||||
|
category = models.TrainingCategory.objects.create(reference_number=i, name=name)
|
||||||
|
category.save()
|
||||||
|
self.categories.append(category)
|
||||||
|
|
||||||
|
def setup_items(self):
|
||||||
|
names = ["Motorised Power Towers", "Catering", "Forgetting Cables", "Gazebo Construction", "Balanced Audio", "Unbalanced Audio", "BBQ/Bin Interactions", "Pushing Boxes", "How Not To Die", "Setting up projectors", "Basketing truss", "First Aid", "Digging Trenches", "Avoiding Bin Lorries", "Getting cherry pickers stuck in mud", "Crashing the Van"]
|
||||||
|
|
||||||
|
for i,name in enumerate(names):
|
||||||
|
item = models.TrainingItem.objects.create(category=random.choice(self.categories), reference_number=random.randint(0, 100), name=name)
|
||||||
|
self.items.append(item)
|
||||||
106
training/migrations/0001_initial.py
Normal file
106
training/migrations/0001_initial.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Generated by Django 3.1.5 on 2021-06-29 16:10
|
||||||
|
|
||||||
|
import RIGS.models
|
||||||
|
import django.contrib.auth.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('RIGS', '0041_auto_20210302_1204'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Department',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Trainee',
|
||||||
|
fields=[
|
||||||
|
('profile_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='RIGS.profile')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'user',
|
||||||
|
'verbose_name_plural': 'users',
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=('RIGS.profile',),
|
||||||
|
managers=[
|
||||||
|
('objects', django.contrib.auth.models.UserManager()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingCategory',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('number', models.CharField(max_length=3)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingItem',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('number', models.CharField(max_length=3)),
|
||||||
|
('name', models.CharField(max_length=50)),
|
||||||
|
('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='training.trainingcategory')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingItemInstance',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('training_started_on', models.DateField()),
|
||||||
|
('training_complete_on', models.DateField()),
|
||||||
|
('passed_out_on', models.DateField()),
|
||||||
|
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='training.trainingitem')),
|
||||||
|
('passed_out_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='passed_out', to='training.trainee')),
|
||||||
|
('trainee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='training.trainee')),
|
||||||
|
('training_complete_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='training_complete', to='training.trainee')),
|
||||||
|
('training_started_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='training_started', to='training.trainee')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Technician',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='training.department')),
|
||||||
|
('requirements', models.ManyToManyField(to='training.TrainingItem')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=(models.Model, RIGS.models.RevisionMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TechnicalAssistant',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('requirements', models.ManyToManyField(to='training.TrainingItem')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=(models.Model, RIGS.models.RevisionMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Supervisor',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='training.department')),
|
||||||
|
('requirements', models.ManyToManyField(to='training.TrainingItem')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
bases=(models.Model, RIGS.models.RevisionMixin),
|
||||||
|
),
|
||||||
|
]
|
||||||
118
training/migrations/0002_auto_20210630_1514.py
Normal file
118
training/migrations/0002_auto_20210630_1514.py
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
# Generated by Django 3.1.5 on 2021-06-30 14:14
|
||||||
|
|
||||||
|
import RIGS.models
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('training', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingItemQualification',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('depth', models.IntegerField(choices=[(0, 'Training Started'), (1, 'Training Complete'), (2, 'Passed Out')])),
|
||||||
|
('date', models.DateTimeField()),
|
||||||
|
('notes', models.TextField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingLevel',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('department', models.CharField(max_length=50, null=True)),
|
||||||
|
('level', models.IntegerField(choices=[(0, 'Technical Assistant'), (1, 'Technician'), (2, 'Supervisor')])),
|
||||||
|
],
|
||||||
|
bases=(models.Model, RIGS.models.RevisionMixin),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TrainingLevelQualification',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('confirmed_on', models.DateTimeField()),
|
||||||
|
('confirmed_by', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='confirmer', to='training.trainee')),
|
||||||
|
('level', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='training.traininglevel')),
|
||||||
|
('trainee', models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='levels', to='training.trainee')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='supervisor',
|
||||||
|
name='department',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='supervisor',
|
||||||
|
name='requirements',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='technicalassistant',
|
||||||
|
name='requirements',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='technician',
|
||||||
|
name='department',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='technician',
|
||||||
|
name='requirements',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='trainingiteminstance',
|
||||||
|
name='item',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='trainingiteminstance',
|
||||||
|
name='passed_out_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='trainingiteminstance',
|
||||||
|
name='trainee',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='trainingiteminstance',
|
||||||
|
name='training_complete_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='trainingiteminstance',
|
||||||
|
name='training_started_by',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='trainingitem',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='training.trainingcategory'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Department',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Supervisor',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='TechnicalAssistant',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='Technician',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='TrainingItemInstance',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='trainingitemqualification',
|
||||||
|
name='item',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, to='training.trainingitem'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='trainingitemqualification',
|
||||||
|
name='supervisor',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='training_started', to='training.trainee'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='trainingitemqualification',
|
||||||
|
name='trainee',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='items', to='training.trainee'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
training/migrations/0003_auto_20210630_1624.py
Normal file
19
training/migrations/0003_auto_20210630_1624.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.1.5 on 2021-06-30 15:24
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('training', '0002_auto_20210630_1514'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='trainingitem',
|
||||||
|
name='category',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.RESTRICT, related_name='items', to='training.trainingcategory'),
|
||||||
|
),
|
||||||
|
]
|
||||||
23
training/migrations/0004_auto_20210630_1641.py
Normal file
23
training/migrations/0004_auto_20210630_1641.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 3.1.5 on 2021-06-30 15:41
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('training', '0003_auto_20210630_1624'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='trainingcategory',
|
||||||
|
old_name='number',
|
||||||
|
new_name='reference_number',
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='trainingitem',
|
||||||
|
old_name='number',
|
||||||
|
new_name='reference_number',
|
||||||
|
),
|
||||||
|
]
|
||||||
0
training/migrations/__init__.py
Normal file
0
training/migrations/__init__.py
Normal file
64
training/models.py
Normal file
64
training/models.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from RIGS.models import RevisionMixin, Profile
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
# 'shim' overtop the profile model to neatly contain all training related fields etc
|
||||||
|
class Trainee(Profile):
|
||||||
|
class Meta:
|
||||||
|
proxy = True
|
||||||
|
|
||||||
|
def get_records_of_depth(self, depth):
|
||||||
|
return self.training_items.filter(depth=depth)
|
||||||
|
|
||||||
|
# Items
|
||||||
|
class TrainingCategory(models.Model):
|
||||||
|
reference_number = models.CharField(max_length=3)
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingItem(models.Model):
|
||||||
|
reference_number = models.CharField(max_length=3)
|
||||||
|
category = models.ForeignKey('TrainingCategory', related_name='items', on_delete=models.RESTRICT)
|
||||||
|
name = models.CharField(max_length=50)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "{}.{} {}".format(self.category.reference_number, self.reference_number, self.name)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO Validation that dates cannot be in the future
|
||||||
|
class TrainingItemQualification(models.Model):
|
||||||
|
STARTED = 0
|
||||||
|
COMPLETE = 1
|
||||||
|
PASSED_OUT = 2
|
||||||
|
CHOICES = (
|
||||||
|
(STARTED, 'Training Started'),
|
||||||
|
(COMPLETE, 'Training Complete'),
|
||||||
|
(PASSED_OUT, 'Passed Out'),
|
||||||
|
)
|
||||||
|
item = models.ForeignKey('TrainingItem', on_delete=models.RESTRICT)
|
||||||
|
trainee = models.ForeignKey('Trainee', related_name='training_items', on_delete=models.RESTRICT)
|
||||||
|
depth = models.IntegerField(choices=CHOICES)
|
||||||
|
date = models.DateTimeField()
|
||||||
|
# TODO Remember that some training is external. Support for making an organisation the trainer?
|
||||||
|
supervisor = models.ForeignKey('Trainee', related_name='training_started', on_delete=models.RESTRICT)
|
||||||
|
notes = models.TextField()
|
||||||
|
|
||||||
|
|
||||||
|
# Levels
|
||||||
|
# FIXME Common Competencies...
|
||||||
|
class TrainingLevel(models.Model, RevisionMixin):
|
||||||
|
CHOICES = (
|
||||||
|
(0, 'Technical Assistant'),
|
||||||
|
(1, 'Technician'),
|
||||||
|
(2, 'Supervisor'),
|
||||||
|
)
|
||||||
|
department = models.CharField(max_length=50, null=True) # N.B. Technical Assistant does not have a department
|
||||||
|
level = models.IntegerField(choices=CHOICES)
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingLevelQualification(models.Model):
|
||||||
|
trainee = models.ForeignKey('Trainee', related_name='levels', on_delete=models.RESTRICT)
|
||||||
|
level = models.ForeignKey('TrainingLevel', on_delete=models.RESTRICT)
|
||||||
|
confirmed_on = models.DateTimeField()
|
||||||
|
confirmed_by = models.ForeignKey('Trainee', related_name='confirmer', on_delete=models.RESTRICT)
|
||||||
18
training/templates/item_list.html
Normal file
18
training/templates/item_list.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{% extends 'base_rigs.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
{% for category in categories %}
|
||||||
|
<div class="col">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<h4 class="card-header">{{ category.name }}</h4>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
{% for item in category.items.all %}
|
||||||
|
<li class="list-group-item">{{ item }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
12
training/templates/session_log_form.html
Normal file
12
training/templates/session_log_form.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% extends 'base_rigs.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<h1>Log New Training Session</h1>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="selectpicker">Select Attendees</label>
|
||||||
|
<select name="attendees" id="attendees_id" class="form-control selectpicker" data-live-search="true">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
29
training/templates/trainee_detail.html
Normal file
29
training/templates/trainee_detail.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends 'base_rigs.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<h2 class="col-12">Training Levels</h2>
|
||||||
|
<p>{{ user.name }} is a...<br></p>
|
||||||
|
<div class="col">
|
||||||
|
<h2><div class="badge badge-success">Sound Supervisor <span class="fas fa-volume-up"></span></div><h2>
|
||||||
|
<h3><div class="badge badge-danger">Power Technician <span class="fas fa-plug"></span></div></h3>
|
||||||
|
<h4><div class="badge badge-primary">Technical Assistant <span class="fas fa-wrench"></span></div></h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<h2 class="col-12">Training Items</h2><br>
|
||||||
|
{% for category in categories %}
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<h3 class="card-header">{{ category.name }}</h3>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
{% for depth in depths %}
|
||||||
|
<li class="list-group-item {% if depth.0 == 0 %}list-group-item-warning{%elif depth.0 == 1%}list-group-item-success{%else%}list-group-item-info{%endif%}">{{depth.1}}</li>
|
||||||
|
<li class="list-group-item">Dummy Item</li>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
15
training/urls.py
Normal file
15
training/urls.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from PyRIGS.decorators import permission_required_with_403
|
||||||
|
|
||||||
|
from training import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('items/', views.ItemList.as_view(), name='item_list'),
|
||||||
|
|
||||||
|
path('trainee/', login_required(views.TraineeDetail.as_view()), name='trainee_detail'),
|
||||||
|
path('trainee/<int:pk>/',
|
||||||
|
permission_required_with_403('RIGS.view_profile')(views.TraineeDetail.as_view()),
|
||||||
|
name='trainee_detail'),
|
||||||
|
]
|
||||||
32
training/views.py
Normal file
32
training/views.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from django.views import generic
|
||||||
|
from training import models
|
||||||
|
|
||||||
|
from users import views
|
||||||
|
|
||||||
|
class ItemList(generic.ListView):
|
||||||
|
template_name = "item_list.html"
|
||||||
|
model = models.TrainingItem
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(ItemList, self).get_context_data(**kwargs)
|
||||||
|
context["page_title"] = "Training Items"
|
||||||
|
context["categories"] = models.TrainingCategory.objects.all()
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class TraineeDetail(views.ProfileDetail):
|
||||||
|
template_name = "trainee_detail.html"
|
||||||
|
model = models.Trainee
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(TraineeDetail, self).get_context_data(**kwargs)
|
||||||
|
context["page_title"] = "{}'s Training Record".format(self.object)
|
||||||
|
context["categories"] = models.TrainingCategory.objects.all()
|
||||||
|
choices = models.TrainingItemQualification.CHOICES
|
||||||
|
context["depths"] = choices
|
||||||
|
for i in [x for x,_ in choices]:
|
||||||
|
context[str(i)] = self.object.get_records_of_depth(i)
|
||||||
|
return context
|
||||||
|
|
||||||
Reference in New Issue
Block a user