Merge branch '3-sample_controls' into dev

This commit is contained in:
Chris Giacofei 2024-06-07 11:41:06 -04:00
commit 8c5896b6b1
5 changed files with 166 additions and 41 deletions

View File

@ -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)

View File

@ -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):

View File

@ -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>

View File

@ -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 %}

View File

@ -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", "")