Merge branch '3-sample_controls' into dev
This commit is contained in:
commit
8c5896b6b1
@ -1,6 +1,8 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
from config.extras import BREWFATHER_APP_ROOT
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger('django')
|
||||
|
||||
@ -18,6 +20,10 @@ class Batch(CustomModel):
|
||||
brewfather_name = models.CharField(max_length=500, default='name')
|
||||
recipe = models.ForeignKey('BatchRecipe', on_delete=models.CASCADE, default=1)
|
||||
|
||||
@property
|
||||
def brewfather_url(self):
|
||||
return '{}/tabs/batches/batch/{}'.format(BREWFATHER_APP_ROOT, self.brewfather_id)
|
||||
|
||||
def __str__(self):
|
||||
# Return a string that represents the instance
|
||||
return 'BF #{num}: {name}'.format(name=self.brewfather_name, num=self.brewfather_num)
|
||||
|
@ -39,8 +39,8 @@ class MaintenanceAdmin(admin.ModelAdmin):
|
||||
class EquipmentAdmin(admin.ModelAdmin):
|
||||
|
||||
readonly_fields = ('id',)
|
||||
list_display = ['id', 'state', 'equipment_type', 'keg_type', 'state']
|
||||
list_editable = ['state', 'equipment_type', 'keg_type', 'state']
|
||||
list_display = ['id', 'equipment_type', 'keg_type', 'state']
|
||||
list_editable = ['state', 'state']
|
||||
|
||||
@admin.register(KegType)
|
||||
class KegTypeAdmin(admin.ModelAdmin):
|
||||
|
@ -8,12 +8,12 @@
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
|
||||
<!-- JS, Popper.js, and jQuery -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
|
||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
|
||||
crossorigin="anonymous"></script>
|
||||
<!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" -->
|
||||
<!-- integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" -->
|
||||
<!-- crossorigin="anonymous"></script> -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
{% block script %}{% endblock %}
|
||||
<style>
|
||||
{% block style %}{% endblock %}
|
||||
@ -23,6 +23,15 @@
|
||||
label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.table-borderless > tbody > tr > td,
|
||||
.table-borderless > tbody > tr > th,
|
||||
.table-borderless > tfoot > tr > td,
|
||||
.table-borderless > tfoot > tr > th,
|
||||
.table-borderless > thead > tr > td,
|
||||
.table-borderless > thead > tr > th {
|
||||
border: none;
|
||||
background-color: rgba(0,0,0, 0.0) !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -90,8 +99,6 @@
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
|
||||
</body>
|
||||
{% block endscript %}{% endblock %}
|
||||
</html>
|
||||
|
@ -2,33 +2,143 @@
|
||||
{% load mathfilters %}
|
||||
{% block title %}Yeast Samples{% endblock %}
|
||||
|
||||
{% block jumbotron %}Yeast Sample:{% endblock %}
|
||||
{% block jumbotronsub %}<a href="{% url 'admin:yeast_yeast_change' sample.id %}">{{ sample.id }}</a>{% endblock %}
|
||||
{% block style %}
|
||||
.table td.fit,
|
||||
.table th.fit {
|
||||
white-space: nowrap;
|
||||
width: 1%;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block jumbotron %}Yeast Sample{% endblock %}
|
||||
{% block jumbotronsub %}
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr><th class="fit">{{ batch.strain.manufacturer.name }} {{ batch.strain.name }}</th><td><a href="{% url 'admin:yeast_yeast_change' sample.id %}">{{ sample.id }}</a></td></tr>
|
||||
<tr><th class="fit">Batch Source</th>
|
||||
<td>{{ batch.get_source_display }}
|
||||
{% if batch.source_batch %}
|
||||
from <a href="{{ batch.beer_url }}" target="_blank" rel="noopener noreferrer">#{{ batch.beer_num }}: {{ batch.beer_name }}</a><br>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr><th class="fit">Production Date</th><td>{{ sample.batch.production_date }}</td></tr>
|
||||
<tr><th class="fit">Storage</th>
|
||||
<td>
|
||||
{{ sample.storage }}
|
||||
{% if sample.pitched %}
|
||||
(Pitched <a href="{{ sample.pitched_batch.brewfather_url }}" target="_blank" rel="noopener noreferrer">#{{ sample.pitched_batch.brewfather_num }}: {{ sample.pitched_batch.brewfather_name }}</a>)
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<!-- Information Header -->
|
||||
<div class="container">
|
||||
|
||||
<h3>{{ batch.strain.name }}</h3>
|
||||
<b>Batch Source:</b> {{ batch.get_source_display }}
|
||||
{% if batch.source_batch %}
|
||||
from <a href="{{ batch.beer_url }}" target="_blank" rel="noopener noreferrer">#{{ batch.beer_num }}: {{ batch.beer_name }}</a>
|
||||
{% endif %}<br>
|
||||
<b>Production Date:</b> {{ sample.batch.production_date }}<br>
|
||||
</div> <!-- /container -->
|
||||
<!-- End Information Header -->
|
||||
|
||||
<!-- Main Data Container -->
|
||||
<div class="container mt-4 mb-4">
|
||||
<div class="row">
|
||||
|
||||
<!-- Tabbed Forms -->
|
||||
<div class="col-lg-6" style="{% if sample.pitched %}display:none{% endif %}">
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-bs-toggle="tab" href="#propogate">Propogate Sample</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#pitch">Pitch Sample</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div id="propogate" class="container tab-pane active"><br>
|
||||
<!-- Sample Propogation Form -->
|
||||
<div class="container" style="border:1px solid #cecece;">
|
||||
<form >
|
||||
<legend>Propogate Yeast Sample</legend>
|
||||
<div class="mb-3">
|
||||
<label for="new-samples" class="form-label"># New Samples</label>
|
||||
<input type="number" class="form-control" id="new-samples" aria-describedby="numHelp">
|
||||
<div id="numHelp" class="form-text">New samples will be automatically created</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="parent" class="form-label">Default Storage Method</label>
|
||||
<select class="form-select" id="parent" name="parent" aria-describedby="storageHelp">
|
||||
<option selected>-- Choose an Option --</option>
|
||||
{% for method in storage %}
|
||||
<option value="{{ method.id }}">{{ method }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div id="storageHelp" class="form-text">How will samples be stored?</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
<!-- End Sample Propogation Form -->
|
||||
</div>
|
||||
<div id="pitch" class="container tab-pane fade"><br>
|
||||
<!-- Sample Pitch Form -->
|
||||
<div class="container" style="border:1px solid #cecece;">
|
||||
<form >
|
||||
<legend>Pitch Yeast Sample</legend>
|
||||
<div class="mb-3">
|
||||
<label for="beer-batch" class="form-label">Beer Batch</label>
|
||||
<select class="form-select" id="beer-batch" name="beer-batch" aria-describedby="batchHelp">
|
||||
<option selected>Beer Batch</option>
|
||||
<option value="1">#16 So So Special</option>
|
||||
<option value="2">#17 Some other beer</option>
|
||||
<option value="3">#18 Another Thing</option>
|
||||
</select>
|
||||
<div id="batchHelp" class="form-text">Select batch of beer sample is pitched into.</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="starterCheck">
|
||||
<label class="form-check-label" for="starterCheck">Pitched into starter?</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
<!-- End Sample Pitch Form -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- End Tabbed Forms -->
|
||||
|
||||
<!-- Remain Sample List -->
|
||||
<div class="col-lg-6">
|
||||
{% if batch.remaining_samples %}<h4>Other Remaining Batch Samples</h4>
|
||||
<ul>
|
||||
{% for s in batch.remaining_samples|dictsort:"storage.name" %}
|
||||
{% if s.id != sample.id %}
|
||||
<li><a href="{% url 'yeast:yeast' s.id %}">{{ s.id }}</a> - {{ s.storage.name }} for {{ s.age }} days, {{ s.viability|mul:100|floatformat:1 }}%</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if batch.used_samples %}<h4>Other Samples Used</h4>
|
||||
<ul>
|
||||
{% for s in batch.used_samples %}
|
||||
{% if s.id != sample.id %}
|
||||
<li><a href="{% url 'yeast:yeast' s.id %}">{{ s.id }}</a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- End Remain Sample List -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Main Data Container -->
|
||||
|
||||
<p><p>
|
||||
{% if batch.remaining_samples %}<h4>Batch Samples Remaining</h4>
|
||||
<ul>
|
||||
{% for sample in batch.remaining_samples %}
|
||||
<li><a href="{% url 'yeast:yeast' sample.id %}">{{ sample.id }}</a> - Storage method: {{ sample.storage.name }} for {{ sample.age }} days, Viability: {{ sample.viability|mul:100|floatformat:1 }}%</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if batch.used_samples %}<h4>Batch Samples Used</h4>
|
||||
<ul>
|
||||
{% for sample in batch.used_samples %}
|
||||
<li><a href="{% url 'yeast:yeast' sample.id %}">{{ sample.id }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div> <!-- /container -->
|
||||
{% endblock %}
|
||||
|
@ -21,10 +21,12 @@ class BatchListView(ListView):
|
||||
model = Propogation
|
||||
|
||||
def sample(request, yeast_id):
|
||||
|
||||
sample = get_object_or_404(Yeast, pk=yeast_id)
|
||||
sample_batch = get_object_or_404(Propogation, pk=sample.batch_id)
|
||||
return render(request, 'yeast/sample.html', {'sample': sample, 'batch':sample_batch})
|
||||
return render(request, 'yeast/sample.html', {
|
||||
'sample': sample,
|
||||
'batch': get_object_or_404(Propogation, pk=sample.batch_id),
|
||||
'storage': list(Storage.objects.all()),
|
||||
})
|
||||
|
||||
# @login_required
|
||||
# def get_batches(request):
|
||||
@ -49,8 +51,8 @@ def batch(request, batch_id):
|
||||
"""
|
||||
Display a batch of yeast samples.
|
||||
|
||||
``Batch``
|
||||
An instance of :model:`yeast.Batch`.
|
||||
``Propogation``
|
||||
An instance of :model:`yeast.Propogation`.
|
||||
|
||||
``Template``
|
||||
:template:`yeast/batch.html`
|
||||
@ -65,7 +67,7 @@ def batch_labels(request, batch_id):
|
||||
**Context**
|
||||
|
||||
``Batch``
|
||||
An instance of :model:`yeast.Batch`.
|
||||
An instance of :model:`yeast.Propogation`.
|
||||
"""
|
||||
skip_count = request.POST.get("skip_count", "")
|
||||
samples = request.POST.getlist("samples", "")
|
||||
|
Loading…
Reference in New Issue
Block a user