Compare commits

..

2 Commits

Author SHA1 Message Date
bobbinz
7835d38f9d Update ec_power_info.html
Fixed spelling booboo
2024-03-26 18:17:45 +00:00
bobbinz
83f5990050 Update ec_power_info.html
Added three phase column and made tables look the same
2024-03-26 18:13:03 +00:00
31 changed files with 7038 additions and 3846 deletions

View File

@@ -14,14 +14,11 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PYTHONDONTWRITEBYTECODE: 1 PYTHONDONTWRITEBYTECODE: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install build dependencies
run: |
sudo apt-get install libcairo2-dev
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version: "3.10" python-version: 3.9
cache: 'pipenv' cache: 'pipenv'
- name: Install Dependencies - name: Install Dependencies
run: | run: |
@@ -30,7 +27,7 @@ jobs:
# if: steps.pcache.outputs.cache-hit != 'true' # if: steps.pcache.outputs.cache-hit != 'true'
- name: Cache Static Files - name: Cache Static Files
id: static-cache id: static-cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: 'pipeline/built_assets' path: 'pipeline/built_assets'
key: ${{ hashFiles('package-lock.json') }}-${{ hashFiles('pipeline/source_assets') }} key: ${{ hashFiles('package-lock.json') }}-${{ hashFiles('pipeline/source_assets') }}
@@ -46,7 +43,7 @@ jobs:
pipenv run python3 manage.py collectstatic --noinput pipenv run python3 manage.py collectstatic --noinput
- name: Run Tests - name: Run Tests
run: pipenv run pytest -n auto --cov run: pipenv run pytest -n auto --cov
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
if: failure() if: failure()
with: with:
name: failure-screenshots ${{ matrix.test-group }} name: failure-screenshots ${{ matrix.test-group }}

10
Pipfile
View File

@@ -28,9 +28,9 @@ django-reversion = "~=3.0.9"
django-widget-tweaks = "~=1.4.8" django-widget-tweaks = "~=1.4.8"
django-htmlmin = "~=0.11.0" django-htmlmin = "~=0.11.0"
envparse = "*" envparse = "*"
gunicorn = "~=22.0.0" gunicorn = "~=20.0.4"
icalendar = "~=4.0.7" icalendar = "~=4.0.7"
idna = "~=3.7" idna = "~=2.10"
Markdown = "~=3.3.3" Markdown = "~=3.3.3"
msgpack = "~=1.0.2" msgpack = "~=1.0.2"
pep517 = "~=0.9.1" pep517 = "~=0.9.1"
@@ -47,17 +47,17 @@ python-dateutil = "~=2.8.1"
pytoml = "~=0.1.21" pytoml = "~=0.1.21"
pytz = "~=2020.5" pytz = "~=2020.5"
reportlab = "*" reportlab = "*"
requests = "~=2.32.3" requests = "~=2.31.0"
retrying = "~=1.3.3" retrying = "~=1.3.3"
simplejson = "~=3.17.2" simplejson = "~=3.17.2"
six = "~=1.15.0" six = "~=1.15.0"
soupsieve = "~=2.1" soupsieve = "~=2.1"
sqlparse = "~=0.5.0" sqlparse = "~=0.4.2"
static3 = "~=0.7.0" static3 = "~=0.7.0"
svg2rlg = "~=0.3" svg2rlg = "~=0.3"
tini = "~=3.0.1" tini = "~=3.0.1"
tornado = "~=6.3" tornado = "~=6.3"
urllib3 = "~=1.26.19" urllib3 = "~=1.26.18"
whitenoise = "~=5.2.0" whitenoise = "~=5.2.0"
yolk = "~=0.4.3" yolk = "~=0.4.3"
zipp = "~=3.4.0" zipp = "~=3.4.0"

1468
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -224,8 +224,6 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
USE_THOUSAND_SEPARATOR = True
# Need to allow seconds as datetime-local input type spits out a time that has seconds # Need to allow seconds as datetime-local input type spits out a time that has seconds
DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S') DATETIME_INPUT_FORMATS = ('%Y-%m-%dT%H:%M', '%Y-%m-%dT%H:%M:%S')

View File

@@ -1,11 +1,10 @@
from datetime import datetime, timedelta from datetime import datetime
import simplejson import simplejson
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.core import serializers from django.core import serializers
from django.utils import timezone from django.utils import timezone
from django.utils.html import format_html
from reversion import revisions as reversion from reversion import revisions as reversion
from RIGS import models from RIGS import models
@@ -98,9 +97,6 @@ class EventForm(forms.ModelForm):
raise forms.ValidationError( raise forms.ValidationError(
'You haven\'t provided any client contact details. Please add a person or organisation.', 'You haven\'t provided any client contact details. Please add a person or organisation.',
code='contact') code='contact')
access = self.cleaned_data.get("access_at")
if 'warn-access' not in self.data and access is not None and access.date() < (self.cleaned_data.get("start_date") - timedelta(days=7)):
raise forms.ValidationError(format_html("Are you sure about that? Your access time seems a bit optimistic. If you're sure, save again. <input type='hidden' id='warn-access' name='warn-access' value='0'/>"), code='access_sanity')
return super().clean() return super().clean()
def save(self, commit=True): def save(self, commit=True):

View File

@@ -254,7 +254,7 @@ class Command(BaseCommand):
new_invoice.void = True new_invoice.void = True
elif random.randint(0, 2) > 1: # 1 in 3 have been paid elif random.randint(0, 2) > 1: # 1 in 3 have been paid
models.Payment.objects.create(invoice=new_invoice, amount=new_invoice.balance, models.Payment.objects.create(invoice=new_invoice, amount=new_invoice.balance,
date=datetime.date.today(), method=random.choice(models.Payment.METHODS)[0]) date=datetime.date.today())
if i == 1 or random.randint(0, 5) > 0: # Event 1 and 1 in 5 have a RA if i == 1 or random.randint(0, 5) > 0: # Event 1 and 1 in 5 have a RA
models.RiskAssessment.objects.create(event=new_event, supervisor_consulted=bool(random.getrandbits(1)), models.RiskAssessment.objects.create(event=new_event, supervisor_consulted=bool(random.getrandbits(1)),
nonstandard_equipment=bool(random.getrandbits(1)), nonstandard_equipment=bool(random.getrandbits(1)),

View File

@@ -943,10 +943,6 @@ class PowerTestRecord(ReviewableModel, RevisionMixin):
def activity_feed_string(self): def activity_feed_string(self):
return str(self.event) return str(self.event)
@property
def name(self):
return f"Power Test Record - {self.event}"
class EventCheckIn(models.Model): class EventCheckIn(models.Model):
event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE) event = models.ForeignKey('Event', related_name='crew', on_delete=models.CASCADE)

View File

@@ -22,9 +22,6 @@
<paraStyle name="center" alignment="center"/> <paraStyle name="center" alignment="center"/>
<paraStyle name="page-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18" spaceAfter="0"/> <paraStyle name="page-head" alignment="center" fontName="OpenSans-Bold" fontSize="16" leading="18" spaceAfter="0"/>
{% block extrastyles %}
{% endblock %}
<paraStyle name="style.event_description" fontName="OpenSans" textColor="DarkGray" /> <paraStyle name="style.event_description" fontName="OpenSans" textColor="DarkGray" />
<paraStyle name="style.item_description" fontName="OpenSans" textColor="DarkGray" leftIndent="10" /> <paraStyle name="style.item_description" fontName="OpenSans" textColor="DarkGray" leftIndent="10" />
<paraStyle name="style.specific_description" fontName="OpenSans" textColor="DarkGray" fontSize="10" /> <paraStyle name="style.specific_description" fontName="OpenSans" textColor="DarkGray" fontSize="10" />
@@ -140,7 +137,6 @@
<nextFrame/> <nextFrame/>
{% block content %} {% block content %}
{% endblock %} {% endblock %}
<namedString id="lastPage"><pageNumber/></namedString>
</story> </story>
</document> </document>

View File

@@ -45,7 +45,6 @@
Invoices <span class="badge {% if todo == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ todo }}</span> Invoices <span class="badge {% if todo == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ todo }}</span>
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownInvoices"> <div class="dropdown-menu" aria-labelledby="navbarDropdownInvoices">
<a class="dropdown-item" href="{% url 'invoice_dashboard' %}"><span class="fas fa-chart-line"></span> Dashboard</a>
{% if perms.RIGS.add_invoice %} {% if perms.RIGS.add_invoice %}
<a class="dropdown-item text-nowrap" href="{% url 'invoice_waiting' %}"><span class="fas fa-briefcase text-danger"></span> Waiting <span class="badge {% if waiting == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ waiting }}</span></a> <a class="dropdown-item text-nowrap" href="{% url 'invoice_waiting' %}"><span class="fas fa-briefcase text-danger"></span> Waiting <span class="badge {% if waiting == 0 %}badge-success{% else %}badge-danger{% endif %} badge-pill">{{ waiting }}</span></a>
{% endif %} {% endif %}

View File

@@ -46,7 +46,7 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-sm-12" style="container-type: inline-size;"> <div class="col-sm-12">
{% with object_list as events %} {% with object_list as events %}
{% include 'partials/event_table.html' %} {% include 'partials/event_table.html' %}
{% endwith %} {% endwith %}

View File

@@ -165,7 +165,6 @@
</div> </div>
</div> </div>
<div class="col-12 text-right"> <div class="col-12 text-right">
{% button 'print' 'pt_print' object.pk %}
{% button 'edit' url='pt_edit' pk=object.pk %} {% button 'edit' url='pt_edit' pk=object.pk %}
{% button 'view' url='event_detail' pk=object.event.pk text="Event" %} {% button 'view' url='event_detail' pk=object.event.pk text="Event" %}
{% include 'partials/review_status.html' with perm=perms.RIGS.review_power review='pt_review' %} {% include 'partials/review_status.html' with perm=perms.RIGS.review_power review='pt_review' %}

View File

@@ -1,170 +0,0 @@
{% extends 'base_print.xml' %}
{% load filters %}
{% block extrastyles %}
<paraStyle name="style.powerReviewed" alignment="center" backColor="green" textColor="white"/>
<paraStyle name="style.powerUnreviewed" alignment="center" backColor="red" textColor="white"/>
<blockTableStyle id="powerTable">
<blockValign value="middle"/>
<lineStyle kind="LINEABOVE" colorName="black" thickness="1"/>
<lineStyle kind="LINEBELOW" colorName="black" thickness="1"/>
<lineStyle kind="LINEAFTER" colorName="black" thickness="1"/>
<lineStyle kind="LINEBEFORE" colorName="black" thickness="1"/>
</blockTableStyle>
{% endblock %}
{% block content %}
<spacer length="15"/>
<h1>Power Test Record for <strong>{{ object.event }}</strong></h1>
<spacer length="15"/>
<h2>Client: {{ object.event.person|default:object.event.organisation }} | Venue: {{ object.event.venue }} | MIC: {{ object.event.mic }}</h2>
<spacer length="15"/>
<hr/>
<spacer length="15"/>
{% if object.reviewed_by %}
<para style="style.powerReviewed"><strong>Reviewed by: {{ object.reviewed_by }} at {{ object.reviewed_at|date:"D d/m/Y" }}</strong></para>
{% else %}
<para style="style.powerUnreviewed"><strong>Power test results not yet reviewed</strong></para>
{% endif %}
<spacer length="15"/>
<hr/>
<spacer length="15"/>
<h2 fontSize="16">Power Plan Information</h2>
<spacer length="15"/>
<blockTable colWidths="250,250">
<tr>
<td><para><strong>Power MIC:</strong> {{ object.power_mic }}</para></td>
<td><para><strong>Venue:</strong> {{ object.event.venue }}</para></td>
</tr>
<tr>
<td><para><strong>Event Date:</strong> {{ object.event.start_date |date:"D d/m/Y" }}</para></td>
<td><para><strong>Generators:</strong> {{ object.event.riskassessment.generators|yesno|capfirst }}</para></td>
</tr>
<tr>
<td><para><strong>Power Test taken at:</strong> {{ object.date_created|date:"D d/m/Y H:i" }}</para></td>
<td><para><strong>Other Companies Power:</strong> {{ object.event.riskassessment.other_companies_power|yesno|capfirst }}</para></td>
</tr>
</blockTable>
<spacer length="15"/>
<hr/>
<spacer length="15"/>
<condPageBreak height="10in"/>
<h2 fontSize="16">Power Test Results</h2>
<spacer length="15"/>
<para><strong>Source RCD protected?</strong> {{ object.source_rcd|yesno|capfirst }}</para>
<para><sub>(If cable is more than 3 metres long)</sub></para>
<spacer length="5"/>
<para><strong>Appropriate and clear labelling on distribution and cabling?</strong> {{ object.labelling|yesno|capfirst }}</para>
<spacer length="5"/>
<para><strong>Equipment appropriately earthed?</strong> {{ object.source_rcd|yesno|capfirst }}</para>
<para><sub>(truss, stage, generators etc.)</sub></para>
<spacer length="5"/>
<para><strong>All equipment in PAT period?</strong> {{ object.pat|yesno|capfirst }}</para>
<spacer length="15"/>
<h2 fontSize="14">Tests at first distro</h2>
<spacer length="5"/>
<blockTable colWidths="100,410">
<tr>
<td><para><strong>Voltage<br/><sub>(cube meter) / V</sub></strong></para></td>
<td>
<blockTable colWidths="100,100,100" style="powerTable">
<tr>
<td><para><strong>L1 - N</strong></para></td>
<td><para><strong>L2 - N</strong></para></td>
<td><para><strong>L3 - N</strong></para></td>
</tr>
<tr>
<td>{{ object.fd_voltage_l1}}</td>
<td>{{ object.fd_voltage_l2}}</td>
<td>{{ object.fd_voltage_l3}}</td>
</tr>
</blockTable>
</td>
</tr>
</blockTable>
<spacer length="15"/>
<blockTable colWidths="100,100,190,120">
<tr>
<td><para><strong>Phase Rotation<br/><sub>(if required)</sub></strong></para></td>
<td><para>{{ object.fd_phase_rotation|yesno|capfirst }}</para></td>
<td><para><strong>Earth Fault Loop Impedance (Z<sub>s</sub>) / Ω</strong></para></td>
<td><para>{{ object.fd_earth_fault }}</para></td>
</tr>
</blockTable>
<spacer length="15"/>
<para><strong>Prospective Short Circuit Current / A</strong> {{ object.fd_pssc }}</para>
<spacer length="15"/>
<h2 fontSize="14">Tests 'Worst Case' points (at least 1 required)</h2>
<spacer length="15"/>
<blockTable colWidths="100,100,190,120" style="powerTable">
<tr>
<td><para><strong>Description</strong></para></td>
<td><para><strong>Polarity checked?</strong></para></td>
<td><para><strong>Voltage / V</strong></para></td>
<td><para><strong>Earth Fault Loop Impedance (Z<sub>s</sub>) / Ω</strong></para></td>
</tr>
{% if object.w1_description %}
<tr>
<td><para><strong>{{ object.w1_description }}</strong></para></td>
<td><para>{{ object.w1_polarity|yesno|capfirst }}</para></td>
<td><para>{{ object.w1_voltage }} V</para></td>
<td><para>{{ object.w1_earth_fault }}</para></td>
</tr>
{% endif %}
{% if object.w2_description %}
<tr>
<td><para><strong>{{ object.w2_description }}</strong></para></td>
<td><para>{{ object.w2_polarity|yesno|capfirst }}</para></td>
<td><para>{{ object.w2_voltage }} V</para></td>
<td><para>{{ object.w2_earth_fault }}</para></td>
</tr>
{% endif %}
{% if object.w3_description %}
<tr>
<td><para><strong>{{ object.w3_description }}</strong></para></td>
<td><para>{{ object.w3_polarity|yesno|capfirst }}</para></td>
<td><para>{{ object.w3_voltage }} V</para></td>
<td><para>{{ object.w3_earth_fault }}</para></td>
</tr>
{% endif %}
</blockTable>
<spacer length="15"/>
<h2 fontSize="14">Generic Tests</h2>
<spacer length="15"/>
<blockTable colWidths="250,270" style="powerTable">
<tr>
<td><para><strong>All circuit RCDs tested?</strong><br/>(using test button)</para></td>
<td><para>{{ object.all_rcds_tested|yesno|capfirst }}</para></td>
</tr>
<tr>
<td><para><strong>Public/performer accessible circuits tested?</strong><br/>(using socket tester)</para></td>
<td><para>{{ object.public_sockets_tested|yesno|capfirst }}</para></td>
</tr>
</blockTable>
{% endblock %}

View File

@@ -1,105 +0,0 @@
{% extends 'base_rigs.html' %}
{% block content %}
<form method="GET" action="{% url 'invoice_dashboard' %}">
<div class="form-row">
<div class="form-group col-md-4">
<label for="time_filter">Time Filter</label>
<select id="time_filter" name="time_filter" class="form-control">
<option value="week" {% if time_filter == 'week' %}selected{% endif %}>Last Week (7 days)</option>
<option value="month" {% if time_filter == 'month' %}selected{% endif %}>Last Month (30 days)</option>
<option value="year" {% if time_filter == 'year' %}selected{% endif %}>Last Year</option>
<option value="all" {% if time_filter == 'all' %}selected{% endif %}>All Time</option>
</select>
</div>
</div>
</form>
<script>
$('#time_filter').change(function () {
$(this).closest('form').submit();
});
</script>
<h3>Overview</h3>
<!-- big cards in 2x2 grid with total_outstanding, total_events, total_invoices and total_payments, different backgrounds -->
<div class="card-deck">
<div class="card">
<a href="{% url 'invoice_waiting' %}" class="text-decoration-none text-white">
<div class="card-body bg-primary">
<h5 class="card-title text-center">Total Waiting</h5>
<p class="card-text text-center h3"><strong>£{{ total_waiting|floatformat:2 }}</strong></p>
</div>
</a>
</div>
<div class="card">
<a href="{% url 'invoice_list' %}" class="text-decoration-none text-dark">
<div class="card-body bg-info">
<h5 class="card-title text-center">Total Outstanding</h5>
<p class="card-text text-center h3"><strong>£{{ total_outstanding|floatformat:2 }}</strong></p>
</div>
</a>
</div>
<div class="card">
<div class="card-body bg-danger">
<h5 class="card-title text-center">Total Events</h5>
<p class="card-text text-center h3"><strong>{{ total_events }}</strong></p>
</div>
</div>
<div class="card">
<div class="card-body bg-success">
<h5 class="card-title text-center">Total Invoices</h5>
<p class="card-text text-center h3"><strong>{{ total_invoices }}</strong></p>
</div>
</div>
</div>
<br />
<h3>Payments</h3>
<br/>
<h4>Sources</h4>
<br/>
{% for source in payment_methods %}
<div class="card">
<div class="card-body">
<h5 class="card-title"><strong>{{ source.method }}</strong></h5>
<p class="card-text h3">£{{ source.total|floatformat:2 }}</p>
</div>
</div>
{% endfor %}
<br/>
<h4>Total</h4>
<br/>
<div class="card">
<div class="card-body">
<h5 class="card-title text-center">Total Income</h5>
<p class="card-text text-center h3"><strong>£{{ total_income|floatformat:2 }}</strong></p>
</div>
</div>
<br/>
<h4>Invoice Payment Time</h4>
<br/>
<div class="card">
<div class="card-body">
<h5 class="card-title text-center">Average Time to Pay</h5>
<p class="card-text text-center h3"><strong>{{ mean_invoice_to_payment|floatformat:2 }} days</strong></p>
</div>
</div>
{% endblock %}

View File

@@ -31,7 +31,7 @@
{% for event in object_list %} {% for event in object_list %}
<tr class="{{event.status_color}}"> <tr class="{{event.status_color}}">
<th scope="row"><a href="{% url 'event_detail' event.pk %}">{{ event.display_id }}</a><br> <th scope="row"><a href="{% url 'event_detail' event.pk %}">{{ event.display_id }}</a><br>
<span class="{% if event.get_status_display == 'Cancelled' %}text-danger{% endif %}">{{ event.get_status_display }}</span></th> <span class="text-muted">{{ event.get_status_display }}</span></th>
<td>{{ event.start_date }}</td> <td>{{ event.start_date }}</td>
<td> <td>
{{ event.name }} {{ event.name }}

View File

@@ -33,8 +33,8 @@
<thead> <thead>
<tr> <tr>
<th scope="row">Distro</th> <th scope="row">Distro</th>
<th scope="row">Max PSCC with Single Phase Supply (kA)</th> <th scope="row">Max PSSC with Single Phase Supply (kA)</th>
<th scope="row">Max PSCC with Three Phase Supply (kA)</th> <th scope="row">Max PSSC with Three Phase Supply (kA)</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@@ -3,7 +3,7 @@
<style> <style>
#event_table { #event_table {
display: grid; display: grid;
grid-template-columns: max-content min-content minmax(max-content, 1fr) max-content; grid-template-columns: max-content auto;
column-gap: 1em; column-gap: 1em;
} }
.eventgrid { .eventgrid {
@@ -11,9 +11,6 @@
grid-column: 1/5; grid-column: 1/5;
grid-template-columns: subgrid; grid-template-columns: subgrid;
padding: 1em; padding: 1em;
dt, dd { display: block; float: left; }
dt { clear: both; }
dd { float: right; }
} }
.grid-header { .grid-header {
border-bottom: 1px solid grey; border-bottom: 1px solid grey;
@@ -26,13 +23,7 @@
grid-row-start: 1; grid-row-start: 1;
grid-column-start: 4; grid-column-start: 4;
} }
.c-none { @media (max-width: 600px) {
display: none;
}
.c-inline {
display: inline;
}
@container (width <= 500px) {
#event_table { #event_table {
grid-template-columns: 1fr !important; grid-template-columns: 1fr !important;
} }
@@ -52,9 +43,9 @@
#event_mic { #event_mic {
grid-row-start: auto; grid-row-start: auto;
grid-column-start: 4; grid-column-start: 4;
}
} }
@container (width <= 700px) { }
@media (max-width: 900px) {
#event_table { #event_table {
grid-template-columns: max-content; grid-template-columns: max-content;
column-gap: 0.5em; column-gap: 0.5em;
@@ -77,20 +68,17 @@
#event_status { #event_status {
grid-column: span 2; grid-column: span 2;
} }
.grid-header, .c-md-none { .grid-header {
display: none; display: none;
} }
} }
@container (width > 700px) { dt {
.c-lg-block { float: left;
display: block; clear: left;
} margin-right: 10px;
.c-lg-inline { }
display: inline; dd {
} margin-left: 0px;
.c-lg-none, .c-md-none {
display: none;
}
} }
</style> </style>
<div id="event_table"> <div id="event_table">
@@ -117,7 +105,7 @@
table-warning table-warning
{% endif %}" {% if event.cancelled %}style="opacity: 50% !important;"{% endif %} id="event_row"> {% endif %}" {% if event.cancelled %}style="opacity: 50% !important;"{% endif %} id="event_row">
<!---Number--> <!---Number-->
<div class="font-weight-bold c-none c-lg-block" id="event_number">{{ event.display_id }}</div> <div class="font-weight-bold d-none d-lg-block" id="event_number">{{ event.display_id }}</div>
<!--Dates & Times--> <!--Dates & Times-->
<div id="event_dates" style="min-width: 180px;"> <div id="event_dates" style="min-width: 180px;">
<dl> <dl>
@@ -151,12 +139,12 @@
<div id="event_details" class="w-100"> <div id="event_details" class="w-100">
<h4> <h4>
<a href="{% url 'event_detail' event.pk %}"> <a href="{% url 'event_detail' event.pk %}">
<span class="c-inline c-lg-none">{{ event }}</span><span class="c-none c-lg-inline">{{ event.name }}</span> <span class="d-inline d-lg-none">{{ event }}</span><span class="d-none d-lg-inline">{{ event.name }}</span>
</a> </a>
{% if event.dry_hire %} {% if event.dry_hire %}
<span class="badge badge-secondary">Dry Hire</span> <span class="badge badge-secondary">Dry Hire</span>
{% endif %} {% endif %}
<br class="c-none c-lg-inline"> <br class="d-none d-lg-inline">
{% if event.venue %} {% if event.venue %}
<small>at {{ event.venue|namewithnotes:'venue_detail' }}</small> <small>at {{ event.venue|namewithnotes:'venue_detail' }}</small>
{% endif %} {% endif %}
@@ -176,7 +164,7 @@
{% include 'partials/event_status.html' %} {% include 'partials/event_status.html' %}
<!---MIC--> <!---MIC-->
<div id="event_mic" class="text-nowrap"> <div id="event_mic" class="text-nowrap">
<span class="c-md-none align-middle">MIC:</span> <span class="d-md-none align-middle">MIC:</span>
{% if event.mic %} {% if event.mic %}
{% if perms.RIGS.view_profile %} {% if perms.RIGS.view_profile %}
<a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href"> <a href="{% url 'profile_detail' event.mic.pk %}" class="modal-href">

View File

@@ -12,7 +12,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div style="container-type: inline-size;">
{% include 'partials/event_table.html' %} {% include 'partials/event_table.html' %}
</div>
{% endblock %} {% endblock %}

View File

@@ -127,7 +127,7 @@ class TestEventCreate(BaseRigboardTest):
# Fix it # Fix it
self.page.end_date = datetime.date(2020, 1, 11) self.page.end_date = datetime.date(2020, 1, 11)
self.page.access_at = datetime.datetime(2020, 1, 8, 9) self.page.access_at = datetime.datetime(2020, 1, 1, 9)
self.page.dry_hire = True self.page.dry_hire = True
self.page.status = "Booked" self.page.status = "Booked"
self.page.collected_by = "Fred" self.page.collected_by = "Fred"

View File

@@ -100,7 +100,6 @@ urlpatterns = [
name='pt_edit'), name='pt_edit'),
path('event/power/<int:pk>/review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()), path('event/power/<int:pk>/review/', permission_required_with_403('RIGS.review_power')(views.MarkReviewed.as_view()),
name='pt_review', kwargs={'model': 'PowerTestRecord'}), name='pt_review', kwargs={'model': 'PowerTestRecord'}),
path('event/power/<int:pk>/print/', permission_required_with_403('RIGS.view_powertestrecord')(views.PowerPrint.as_view()), name='pt_print'),
path('event/<int:pk>/checkin/', login_required(views.EventCheckIn.as_view()), path('event/<int:pk>/checkin/', login_required(views.EventCheckIn.as_view()),
name='event_checkin'), name='event_checkin'),
@@ -115,8 +114,7 @@ urlpatterns = [
path('event/webhook/', views.RecieveForumWebhook.as_view(), name='webhook_recieve'), path('event/webhook/', views.RecieveForumWebhook.as_view(), name='webhook_recieve'),
# Finance # Finance
path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceDashboard.as_view()), name='invoice_dashboard'), path('invoice/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceIndex.as_view()),
path('invoice/outstanding', permission_required_with_403('RIGS.view_invoice')(views.InvoiceOutstanding.as_view()),
name='invoice_list'), name='invoice_list'),
path('invoice/archive/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceArchive.as_view()), path('invoice/archive/', permission_required_with_403('RIGS.view_invoice')(views.InvoiceArchive.as_view()),
name='invoice_archive'), name='invoice_archive'),

View File

@@ -5,7 +5,7 @@ import reversion
from django import forms from django import forms
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction
from django.db.models import Sum from django.db.models import Q
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@@ -18,76 +18,8 @@ from RIGS import models
forms.DateField.widget = forms.DateInput(attrs={'type': 'date'}) forms.DateField.widget = forms.DateInput(attrs={'type': 'date'})
TIME_FILTERS = ["all", "year", "month", "week"]
class InvoiceIndex(generic.ListView):
def days_between(d1, d2):
diff = d2 - d1
return diff.total_seconds() / datetime.timedelta(days=1).total_seconds()
class InvoiceDashboard(generic.TemplateView):
template_name = 'invoice_dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = "Invoice Dashboard"
context['description'] = "Overview of financial status of TEC rigs."
time_filter = self.request.GET.get('time_filter', 'all')
if time_filter not in TIME_FILTERS:
time_filter = 'all'
if time_filter == 'all':
context['events'] = models.Event.objects.all()
context['invoices'] = models.Invoice.objects.all()
context['payments'] = models.Payment.objects.all()
elif time_filter == 'year':
context['events'] = models.Event.objects.filter(start_date__gte=datetime.date.today() - datetime.timedelta(days=365))
context['invoices'] = models.Invoice.objects.filter(invoice_date__gte=datetime.date.today() - datetime.timedelta(days=365))
context['payments'] = models.Payment.objects.filter(date__gte=datetime.date.today() - datetime.timedelta(days=365))
elif time_filter == 'month':
context['events'] = models.Event.objects.filter(start_date__gte=datetime.date.today() - datetime.timedelta(days=30))
context['invoices'] = models.Invoice.objects.filter(invoice_date__gte=datetime.date.today() - datetime.timedelta(days=30))
context['payments'] = models.Payment.objects.filter(date__gte=datetime.date.today() - datetime.timedelta(days=30))
elif time_filter == 'week':
context['events'] = models.Event.objects.filter(start_date__gte=datetime.date.today() - datetime.timedelta(days=7))
context['invoices'] = models.Invoice.objects.filter(invoice_date__gte=datetime.date.today() - datetime.timedelta(days=7))
context['payments'] = models.Payment.objects.filter(date__gte=datetime.date.today() - datetime.timedelta(days=7))
context["time_filter"] = time_filter
context['total_outstanding'] = sum([i.balance for i in models.Invoice.objects.outstanding_invoices()])
context['total_waiting'] = sum([i.sum_total for i in models.Event.objects.waiting_invoices()])
context['total_events'] = len(context['events'])
context['total_invoices'] = len(context['invoices'])
context['total_payments'] = len(context['payments'])
payment_methods = dict(models.Payment.METHODS)
context['payment_methods'] = context["payments"].values('method').annotate(total=Sum('amount')).order_by('method')
for method in context['payment_methods']:
method['method'] = payment_methods.get(method['method'], f"Unknown method ({method['method']})")
context["total_income"] = sum([i['total'] for i in context['payment_methods']])
payments = context['payments']
mean_duration = 0
for payment in payments:
mean_duration += days_between(payment.invoice.invoice_date, payment.date)
if len(payments) > 0:
mean_duration /= len(payments)
context['mean_invoice_to_payment'] = mean_duration
return context
class InvoiceOutstanding(generic.ListView):
model = models.Invoice model = models.Invoice
template_name = 'invoice_list.html' template_name = 'invoice_list.html'

View File

@@ -232,16 +232,6 @@ class RAPrint(PrintView):
return context return context
class PowerPrint(PrintView):
model = models.PowerTestRecord
template_name = 'hs/power_print.xml'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filename'] = f"PowerTestRecord_for_{context['object'].event.display_id}.pdf"
return context
class EventCheckIn(generic.CreateView, ModalURLMixin): class EventCheckIn(generic.CreateView, ModalURLMixin):
model = models.EventCheckIn model = models.EventCheckIn
template_name = 'hs/eventcheckin_form.html' template_name = 'hs/eventcheckin_form.html'

View File

@@ -16,7 +16,7 @@ const con = require('gulp-concat');
const gulpif = require('gulp-if'); const gulpif = require('gulp-if');
function fonts(done) { function fonts(done) {
return gulp.src('node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.*', { encoding: false }) return gulp.src('node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.*')
.pipe(gulp.dest('pipeline/built_assets/fonts')) .pipe(gulp.dest('pipeline/built_assets/fonts'))
.pipe(browsersync.stream()); .pipe(browsersync.stream());
} }
@@ -70,14 +70,14 @@ function scripts() {
.pipe(gulpif(function(file) { return interaction.includes(file.relative);}, con('interaction.js'))) .pipe(gulpif(function(file) { return interaction.includes(file.relative);}, con('interaction.js')))
.pipe(gulpif(function(file) { return jpop.includes(file.relative);}, con('jpop.js'))) .pipe(gulpif(function(file) { return jpop.includes(file.relative);}, con('jpop.js')))
.pipe(flatten()) .pipe(flatten())
// Only minify if filename does not already denote it as minified .pipe(terser())
.pipe(gulpif(function(file) { return file.path.indexOf("min") == -1;},terser()))
.pipe(gulp.dest(dest)) .pipe(gulp.dest(dest))
.pipe(browsersync.stream()); .pipe(browsersync.stream());
} }
function browserSync(done) { function browserSync(done) {
spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}); spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'});
// TODO Wait for Django server to come up before browsersync, it seems inconsistent
browsersync.init({ browsersync.init({
notify: true, notify: true,
open: false, open: false,

8901
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@
"cssnano": "^5.0.13", "cssnano": "^5.0.13",
"easymde": "^2.16.1", "easymde": "^2.16.1",
"fullcalendar": "^5.10.1", "fullcalendar": "^5.10.1",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"gulp-flatten": "^0.4.0", "gulp-flatten": "^0.4.0",
"gulp-if": "^3.0.0", "gulp-if": "^3.0.0",
@@ -33,8 +34,7 @@
"uglify-js": "^3.14.5" "uglify-js": "^3.14.5"
}, },
"devDependencies": { "devDependencies": {
"browser-sync": "^3.0.2", "browser-sync": "^3.0.2"
"gulp": "^5.0.0"
}, },
"scripts": { "scripts": {
"gulp": "gulp", "gulp": "gulp",

View File

@@ -1,11 +1,16 @@
function changeSelectedValue(obj,pk,text,update_url) { //Pass in JQuery object and new parameters function changeSelectedValue(obj,pk,text,update_url) { //Pass in JQuery object and new parameters
//console.log('Changing selected value'); //console.log('Changing selected value');
obj.find('option').remove(); //Remove all the available options obj.find('option').remove(); //Remove all the available options
obj[0].add(new Option(text, pk, true, true)); // Add new option obj.append( //Add the new option
//obj.selectpicker('val', pk); //Set the new value to be selected $("<option></option>")
obj.selectpicker('refresh'); .attr("value",pk)
.text(text)
.data('update_url',update_url)
);
obj.selectpicker('render'); //Re-render the UI
obj.selectpicker('refresh'); //Re-render the UI
obj.selectpicker('val', pk); //Set the new value to be selected
obj.change(); //Trigger the change function manually obj.change(); //Trigger the change function manually
//console.log(obj);
} }
function refreshUpdateHref(obj) { function refreshUpdateHref(obj) {

View File

@@ -17,12 +17,14 @@ jQuery(document).ready(function () {
}); });
} }
}); });
var easter_egg = new Konami(function () { var easter_egg = new Konami();
easter_egg.code = function () {
var s = document.createElement('script'); var s = document.createElement('script');
s.type = 'text/javascript'; s.type = 'text/javascript';
document.body.appendChild(s); document.body.appendChild(s);
s.src = '/static/js/asteroids.min.js'; s.src = '{% static "js/asteroids.min.js"%}';
}); ga('send', 'event', 'easter_egg', 'activated');
}
easter_egg.load(); easter_egg.load();
}); });
//CTRL-Enter form submission //CTRL-Enter form submission

View File

@@ -9,4 +9,3 @@ $theme-colors: (
"primary": #3A52A2 "primary": #3A52A2
) !default; ) !default;
$enable-shadows: true; $enable-shadows: true;
$alert-color-level: 10;

View File

@@ -281,12 +281,3 @@ html.embedded {
.bootstrap-select, button.btn.dropdown-toggle.bs-placeholder.btn-light { .bootstrap-select, button.btn.dropdown-toggle.bs-placeholder.btn-light {
padding-right: 1rem !important; padding-right: 1rem !important;
} }
// New implementation of class dropped in Bootstrap 3
.dl-horizontal {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.7rem 0;
}
.dl-horizontal > dd, .dl-horizontal .markdown > p {
margin-bottom: 0 !important;
}

View File

@@ -35,8 +35,8 @@
{% endif %} {% endif %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation"> <nav class="navbar navbar-expand-lg navbar-dark bg-dark" role="navigation">
<div class="container"> <div class="container">
<a class="navbar-brand" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}"> <a class="navbar-brand" style="position: absolute; left:0.5em; top: 2px;" href="{% if request.user.is_authenticated %}https://rigs.nottinghamtec.co.uk{%else%}https://nottinghamtec.co.uk{%endif%}">
<img src="{% static 'imgs/logo.webp' %}" class="mr-auto" style="max-height: 40px; position: absolute; left: 0.5em; top: 0;" alt="TEC's Logo: Serif 'TEC' vertically next to a blue box with the words 'PA and Lighting', surrounded by graduated rings" id="logo"> <img src="{% static 'imgs/logo.webp' %}" width="40" height="40" alt="TEC's Logo: Serif 'TEC' vertically next to a blue box with the words 'PA and Lighting', surrounded by graduated rings" id="logo">
</a> </a>
{% block titleheader %} {% block titleheader %}
{% endblock %} {% endblock %}

View File

@@ -9,11 +9,9 @@
<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>
{% if now %} {% if now %}
<div class="col-sm-12"> <div class="col-sm-12 alert alert-primary rounded-0 mx-auto">
{% for event in now %} {% for event in now %}
<div class="alert alert-primary rounded-0"> Event {{ event }} is happening today! <a href="{% url 'event_checkin' event.pk %}" class="btn btn-success btn-sm modal-href align-baseline {% if request.user.current_event %}disabled{%endif%}"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a><br/>
Event <a href="{% url 'event_detail' event.pk %}" class="text-danger">{{ event }}</a> is happening today! <a href="{% url 'event_checkin' event.pk %}" class="btn btn-success btn-sm modal-href align-baseline {% if request.user.current_event %}disabled{%endif%}"><span class="fas fa-user-clock"></span> <span class="d-none d-sm-inline">Check In</span></a><br/>
</div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}

View File

@@ -167,11 +167,9 @@
<div class="col-lg-6"> <div class="col-lg-6">
<div class="card"> <div class="card">
<div class="card-header">Events</div> <div class="card-header">Events</div>
<div style="container-type: size; height: 30vh; overflow-y: scroll;">
{% with object.latest_events as events %} {% with object.latest_events as events %}
{% include 'partials/event_table.html' %} {% include 'partials/event_table.html' %}
{% endwith %} {% endwith %}
</div>
</div> </div>
</div> </div>
</div> </div>