new update
This commit is contained in:
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
@@ -1,2 +1,45 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from .models import Client # Only import Client
|
||||||
|
from .models import SecondTableEntry
|
||||||
|
|
||||||
|
# Register only the Client model
|
||||||
|
@admin.register(Client)
|
||||||
|
class ClientAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'address')
|
||||||
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
# Optional: Customize the add form fields
|
||||||
|
fields = ['name', 'address']
|
||||||
|
|
||||||
|
@admin.register(SecondTableEntry)
|
||||||
|
class SecondTableEntryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('id', 'client', 'date', 'is_warm', 'lhe_output_short', 'notes_preview')
|
||||||
|
list_display_links = ('id', 'client') # Fields that link to edit page
|
||||||
|
list_editable = ('is_warm',)
|
||||||
|
list_filter = ('is_warm', 'client')
|
||||||
|
search_fields = ('client__name', 'notes')
|
||||||
|
date_hierarchy = 'date'
|
||||||
|
ordering = ('-date',)
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {
|
||||||
|
'fields': ('client', 'date')
|
||||||
|
}),
|
||||||
|
('LHe Data', {
|
||||||
|
'fields': ('is_warm', 'lhe_delivery', 'lhe_output'),
|
||||||
|
'description': 'Enter all liquid helium measurements'
|
||||||
|
}),
|
||||||
|
('Additional Info', {
|
||||||
|
'fields': ('notes',),
|
||||||
|
'classes': ('collapse',)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
# Custom display methods
|
||||||
|
def lhe_output_short(self, obj):
|
||||||
|
return f"{obj.lhe_output} L" if obj.lhe_output else "-"
|
||||||
|
lhe_output_short.short_description = 'Output'
|
||||||
|
|
||||||
|
def notes_preview(self, obj):
|
||||||
|
return obj.notes[:30] + '...' if obj.notes else ""
|
||||||
|
notes_preview.short_description = 'Notes Preview'
|
@@ -0,0 +1,47 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-07-08 12:13
|
||||||
|
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sheets', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='age',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='email',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(default=django.utils.timezone.now),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='is_warm',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='lhe_delivery',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='lhe_output',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
19
sheets/migrations/0003_alter_secondtableentry_lhe_output.py
Normal file
19
sheets/migrations/0003_alter_secondtableentry_lhe_output.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-07-08 13:18
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sheets', '0002_remove_secondtableentry_age_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='lhe_output',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
]
|
18
sheets/migrations/0004_alter_secondtableentry_lhe_output.py
Normal file
18
sheets/migrations/0004_alter_secondtableentry_lhe_output.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-07-08 13:35
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sheets', '0003_alter_secondtableentry_lhe_output'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='lhe_output',
|
||||||
|
field=models.CharField(blank=True, max_length=100, null=True),
|
||||||
|
),
|
||||||
|
]
|
19
sheets/migrations/0005_alter_secondtableentry_lhe_output.py
Normal file
19
sheets/migrations/0005_alter_secondtableentry_lhe_output.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-07-08 13:36
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sheets', '0004_alter_secondtableentry_lhe_output'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='secondtableentry',
|
||||||
|
name='lhe_output',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
]
|
@@ -0,0 +1,43 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-07-09 11:15
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('sheets', '0005_alter_secondtableentry_lhe_output'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='age',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='email',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='date',
|
||||||
|
field=models.DateField(default=django.utils.timezone.now),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='notes',
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='pressure',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='excelentry',
|
||||||
|
name='purity',
|
||||||
|
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=5, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(100)]),
|
||||||
|
),
|
||||||
|
]
|
@@ -1,4 +1,8 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Client(models.Model):
|
class Client(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
@@ -9,12 +13,39 @@ class Client(models.Model):
|
|||||||
|
|
||||||
class ExcelEntry(models.Model):
|
class ExcelEntry(models.Model):
|
||||||
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
||||||
age = models.IntegerField()
|
date = models.DateField(default=timezone.now)
|
||||||
email = models.EmailField()
|
pressure = models.DecimalField(
|
||||||
|
max_digits=10,
|
||||||
|
decimal_places=2,
|
||||||
|
validators=[MinValueValidator(0)],
|
||||||
|
default=0.00
|
||||||
|
)
|
||||||
|
purity = models.DecimalField(
|
||||||
|
max_digits=5,
|
||||||
|
decimal_places=2,
|
||||||
|
validators=[MinValueValidator(0), MaxValueValidator(100)],
|
||||||
|
default=0.00
|
||||||
|
)
|
||||||
|
notes = models.TextField(blank=True, null=True)
|
||||||
date_joined = models.DateField(auto_now_add=True)
|
date_joined = models.DateField(auto_now_add=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.client.name} - {self.date}"
|
||||||
|
|
||||||
class SecondTableEntry(models.Model):
|
class SecondTableEntry(models.Model):
|
||||||
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
client = models.ForeignKey(Client, on_delete=models.CASCADE)
|
||||||
age = models.IntegerField()
|
date = models.DateField(default=timezone.now) # Added default value
|
||||||
email = models.EmailField()
|
is_warm = models.BooleanField(default=False)
|
||||||
|
lhe_delivery = models.CharField(max_length=100, blank=True, null=True)
|
||||||
|
lhe_output = models.DecimalField(
|
||||||
|
max_digits=10,
|
||||||
|
decimal_places=2,
|
||||||
|
validators=[MinValueValidator(0)],
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
notes = models.TextField(blank=True, null=True)
|
||||||
date_joined = models.DateField(auto_now_add=True)
|
date_joined = models.DateField(auto_now_add=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.client.name} - {self.date}"
|
@@ -1,290 +1,124 @@
|
|||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Clients Table</title>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" />
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #f4f4f9;
|
|
||||||
}
|
|
||||||
.add-row-btn, .btn-go-back {
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.add-row-btn:hover,
|
|
||||||
.btn-go-back:hover {
|
|
||||||
background-color: #0056b3;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
background-color: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
th, td {
|
|
||||||
padding: 12px;
|
|
||||||
text-align: left;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
th {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
tr:hover {
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
}
|
|
||||||
.actions button {
|
|
||||||
margin: 2px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.edit-btn {
|
|
||||||
|
|
||||||
background-color: #28a745;
|
{% block content %}
|
||||||
color: white;
|
<div class="container">
|
||||||
}
|
<!-- Year Filter -->
|
||||||
.delete-btn {
|
<div class="year-filter">
|
||||||
background-color: #dc3545;
|
<label for="year-select">Year:</label>
|
||||||
color: white;
|
<select id="year-select" onchange="window.location.href='?year='+this.value">
|
||||||
}
|
{% for year in available_years %}
|
||||||
.popup {
|
<option value="{{ year }}" {% if year == current_year %}selected{% endif %}>
|
||||||
display: none;
|
{{ year }}
|
||||||
position: fixed;
|
</option>
|
||||||
top: 50%;
|
{% endfor %}
|
||||||
left: 50%;
|
</select>
|
||||||
transform: translate(-50%, -50%);
|
</div>
|
||||||
background: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.popup input {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
width: 100%;
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.popup button {
|
|
||||||
margin-top: 10px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
.close-btn {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
|
<!-- Annual Summary Table -->
|
||||||
<div class="container">
|
<table class="summary-table">
|
||||||
<h2>Clients Table</h2>
|
|
||||||
<button class="add-row-btn" id="add-client">Add Client</button>
|
|
||||||
<table>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th> <!-- This is your new sequential number column -->
|
<th>Client</th>
|
||||||
<th>ID</th>
|
{% for month in months %}
|
||||||
<th>Name</th>
|
<th>{{ month }}</th>
|
||||||
<th>Address</th>
|
{% endfor %}
|
||||||
<th>Actions</th>
|
<th>Total</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for client in clients %}
|
{% for data in monthly_data %}
|
||||||
<tr data-id="{{ client.id }}">
|
<tr>
|
||||||
<td>{{ forloop.counter }}</td> <!-- ← this gives you 1, 2, 3... -->
|
<td>{{ data.client.name }}</td>
|
||||||
<td>{{ client.id }}</td>
|
{% for total in data.monthly_totals %}
|
||||||
<td>{{ client.name }}</td>
|
<td>{{ total|floatformat:2 }}</td>
|
||||||
<td>{{ client.address }}</td>
|
{% endfor %}
|
||||||
<td class="actions">
|
<td class="total">{{ data.year_total|floatformat:2 }}</td>
|
||||||
<button class="edit-btn">Edit</button>
|
|
||||||
<button class="delete-btn">Delete</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Add Client Popup -->
|
<!-- Navigation Buttons -->
|
||||||
<div id="add-popup" class="popup">
|
<div class="navigation-buttons">
|
||||||
<span class="close-btn">×</span>
|
<a href="{% url 'table_one' %}" class="nav-button">
|
||||||
<h3>Add Client</h3>
|
Go to Helium Input
|
||||||
<input type="text" id="add-name" placeholder="Name">
|
|
||||||
<input type="text" id="add-address" placeholder="Address">
|
|
||||||
<button id="save-add">Add</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Edit Client Popup -->
|
|
||||||
<div id="edit-popup" class="popup">
|
|
||||||
<span class="close-btn">×</span>
|
|
||||||
<h3>Edit Client</h3>
|
|
||||||
<input type="hidden" id="edit-id">
|
|
||||||
<input type="text" id="edit-name" placeholder="Name">
|
|
||||||
<input type="text" id="edit-address" placeholder="Address">
|
|
||||||
<button id="save-edit">Save</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 30px; text-align: center;">
|
|
||||||
<a href="{% url 'table_one' %}">
|
|
||||||
<button class="add-row-btn">Go to Helium input</button>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'table_two' %}">
|
<a href="{% url 'table_two' %}" class="nav-button">
|
||||||
<button class="add-row-btn">Go to Table output</button>
|
Go to Helium Output
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
<script>
|
.container {
|
||||||
let currentModelName = "Client";
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
// Open Add Popup
|
padding: 20px;
|
||||||
$('#add-client').on('click', function () {
|
|
||||||
$('#add-popup').fadeIn();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Close Popups
|
|
||||||
$('.close-btn').on('click', function () {
|
|
||||||
$('.popup').fadeOut();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save Add Client
|
|
||||||
$('#save-add').on('click', function () {
|
|
||||||
let name = $('#add-name').val();
|
|
||||||
let address = $('#add-address').val();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: `/add-entry/Client/`,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
'name': name,
|
|
||||||
'address': address,
|
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
let rowCount = $('tbody tr').length + 1;
|
|
||||||
let newRow = `
|
|
||||||
<tr data-id="${response.id}">
|
|
||||||
<td>${rowCount}</td>
|
|
||||||
<td>${response.id}</td>
|
|
||||||
<td>${response.name}</td>
|
|
||||||
<td>${response.address}</td>
|
|
||||||
<td class="actions">
|
|
||||||
<button class="edit-btn">Edit</button>
|
|
||||||
<button class="delete-btn">Delete</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
|
||||||
$('tbody').append(newRow);
|
|
||||||
$('#add-popup').fadeOut();
|
|
||||||
},
|
|
||||||
error: function (xhr) {
|
|
||||||
alert('Failed to add client: ' + xhr.responseText);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Open Edit Popup
|
.year-filter {
|
||||||
$(document).on('click', '.edit-btn', function () {
|
margin: 20px 0;
|
||||||
let row = $(this).closest('tr');
|
text-align: right;
|
||||||
$('#edit-id').val(row.data('id'));
|
|
||||||
$('#edit-name').val(row.find('td:eq(2)').text()); // Name
|
|
||||||
$('#edit-address').val(row.find('td:eq(3)').text()); // Address
|
|
||||||
$('#edit-popup').fadeIn();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Save Edit Client
|
|
||||||
$('#save-edit').on('click', function () {
|
|
||||||
let id = $('#edit-id').val();
|
|
||||||
let name = $('#edit-name').val();
|
|
||||||
let address = $('#edit-address').val();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: `/update-entry/${currentModelName}/`,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
'id': id,
|
|
||||||
'name': name,
|
|
||||||
'address': address,
|
|
||||||
'age': 0,
|
|
||||||
'email': 'none@example.com',
|
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
if (response.status === 'success') {
|
|
||||||
let row = $(`tr[data-id="${id}"]`);
|
|
||||||
row.find('td:eq(2)').text(name); // Correct column for Name
|
|
||||||
row.find('td:eq(3)').text(address); // Correct column for Address
|
|
||||||
$('#edit-popup').fadeOut();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.year-filter label {
|
||||||
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete Client
|
.year-filter select {
|
||||||
$(document).on('click', '.delete-btn', function () {
|
padding: 5px;
|
||||||
let row = $(this).closest('tr');
|
border-radius: 4px;
|
||||||
let id = row.data('id');
|
border: 1px solid #ddd;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to delete this client?')) return;
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: `/delete-entry/${currentModelName}/`,
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
'id': id,
|
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
if (response.status === 'success') {
|
|
||||||
row.fadeOut(300, function () { $(this).remove(); });
|
|
||||||
} else {
|
|
||||||
alert('Delete failed: ' + response.message);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
error: function (xhr, status, error) {
|
|
||||||
alert('Delete request failed:\n' + xhr.responseText);
|
|
||||||
console.log('Error:', error);
|
|
||||||
console.log('Status:', status);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
.summary-table {
|
||||||
</html>
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-table th, .summary-table td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-table th {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-table tr:nth-child(even) {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-table tr:hover {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: #e6f2ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button {
|
||||||
|
padding: 12px 24px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-button:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
@@ -27,18 +27,32 @@
|
|||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
table-layout: fixed;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
margin-top: 20px;
|
|
||||||
}
|
}
|
||||||
th, td {
|
th, td {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
text-align: left;
|
text-align: center;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
th:nth-child(1), td:nth-child(1) { width: 5%; } /* # column */
|
||||||
|
th:nth-child(2), td:nth-child(2) { width: 5%; } /* ID column */
|
||||||
|
th:nth-child(3), td:nth-child(3) { width: 15%; } /* Client column */
|
||||||
|
th:nth-child(4), td:nth-child(4) { width: 10%; } /* Entry 1 (Pressure) */
|
||||||
|
th:nth-child(5), td:nth-child(5) { width: 10%; } /* Entry 2 (Purity) */
|
||||||
|
th:nth-child(6), td:nth-child(6) { width: 15%; } /* Date Joined */
|
||||||
|
th:nth-child(7), td:nth-child(7) { width: 25%; } /* Notes */
|
||||||
|
th:nth-child(7), td:nth-child(7) { width: 30%; } /* Actions */
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
white-space: nowrap; /* Prevent buttons from wrapping */
|
||||||
|
}
|
||||||
th {
|
th {
|
||||||
background-color: #007bff;
|
background-color: #007bff;
|
||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
tr:hover {
|
tr:hover {
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
@@ -106,6 +120,7 @@
|
|||||||
.add-row-btn:hover {
|
.add-row-btn:hover {
|
||||||
background-color: #0056b3;
|
background-color: #0056b3;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -118,14 +133,25 @@
|
|||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<button class="add-row-btn" id="add-row-one">Add Row</button>
|
<button class="add-row-btn" id="add-row-one">Add Row</button>
|
||||||
<table id="table-one">
|
<table id="table-one">
|
||||||
|
<colgroup>
|
||||||
|
<col style="width: 5%"> <!-- # -->
|
||||||
|
<col style="width: 5%"> <!-- ID -->
|
||||||
|
<col style="width: 15%"> <!-- Client -->
|
||||||
|
<col style="width: 10%"> <!-- Druck -->
|
||||||
|
<col style="width: 10%"> <!-- Reinheit -->
|
||||||
|
<col style="width: 15%"> <!-- Date Joined -->
|
||||||
|
<col style="width: 25%"> <!-- Notes -->
|
||||||
|
<col style="width: 15%"> <!-- Actions -->
|
||||||
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th>ID</th>
|
<th>ID</th>
|
||||||
<th>Client</th>
|
<th>Client</th>
|
||||||
<th>Entry 1</th>
|
<th>Druck</th>
|
||||||
<th>Entry 2</th>
|
<th>Reinheit</th>
|
||||||
<th>Date Joined</th>
|
<th>Date Joined</th>
|
||||||
|
<th>Notes</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -135,9 +161,10 @@
|
|||||||
<td>{{ forloop.counter }}</td>
|
<td>{{ forloop.counter }}</td>
|
||||||
<td>{{ entry.id }}</td>
|
<td>{{ entry.id }}</td>
|
||||||
<td>{{ entry.client.name }}</td>
|
<td>{{ entry.client.name }}</td>
|
||||||
<td>{{ entry.age }}</td>
|
<td>{{ entry.pressure|floatformat:2 }}</td>
|
||||||
<td>{{ entry.email }}</td>
|
<td>{{ entry.purity|floatformat:2 }}</td>
|
||||||
<td>{{ entry.date_joined }}</td>
|
<td>{{ entry.date_joined|date:"Y-m-d" }}</td>
|
||||||
|
<td>{{ entry.notes|default:"" }}</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
<button class="edit-btn-one">Edit</button>
|
<button class="edit-btn-one">Edit</button>
|
||||||
<button class="delete-btn-one">Delete</button>
|
<button class="delete-btn-one">Delete</button>
|
||||||
@@ -152,30 +179,72 @@
|
|||||||
<!-- Add Popup -->
|
<!-- Add Popup -->
|
||||||
<div id="add-popup-one" class="popup">
|
<div id="add-popup-one" class="popup">
|
||||||
<span class="close-btn">×</span>
|
<span class="close-btn">×</span>
|
||||||
<h3>Add Entry</h3>
|
<h3>He Gas Bundle</h3>
|
||||||
|
|
||||||
|
<label for="add-client-id">Kunde:</label>
|
||||||
<select id="add-client-id">
|
<select id="add-client-id">
|
||||||
{% for client in clients %}
|
{% for client in clients %}
|
||||||
<option value="{{ client.id }}">{{ client.name }}</option>
|
<option value="{{ client.id }}">{{ client.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="number" id="add-age" placeholder="Age">
|
|
||||||
<input type="email" id="add-email" placeholder="Email">
|
<label for="add-date">Date:</label>
|
||||||
<button id="save-add-one">Add</button>
|
<input type="date" id="add-date">
|
||||||
|
|
||||||
|
<div class="input-with-label">
|
||||||
|
<label for="add-pressure">Druck:</label>
|
||||||
|
<input type="number" id="add-pressure" placeholder="Enter pressure" step="0.01" min="0">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-with-label">
|
||||||
|
<label for="add-purity">Reinheit:</label>
|
||||||
|
<input type="number" id="add-purity" placeholder="Enter purity" step="0.01" min="0" max="100">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="add-notes">Notes:</label>
|
||||||
|
<textarea id="add-notes" placeholder="Additional notes"></textarea>
|
||||||
|
|
||||||
|
<div class="popup-buttons">
|
||||||
|
<button class="save-btn" id="save-add-one">Save</button>
|
||||||
|
<button class="cancel-btn">Cancel</button>
|
||||||
|
<button class="help-btn">Help</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Edit Popup -->
|
<!-- Edit Popup -->
|
||||||
<div id="edit-popup-one" class="popup">
|
<div id="edit-popup-one" class="popup">
|
||||||
<span class="close-btn">×</span>
|
<span class="close-btn">×</span>
|
||||||
<h3>Edit Entry</h3>
|
<h3>He Gas Bundle</h3>
|
||||||
<input type="hidden" id="edit-id">
|
<input type="hidden" id="edit-id">
|
||||||
|
|
||||||
|
<label for="edit-client-id">Kunde:</label>
|
||||||
<select id="edit-client-id">
|
<select id="edit-client-id">
|
||||||
{% for client in clients %}
|
{% for client in clients %}
|
||||||
<option value="{{ client.id }}">{{ client.name }}</option>
|
<option value="{{ client.id }}">{{ client.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="number" id="edit-age" placeholder="Age">
|
|
||||||
<input type="email" id="edit-email" placeholder="Email">
|
<label for="edit-date">Date:</label>
|
||||||
<button id="save-edit-one">Save</button>
|
<input type="date" id="edit-date">
|
||||||
|
|
||||||
|
<div class="input-with-label">
|
||||||
|
<label for="edit-pressure">Druck:</label>
|
||||||
|
<input type="number" id="edit-pressure" placeholder="Enter pressure" step="0.01" min="0">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-with-label">
|
||||||
|
<label for="edit-purity">Reinheit:</label>
|
||||||
|
<input type="number" id="edit-purity" placeholder="Enter purity" step="0.01" min="0" max="100">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="edit-notes">Notes:</label>
|
||||||
|
<textarea id="edit-notes" placeholder="Additional notes"></textarea>
|
||||||
|
|
||||||
|
<div class="popup-buttons">
|
||||||
|
<button class="save-btn" id="save-edit-one">Save</button>
|
||||||
|
<button class="cancel-btn">Cancel</button>
|
||||||
|
<button class="help-btn">Help</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -192,81 +261,135 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
$('#save-add-one').on('click', function () {
|
$('#save-add-one').on('click', function() {
|
||||||
let client_id = $('#add-client-id').val();
|
// Validate date first
|
||||||
let age = $('#add-age').val();
|
let dateInput = $('#add-date').val();
|
||||||
let email = $('#add-email').val();
|
if (!dateInput) {
|
||||||
|
alert('Please select a date');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate numbers
|
||||||
|
let pressure = parseFloat($('#add-pressure').val());
|
||||||
|
let purity = parseFloat($('#add-purity').val());
|
||||||
|
|
||||||
|
if (isNaN(pressure) || pressure < 0) {
|
||||||
|
alert('Please enter a valid pressure value');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(purity) || purity < 0 || purity > 100) {
|
||||||
|
alert('Please enter a valid purity value (0-100)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the form data
|
||||||
|
let formData = {
|
||||||
|
'client_id': $('#add-client-id').val(),
|
||||||
|
'date': dateInput,
|
||||||
|
'pressure': pressure,
|
||||||
|
'purity': purity,
|
||||||
|
'notes': $('#add-notes').val(),
|
||||||
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||||
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/add-entry/${currentModelName}/`,
|
url: '/add-entry/ExcelEntry/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: formData,
|
||||||
'client_id': client_id,
|
success: function(response) {
|
||||||
'age': age,
|
if (response.status === 'success') {
|
||||||
'email': email,
|
// Add the new row to the table
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
let rowCount = $(`#${currentTableId} tbody tr`).length + 1;
|
|
||||||
let newRow = `
|
let newRow = `
|
||||||
<tr data-id="${response.id}">
|
<tr data-id="${response.id}">
|
||||||
<td>${rowCount}</td>
|
<td>${$('#table-one tbody tr').length + 1}</td>
|
||||||
<td>${response.id}</td>
|
<td>${response.id}</td>
|
||||||
<td>${response.client_name}</td>
|
<td>${response.client_name}</td>
|
||||||
<td>${response.age}</td>
|
<td>${response.pressure}</td>
|
||||||
<td>${response.email}</td>
|
<td>${response.purity}</td>
|
||||||
<td>${response.date_joined}</td>
|
<td>${response.date || ''}</td>
|
||||||
|
<td>${response.notes || ''}</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
<button class="edit-btn-one">Edit</button>
|
<button class="edit-btn-one">Edit</button>
|
||||||
<button class="delete-btn-one">Delete</button>
|
<button class="delete-btn-one">Delete</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
$(`#${currentTableId} tbody`).append(newRow);
|
$('#table-one tbody').append(newRow);
|
||||||
$('#add-popup-one').fadeOut();
|
$('#add-popup-one').fadeOut();
|
||||||
|
} else {
|
||||||
|
alert('Error: ' + (response.message || 'Failed to add entry'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
alert('Error: ' + (xhr.responseJSON?.message || 'Server error'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Edit
|
// Edit
|
||||||
$(document).on('click', '.edit-btn-one', function () {
|
$(document).on('click', '.edit-btn-one', function() {
|
||||||
let row = $(this).closest('tr');
|
let row = $(this).closest('tr');
|
||||||
$('#edit-id').val(row.data('id'));
|
$('#edit-id').val(row.data('id'));
|
||||||
$('#edit-client-id').val(row.find('td:eq(2)').text());
|
$('#edit-client-id').val(row.find('td:eq(2)').text().trim());
|
||||||
$('#edit-age').val(row.find('td:eq(3)').text());
|
|
||||||
$('#edit-email').val(row.find('td:eq(4)').text());
|
// Handle date - ensure it's in correct format
|
||||||
|
let dateText = row.find('td:eq(5)').text().trim();
|
||||||
|
if (dateText) {
|
||||||
|
$('#edit-date').val(dateText);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#edit-pressure').val(row.find('td:eq(3)').text().trim());
|
||||||
|
$('#edit-purity').val(row.find('td:eq(4)').text().trim());
|
||||||
|
$('#edit-notes').val(row.find('td:eq(6)').text().trim());
|
||||||
$('#edit-popup-one').fadeIn();
|
$('#edit-popup-one').fadeIn();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#save-edit-one').on('click', function () {
|
// Update the save-edit-one handler
|
||||||
let id = $('#edit-id').val();
|
$('#save-edit-one').on('click', function() {
|
||||||
let client_id = $('#edit-client-id').val();
|
let formData = {
|
||||||
let age = $('#edit-age').val();
|
'id': $('#edit-id').val(),
|
||||||
let email = $('#edit-email').val();
|
'client_id': $('#edit-client-id').val(),
|
||||||
|
'date': $('#edit-date').val(), // Already in YYYY-MM-DD format
|
||||||
|
'pressure': $('#edit-pressure').val(),
|
||||||
|
'purity': $('#edit-purity').val(),
|
||||||
|
'notes': $('#edit-notes').val(),
|
||||||
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate inputs
|
||||||
|
if (!formData.date) {
|
||||||
|
alert('Please select a date');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(formData.pressure) || formData.pressure < 0) {
|
||||||
|
alert('Please enter a valid pressure value');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isNaN(formData.purity) || formData.purity < 0 || formData.purity > 100) {
|
||||||
|
alert('Please enter a valid purity value (0-100)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/update-entry/${currentModelName}/`,
|
url: '/update-entry/ExcelEntry/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: formData,
|
||||||
'id': id,
|
success: function(response) {
|
||||||
'client_id': client_id,
|
|
||||||
'age': age,
|
|
||||||
'email': email,
|
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
let row = $(`tr[data-id="${response.id}"]`);
|
let row = $(`tr[data-id="${response.id}"]`);
|
||||||
row.find('td:eq(2)').text(response.name);
|
row.find('td:eq(2)').text(response.client_name);
|
||||||
row.find('td:eq(3)').text(response.age);
|
row.find('td:eq(3)').text(response.pressure);
|
||||||
row.find('td:eq(4)').text(response.email);
|
row.find('td:eq(4)').text(response.purity);
|
||||||
|
row.find('td:eq(5)').text(response.date || '');
|
||||||
|
row.find('td:eq(6)').text(response.notes || '');
|
||||||
$('#edit-popup-one').fadeOut();
|
$('#edit-popup-one').fadeOut();
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to update entry: ' + response.message);
|
alert('Error: ' + (response.message || 'Failed to update entry'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function(xhr) {
|
||||||
alert('Failed to update entry. Please try again.');
|
alert('Error: ' + (xhr.responseJSON?.message || 'Server error'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="UTF-8">
|
||||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Helium Output</title>
|
<title>Helium Output</title>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.js"></script>
|
||||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" rel="stylesheet"/>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-modal/0.9.1/jquery.modal.min.css" />
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -76,23 +75,56 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
width: 400px;
|
||||||
}
|
}
|
||||||
.popup input {
|
.popup h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.popup label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.popup input, .popup select, .popup textarea {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.popup textarea {
|
||||||
|
height: 100px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
.popup-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
}
|
}
|
||||||
.popup button {
|
.popup button {
|
||||||
margin-top: 10px;
|
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
.save-btn {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.cancel-btn {
|
||||||
|
background-color: #6c757d;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.help-btn {
|
||||||
|
background-color: #17a2b8;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
.close-btn {
|
.close-btn {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
float: right;
|
float: right;
|
||||||
@@ -112,174 +144,244 @@
|
|||||||
.add-row-btn:hover {
|
.add-row-btn:hover {
|
||||||
background-color: #0056b3;
|
background-color: #0056b3;
|
||||||
}
|
}
|
||||||
.popup select {
|
.checkbox-container {
|
||||||
display: block;
|
display: flex;
|
||||||
margin-bottom: 10px;
|
align-items: center;
|
||||||
width: 100%;
|
margin-bottom: 15px;
|
||||||
padding: 8px;
|
}
|
||||||
border: 1px solid #ddd;
|
.checkbox-container input[type="checkbox"] {
|
||||||
border-radius: 4px;
|
width: auto;
|
||||||
font-family: Arial, sans-serif;
|
margin-right: 10px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.input-with-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.input-with-label label {
|
||||||
|
width: 120px;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.input-with-label input {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="d-flex justify-content-start mb-2">
|
|
||||||
<!-- "Go to Clients" button at top-left -->
|
<div class="d-flex justify-content-start mb-2">
|
||||||
<a class="btn btn-outline-primary" href="{% url 'clients_list' %}">
|
<!-- "Go to Clients" button at top-left -->
|
||||||
⇦ Go to Clients
|
<a href="{% url 'clients_list' %}" class="btn btn-outline-primary">
|
||||||
|
⇦ Go to Clients
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<h2>Helium Output</h2>
|
|
||||||
<!-- Second Table -->
|
<h2>LHe Dewar Output</h2>
|
||||||
<div class="table-container">
|
|
||||||
<button class="add-row-btn" id="add-row-two">Add Row</button>
|
<div class="table-container">
|
||||||
<table id="table-two">
|
<button class="add-row-btn" id="add-row-two">Add Output</button>
|
||||||
<thead><tr><th>#</th><th>ID</th><th>Client</th><th>Date</th><th>Warm</th><th>LHe Anlieferung</th><th>LHe Ausgabe</th><th>Comments</th><th>Actions</th></tr></thead>
|
<table id="table-two">
|
||||||
<tbody>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Warm</th>
|
||||||
|
<th>LHe Delivery</th>
|
||||||
|
<th>LHe Output</th>
|
||||||
|
<th>Notes</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
{% for entry in entries_table2 %}
|
{% for entry in entries_table2 %}
|
||||||
<tr data-id="{{ entry.id }}">
|
<tr data-id="{{ entry.id }}">
|
||||||
<td>{{ forloop.counter }}</td>
|
<td>{{ forloop.counter }}</td>
|
||||||
<td>{{ entry.id }}</td>
|
<td>{{ entry.id }}</td>
|
||||||
<td>{{ entry.client.name }}</td>
|
<td>{{ entry.client.name }}</td>
|
||||||
<td>{{ entry.age }}</td>
|
<td>{{ entry.date }}</td>
|
||||||
<td>{{ entry.email }}</td>
|
<td>{{ entry.is_warm|yesno:"Yes,No" }}</td>
|
||||||
<td>{{ entry.date_joined }}</td>
|
<td>{{ entry.lhe_delivery }}</td>
|
||||||
<td class="actions">
|
<td>{{ entry.lhe_output }}</td>
|
||||||
<button class="edit-btn-two">Edit</button>
|
<td>{{ entry.notes }}</td>
|
||||||
<button class="delete-btn-two">Delete</button>
|
<td class="actions">
|
||||||
</td>
|
<button class="edit-btn-two">Edit</button>
|
||||||
</tr>
|
<button class="delete-btn-two">Delete</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Add Entry Popup -->
|
<!-- Add Entry Popup -->
|
||||||
<div id="add-popup-two" class="popup" style="display:none;">
|
<div id="add-popup-two" class="popup">
|
||||||
<span class="close-btn">×</span>
|
<span class="close-btn">×</span>
|
||||||
<h3>Add Entry</h3>
|
<h3>LHe Dewar Output</h3>
|
||||||
<label for="add-client-id">Kunde:</label>
|
<label for="add-client-id">Client:</label>
|
||||||
<select id="add-client-id">
|
<select id="add-client-id">
|
||||||
{% for client in clients %}
|
{% for client in clients %}
|
||||||
<option value="{{ client.id }}">{{ client.name }}</option>
|
<option value="{{ client.id }}">{{ client.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
<label for="add-date">Date:</label>
|
||||||
<label for="add-date">Datum:</label>
|
|
||||||
<input type="date" id="add-date">
|
<input type="date" id="add-date">
|
||||||
|
|
||||||
<label><input type="checkbox" id="add-warm"> warm</label>
|
<div class="checkbox-container">
|
||||||
|
<input type="checkbox" id="add-is-warm">
|
||||||
<label for="add-lhe-anlieferung">LHe Anlieferung:</label>
|
<label for="add-is-warm">Warm</label>
|
||||||
<input type="text" id="add-lhe-anlieferung" placeholder="LHe Anlieferung">
|
|
||||||
|
|
||||||
<label for="add-lhe-ausgabe">LHe Ausgabe:</label>
|
|
||||||
<input type="text" id="add-lhe-ausgabe" placeholder="LHe Ausgabe">
|
|
||||||
|
|
||||||
<label for="add-comment">Kommentar:</label>
|
|
||||||
<textarea id="add-comment" rows="4"></textarea>
|
|
||||||
|
|
||||||
<div style="margin-top: 10px;">
|
|
||||||
<button id="save-add-two">💾 Save</button>
|
|
||||||
<button class="close-btn">❌ Cancel</button>
|
|
||||||
<button id="help-btn">❓ Help</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
<div class="input-with-label">
|
||||||
<!-- Edit Entry Popup -->
|
<label for="add-lhe-delivery">LHe Anlieferung:</label>
|
||||||
<div class="popup" id="edit-popup-two">
|
<input type="text" id="add-lhe-delivery" placeholder="Enter delivery amount">
|
||||||
<span class="close-btn">×</span>
|
</div>
|
||||||
<h3>Edit Entry</h3>
|
|
||||||
<input id="edit-id" type="hidden"/>
|
<div class="input-with-label">
|
||||||
<label for="edit-client-id">Kunde:</label>
|
<label for="add-lhe-output">LHe Ausgabe:</label>
|
||||||
<select id="edit-client-id">
|
<input type="number" id="add-lhe-output" placeholder="Enter output amount (numbers only)" step="0.01" min="0" placeholder="Enter output amount">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="add-notes">Notes:</label>
|
||||||
|
<textarea id="add-notes" placeholder="Additional notes"></textarea>
|
||||||
|
|
||||||
|
<div class="popup-buttons">
|
||||||
|
<button class="save-btn" id="save-add-two">Save</button>
|
||||||
|
<button class="cancel-btn" id="cancel-add-two">Cancel</button>
|
||||||
|
<button class="help-btn">Help</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Edit Entry Popup -->
|
||||||
|
<div id="edit-popup-two" class="popup">
|
||||||
|
<span class="close-btn">×</span>
|
||||||
|
<h3>LHe Dewar Output</h3>
|
||||||
|
<input type="hidden" id="edit-id">
|
||||||
|
<label for="edit-client-id">Client:</label>
|
||||||
|
<select id="edit-client-id">
|
||||||
{% for client in clients %}
|
{% for client in clients %}
|
||||||
<option value="{{ client.id }}">{{ client.name }}</option>
|
<option value="{{ client.id }}">{{ client.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<label><input id="edit-warm" type="checkbox"/> warm</label>
|
<label for="edit-date">Date:</label>
|
||||||
<input id="edit-anlieferung" placeholder="LHe Anlieferung" type="text"/>
|
<input type="date" id="edit-date">
|
||||||
<input id="edit-ausgabe" placeholder="LHe Ausgabe" type="text"/>
|
|
||||||
<textarea id="edit-comments" placeholder="Comments" rows="4"></textarea>
|
<div class="checkbox-container">
|
||||||
<button id="save-edit-two">Save</button>
|
<input type="checkbox" id="edit-is-warm">
|
||||||
<button class="close-btn">Cancel</button>
|
<label for="edit-is-warm">Warm</label>
|
||||||
<button id="help-btn-edit-two">Help</button>
|
</div>
|
||||||
</div>
|
|
||||||
<script>
|
<div class="input-with-label">
|
||||||
|
<label for="edit-lhe-delivery">LHe Anlieferung:</label>
|
||||||
|
<input type="text" id="edit-lhe-delivery" placeholder="Enter delivery amount">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-with-label">
|
||||||
|
<label for="edit-lhe-output">LHe Ausgabe:</label>
|
||||||
|
<input type="number" id="edit-lhe-output" placeholder="Enter output amount">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="edit-notes">Notes:</label>
|
||||||
|
<textarea id="edit-notes" placeholder="Additional notes"></textarea>
|
||||||
|
|
||||||
|
<div class="popup-buttons">
|
||||||
|
<button class="save-btn" id="save-edit-two">Save</button>
|
||||||
|
<button class="cancel-btn" id="cancel-edit-two">Cancel</button>
|
||||||
|
<button class="help-btn">Help</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
let currentTableId = null; // To track which table is being edited
|
let currentTableId = null;
|
||||||
let currentModelName = null; // To track which model is being used
|
let currentModelName = null;
|
||||||
|
|
||||||
// Open Add Popup for Table 2
|
// Open Add Popup for Table 2
|
||||||
$('#add-row-two').on('click', function () {
|
$('#add-row-two').on('click', function () {
|
||||||
currentTableId = 'table-two';
|
currentTableId = 'table-two';
|
||||||
currentModelName = 'SecondTableEntry'; // Model name for Table 2
|
currentModelName = 'SecondTableEntry';
|
||||||
$('#add-popup-two').fadeIn();
|
$('#add-popup-two').fadeIn();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close Popups
|
// Close Popups
|
||||||
$('.close-btn').on('click', function () {
|
$('.close-btn, .cancel-btn').on('click', function () {
|
||||||
$('.popup').fadeOut();
|
$('.popup').fadeOut();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save Add Entry
|
// Save Add Entry
|
||||||
$('#save-add-two').on('click', function () {
|
$('#save-add-two').on('click', function() {
|
||||||
let client_id = $('#add-client-id').val();
|
let formData = {
|
||||||
let date = $('#add-date').val();
|
'client_id': $('#add-client-id').val(),
|
||||||
let warm = $('#add-warm').is(':checked') ? 1 : 0;
|
'date': $('#add-date').val(),
|
||||||
let lhe_anlieferung = $('#add-lhe-anlieferung').val();
|
'is_warm': $('#add-is-warm').is(':checked'),
|
||||||
let lhe_ausgabe = $('#add-lhe-ausgabe').val();
|
'lhe_delivery': $('#add-lhe-delivery').val(),
|
||||||
let comment = $('#add-comment').val();
|
'lhe_output': $('#add-lhe-output').val(),
|
||||||
|
'notes': $('#add-notes').val(),
|
||||||
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate LHe Output is a number
|
||||||
|
if (isNaN(parseFloat(formData.lhe_output))) {
|
||||||
|
alert('LHe Output must be a valid number');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/add-entry/SecondTableEntry/',
|
url: '/add-entry/SecondTableEntry/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: formData,
|
||||||
'client_id': client_id,
|
success: function(response) {
|
||||||
'date': date,
|
// Clear the form
|
||||||
'warm': warm,
|
$('#add-popup-two').find('input, textarea, select').val('');
|
||||||
'lhe_anlieferung': lhe_anlieferung,
|
$('#add-is-warm').prop('checked', false);
|
||||||
'lhe_ausgabe': lhe_ausgabe,
|
|
||||||
'comment': comment,
|
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
|
||||||
},
|
|
||||||
success: function (response) {
|
|
||||||
let rowCount = $('tbody tr').length + 1;
|
|
||||||
let newRow = `
|
|
||||||
<tr data-id="${response.id}">
|
|
||||||
<td>${rowCount}</td>
|
|
||||||
<td>${response.id}</td>
|
|
||||||
<td>${response.name}</td>
|
|
||||||
<td>${response.warm}</td>
|
|
||||||
<td>${response.lhe_anlieferung}</td>
|
|
||||||
<td>${response.lhe_ausgabe}</td>
|
|
||||||
<td>${response.date}</td>
|
|
||||||
<td class="actions">
|
|
||||||
<button class="edit-btn-two">Edit</button>
|
|
||||||
<button class="delete-btn-two">Delete</button>
|
|
||||||
</td>
|
|
||||||
</tr>`;
|
|
||||||
$('tbody').append(newRow);
|
|
||||||
$('#add-popup-two').fadeOut();
|
$('#add-popup-two').fadeOut();
|
||||||
|
|
||||||
|
// Reload the table data
|
||||||
|
loadTableData();
|
||||||
},
|
},
|
||||||
error: function (xhr) {
|
error: function(xhr) {
|
||||||
alert('Failed to add entry: ' + xhr.responseText);
|
alert('Error: ' + xhr.responseJSON?.message || 'Failed to add entry');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add this new function to load table data
|
||||||
|
function loadTableData() {
|
||||||
|
$.ajax({
|
||||||
|
url: window.location.href,
|
||||||
|
method: 'GET',
|
||||||
|
success: function(data) {
|
||||||
|
// Parse the HTML response to extract the table body
|
||||||
|
let newBody = $(data).find('#table-two tbody').html();
|
||||||
|
$('#table-two tbody').html(newBody);
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
alert('Failed to refresh table data');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Open Edit Popup
|
// Open Edit Popup
|
||||||
$(document).on('click', '.edit-btn-two', function () {
|
$(document).on('click', '.edit-btn-two', function () {
|
||||||
let row = $(this).closest('tr');
|
let row = $(this).closest('tr');
|
||||||
currentTableId = row.closest('table').attr('id'); // Set current table ID
|
currentTableId = row.closest('table').attr('id');
|
||||||
currentModelName = 'SecondTableEntry'; // Set model name
|
currentModelName = 'SecondTableEntry';
|
||||||
|
|
||||||
|
// Get data from the row
|
||||||
|
let is_warm = row.find('td:eq(4)').text().trim() === 'Yes';
|
||||||
|
|
||||||
$('#edit-id').val(row.data('id'));
|
$('#edit-id').val(row.data('id'));
|
||||||
$('#edit-client-id').val(row.find('td:eq(2)').text()); // Name is now in column 2
|
$('#edit-client-id').val(row.find('td:eq(2)').text().trim());
|
||||||
$('#edit-age').val(row.find('td:eq(3)').text()); // Age is now in column 3
|
$('#edit-date').val(row.find('td:eq(3)').text().trim());
|
||||||
$('#edit-email').val(row.find('td:eq(4)').text()); // Email is now in column 4
|
$('#edit-is-warm').prop('checked', is_warm);
|
||||||
|
$('#edit-lhe-delivery').val(row.find('td:eq(5)').text().trim());
|
||||||
|
$('#edit-lhe-output').val(row.find('td:eq(6)').text().trim());
|
||||||
|
$('#edit-notes').val(row.find('td:eq(7)').text().trim());
|
||||||
|
|
||||||
$('#edit-popup-two').fadeIn();
|
$('#edit-popup-two').fadeIn();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -287,8 +389,11 @@ $('#save-add-two').on('click', function () {
|
|||||||
$('#save-edit-two').on('click', function () {
|
$('#save-edit-two').on('click', function () {
|
||||||
let id = $('#edit-id').val();
|
let id = $('#edit-id').val();
|
||||||
let client_id = $('#edit-client-id').val();
|
let client_id = $('#edit-client-id').val();
|
||||||
let age = $('#edit-age').val();
|
let date = $('#edit-date').val();
|
||||||
let email = $('#edit-email').val();
|
let is_warm = $('#edit-is-warm').is(':checked');
|
||||||
|
let lhe_delivery = $('#edit-lhe-delivery').val();
|
||||||
|
let lhe_output = $('#edit-lhe-output').val();
|
||||||
|
let notes = $('#edit-notes').val();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/update-entry/${currentModelName}/`,
|
url: `/update-entry/${currentModelName}/`,
|
||||||
@@ -296,23 +401,30 @@ $('#save-add-two').on('click', function () {
|
|||||||
data: {
|
data: {
|
||||||
'id': id,
|
'id': id,
|
||||||
'client_id': client_id,
|
'client_id': client_id,
|
||||||
'age': age,
|
'date': date,
|
||||||
'email': email,
|
'is_warm': is_warm,
|
||||||
|
'lhe_delivery': lhe_delivery,
|
||||||
|
'lhe_output': lhe_output,
|
||||||
|
'notes': notes,
|
||||||
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
'csrfmiddlewaretoken': '{{ csrf_token }}'
|
||||||
},
|
},
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
let row = $(`tr[data-id="${response.id}"]`);
|
let row = $(`tr[data-id="${response.id}"]`);
|
||||||
row.find('td:eq(2)').text(response.name);
|
row.find('td:eq(2)').text(response.client_name);
|
||||||
row.find('td:eq(3)').text(response.age);
|
row.find('td:eq(3)').text(response.date);
|
||||||
row.find('td:eq(4)').text(response.email);
|
row.find('td:eq(4)').text(response.is_warm ? 'Yes' : 'No');
|
||||||
|
row.find('td:eq(5)').text(response.lhe_delivery);
|
||||||
|
row.find('td:eq(6)').text(response.lhe_output);
|
||||||
|
row.find('td:eq(7)').text(response.notes);
|
||||||
$('#edit-popup-two').fadeOut();
|
$('#edit-popup-two').fadeOut();
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to update entry: ' + response.message);
|
alert('Update failed: ' + (response.message || 'Please try again later'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function (xhr, status, error) {
|
||||||
alert('Failed to update entry. Please try again.');
|
alert('Update failed: ' + (xhr.responseJSON?.message || 'Please try again later'));
|
||||||
|
console.error('Error:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -321,8 +433,8 @@ $('#save-add-two').on('click', function () {
|
|||||||
$(document).on('click', '.delete-btn-two', function () {
|
$(document).on('click', '.delete-btn-two', function () {
|
||||||
let row = $(this).closest('tr');
|
let row = $(this).closest('tr');
|
||||||
let id = row.data('id');
|
let id = row.data('id');
|
||||||
currentTableId = row.closest('table').attr('id'); // Set current table ID
|
currentTableId = row.closest('table').attr('id');
|
||||||
currentModelName = 'SecondTableEntry'; // Set model name
|
currentModelName = 'SecondTableEntry';
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to delete this entry?')) return;
|
if (!confirm('Are you sure you want to delete this entry?')) return;
|
||||||
|
|
||||||
@@ -337,11 +449,12 @@ $('#save-add-two').on('click', function () {
|
|||||||
if (response.status === 'success') {
|
if (response.status === 'success') {
|
||||||
row.fadeOut(300, function () { $(this).remove(); });
|
row.fadeOut(300, function () { $(this).remove(); });
|
||||||
} else {
|
} else {
|
||||||
alert('Failed to delete entry: ' + response.message);
|
alert('Delete failed: ' + response.message);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function (xhr, status, error) {
|
||||||
alert('Failed to delete entry. Please try again.');
|
alert('Delete failed: ' + (xhr.responseJSON?.message || 'Please try again later'));
|
||||||
|
console.error('Error:', error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
201
sheets/views.py
201
sheets/views.py
@@ -1,20 +1,51 @@
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
|
from django.db.models import Q
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from datetime import date
|
from datetime import date, datetime
|
||||||
from .models import Client
|
from django.utils import timezone
|
||||||
|
from .models import Client, SecondTableEntry
|
||||||
|
from django.db.models import Sum
|
||||||
|
|
||||||
|
|
||||||
# Clients Page (Main)
|
# Clients Page (Main)
|
||||||
def clients_list(request):
|
def clients_list(request):
|
||||||
clients = Client.objects.all().order_by('id')
|
# Annual summary data
|
||||||
return render(request, 'clients_table.html', {'clients': clients})
|
current_year = int(request.GET.get('year', datetime.now().year))
|
||||||
|
clients = Client.objects.all()
|
||||||
|
|
||||||
|
monthly_data = []
|
||||||
|
for client in clients:
|
||||||
|
monthly_totals = []
|
||||||
|
for month in range(1, 13):
|
||||||
|
total = SecondTableEntry.objects.filter(
|
||||||
|
client=client,
|
||||||
|
date__year=current_year,
|
||||||
|
date__month=month
|
||||||
|
).aggregate(total=Sum('lhe_output'))['total'] or 0
|
||||||
|
monthly_totals.append(total)
|
||||||
|
|
||||||
|
monthly_data.append({
|
||||||
|
'client': client,
|
||||||
|
'monthly_totals': monthly_totals,
|
||||||
|
'year_total': sum(monthly_totals)
|
||||||
|
})
|
||||||
|
|
||||||
|
available_years = SecondTableEntry.objects.dates('date', 'year').distinct()
|
||||||
|
|
||||||
|
return render(request, 'clients_table.html', {
|
||||||
|
'monthly_data': monthly_data,
|
||||||
|
'current_year': current_year,
|
||||||
|
'available_years': [y.year for y in available_years],
|
||||||
|
'months': ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
|
||||||
|
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||||
|
})
|
||||||
|
|
||||||
# Table One View (ExcelEntry)
|
# Table One View (ExcelEntry)
|
||||||
def table_one_view(request):
|
def table_one_view(request):
|
||||||
ExcelEntry = apps.get_model('sheets', 'ExcelEntry')
|
ExcelEntry = apps.get_model('sheets', 'ExcelEntry')
|
||||||
entries_table1 = ExcelEntry.objects.all()
|
entries_table1 = ExcelEntry.objects.all().select_related('client')
|
||||||
clients = Client.objects.all()
|
clients = Client.objects.all()
|
||||||
return render(request, 'table_one.html', {
|
return render(request, 'table_one.html', {
|
||||||
'entries_table1': entries_table1,
|
'entries_table1': entries_table1,
|
||||||
@@ -24,14 +55,24 @@ def table_one_view(request):
|
|||||||
|
|
||||||
# Table Two View (SecondTableEntry)
|
# Table Two View (SecondTableEntry)
|
||||||
def table_two_view(request):
|
def table_two_view(request):
|
||||||
|
try:
|
||||||
SecondTableEntry = apps.get_model('sheets', 'SecondTableEntry')
|
SecondTableEntry = apps.get_model('sheets', 'SecondTableEntry')
|
||||||
entries_table2 = SecondTableEntry.objects.all()
|
entries = SecondTableEntry.objects.all().order_by('-date')
|
||||||
clients = Client.objects.all()
|
clients = Client.objects.all()
|
||||||
|
|
||||||
return render(request, 'table_two.html', {
|
return render(request, 'table_two.html', {
|
||||||
'entries_table2': entries_table2,
|
'entries_table2': entries,
|
||||||
'clients': clients,
|
'clients': clients,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return render(request, 'table_two.html', {
|
||||||
|
'error_message': f"Failed to load data: {str(e)}",
|
||||||
|
'entries_table2': [],
|
||||||
|
'clients': Client.objects.all()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Add Entry (Generic)
|
# Add Entry (Generic)
|
||||||
def add_entry(request, model_name):
|
def add_entry(request, model_name):
|
||||||
@@ -39,42 +80,74 @@ def add_entry(request, model_name):
|
|||||||
try:
|
try:
|
||||||
model = apps.get_model('sheets', model_name)
|
model = apps.get_model('sheets', model_name)
|
||||||
|
|
||||||
if model_name.lower() == 'client':
|
common_data = {
|
||||||
name = request.POST.get('name', 'New Name')
|
'client': Client.objects.get(id=request.POST.get('client_id')),
|
||||||
address = request.POST.get('address', '')
|
'date': request.POST.get('date'),
|
||||||
entry = model.objects.create(name=name, address=address)
|
'notes': request.POST.get('notes', '')
|
||||||
return JsonResponse({
|
}
|
||||||
'id': entry.id,
|
|
||||||
'name': entry.name,
|
|
||||||
'address': entry.address,
|
|
||||||
})
|
|
||||||
|
|
||||||
client_id = request.POST.get('client_id')
|
|
||||||
client = Client.objects.get(id=client_id)
|
|
||||||
age = int(request.POST.get('age', 0))
|
|
||||||
email = request.POST.get('email', 'example@email.com')
|
|
||||||
|
|
||||||
|
if model_name == 'SecondTableEntry':
|
||||||
|
# Handle Helium Output (Table Two)
|
||||||
|
lhe_output = request.POST.get('lhe_output')
|
||||||
entry = model.objects.create(
|
entry = model.objects.create(
|
||||||
client=client,
|
**common_data,
|
||||||
age=age,
|
is_warm=request.POST.get('is_warm') == 'true',
|
||||||
email=email,
|
lhe_delivery=request.POST.get('lhe_delivery', ''),
|
||||||
date_joined=date.today()
|
lhe_output=Decimal(lhe_output) if lhe_output else None
|
||||||
)
|
)
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
|
'status': 'success',
|
||||||
'id': entry.id,
|
'id': entry.id,
|
||||||
'client_name': client.name,
|
'client_name': entry.client.name,
|
||||||
'age': entry.age,
|
'date': entry.date.strftime('%Y-%m-%d') if entry.date else '',
|
||||||
'email': entry.email,
|
'is_warm': entry.is_warm,
|
||||||
'date_joined': entry.date_joined.strftime('%Y-%m-%d'),
|
'lhe_delivery': entry.lhe_delivery,
|
||||||
|
'lhe_output': str(entry.lhe_output) if entry.lhe_output else '',
|
||||||
|
'notes': entry.notes
|
||||||
})
|
})
|
||||||
|
|
||||||
|
elif model_name == 'ExcelEntry':
|
||||||
|
# Parse the date string into a date object
|
||||||
|
date_str = request.POST.get('date')
|
||||||
|
try:
|
||||||
|
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else None
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
date_obj = None
|
||||||
|
|
||||||
|
# Create the entry
|
||||||
|
entry = model.objects.create(
|
||||||
|
client=Client.objects.get(id=request.POST.get('client_id')),
|
||||||
|
date=date_obj,
|
||||||
|
pressure=Decimal(request.POST.get('pressure', 0)),
|
||||||
|
purity=Decimal(request.POST.get('purity', 0)),
|
||||||
|
notes=request.POST.get('notes', '')
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prepare the response
|
||||||
|
response_data = {
|
||||||
|
'status': 'success',
|
||||||
|
'id': entry.id,
|
||||||
|
'client_name': entry.client.name,
|
||||||
|
'pressure': str(entry.pressure),
|
||||||
|
'purity': str(entry.purity),
|
||||||
|
'notes': entry.notes
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only add date if it exists
|
||||||
|
if entry.date:
|
||||||
|
response_data['date'] = entry.date.strftime('%Y-%m-%d')
|
||||||
|
else:
|
||||||
|
response_data['date'] = None
|
||||||
|
|
||||||
|
return JsonResponse(response_data)
|
||||||
|
|
||||||
|
# Keep your existing SecondTableEntry code here...
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
|
return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
|
||||||
|
|
||||||
return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400)
|
return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400)
|
||||||
|
|
||||||
|
|
||||||
# Update Entry (Generic)
|
# Update Entry (Generic)
|
||||||
def update_entry(request, model_name):
|
def update_entry(request, model_name):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@@ -83,44 +156,60 @@ def update_entry(request, model_name):
|
|||||||
entry_id = int(request.POST.get('id'))
|
entry_id = int(request.POST.get('id'))
|
||||||
entry = model.objects.get(id=entry_id)
|
entry = model.objects.get(id=entry_id)
|
||||||
|
|
||||||
if model_name.lower() == 'client':
|
# Common updates for both models
|
||||||
entry.name = request.POST.get('name')
|
entry.client = Client.objects.get(id=request.POST.get('client_id'))
|
||||||
entry.address = request.POST.get('address', '')
|
entry.date = request.POST.get('date')
|
||||||
entry.save()
|
entry.notes = request.POST.get('notes', '')
|
||||||
return JsonResponse({
|
|
||||||
'status': 'success',
|
|
||||||
'id': entry.id,
|
|
||||||
'name': entry.name,
|
|
||||||
'address': entry.address,
|
|
||||||
})
|
|
||||||
|
|
||||||
client_id = request.POST.get('client_id')
|
if model_name == 'SecondTableEntry':
|
||||||
client = Client.objects.get(id=client_id)
|
# Handle Helium Output (Table Two)
|
||||||
age = int(request.POST.get('age'))
|
lhe_output = request.POST.get('lhe_output')
|
||||||
email = request.POST.get('email')
|
entry.is_warm = request.POST.get('is_warm') == 'true'
|
||||||
|
entry.lhe_delivery = request.POST.get('lhe_delivery', '')
|
||||||
entry.client = client
|
entry.lhe_output = Decimal(lhe_output) if lhe_output else None
|
||||||
entry.age = age
|
|
||||||
entry.email = email
|
|
||||||
entry.save()
|
entry.save()
|
||||||
|
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'id': entry.id,
|
'id': entry.id,
|
||||||
'name': client.name,
|
'client_name': entry.client.name,
|
||||||
'age': entry.age,
|
'date': entry.date.strftime('%Y-%m-%d') if entry.date else '',
|
||||||
'email': entry.email,
|
'is_warm': entry.is_warm,
|
||||||
'date_joined': entry.date_joined.strftime('%Y-%m-%d'),
|
'lhe_delivery': entry.lhe_delivery,
|
||||||
|
'lhe_output': str(entry.lhe_output) if entry.lhe_output else '',
|
||||||
|
'notes': entry.notes
|
||||||
})
|
})
|
||||||
|
|
||||||
|
elif model_name == 'ExcelEntry':
|
||||||
|
# Handle Helium Input (Table One)
|
||||||
|
date_str = request.POST.get('date')
|
||||||
|
try:
|
||||||
|
date_obj = datetime.strptime(date_str, '%Y-%m-%d').date() if date_str else None
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
date_obj = None
|
||||||
|
|
||||||
|
entry.client = Client.objects.get(id=request.POST.get('client_id'))
|
||||||
|
entry.date = date_obj
|
||||||
|
entry.pressure = Decimal(request.POST.get('pressure', 0))
|
||||||
|
entry.purity = Decimal(request.POST.get('purity', 0))
|
||||||
|
entry.notes = request.POST.get('notes', '')
|
||||||
|
entry.save()
|
||||||
|
|
||||||
|
return JsonResponse({
|
||||||
|
'status': 'success',
|
||||||
|
'id': entry.id,
|
||||||
|
'client_name': entry.client.name,
|
||||||
|
'pressure': str(entry.pressure),
|
||||||
|
'purity': str(entry.purity),
|
||||||
|
'date': entry.date.strftime('%Y-%m-%d') if entry.date else '',
|
||||||
|
'notes': entry.notes
|
||||||
|
})
|
||||||
except model.DoesNotExist:
|
except model.DoesNotExist:
|
||||||
return JsonResponse({'status': 'error', 'message': 'Entry not found'}, status=404)
|
return JsonResponse({'status': 'error', 'message': 'Entry not found'}, status=404)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
|
return JsonResponse({'status': 'error', 'message': str(e)}, status=400)
|
||||||
|
|
||||||
return JsonResponse({'status': 'error', 'message': 'Invalid request'}, status=400)
|
return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=400)
|
||||||
|
|
||||||
|
|
||||||
# Delete Entry (Generic)
|
# Delete Entry (Generic)
|
||||||
def delete_entry(request, model_name):
|
def delete_entry(request, model_name):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
Reference in New Issue
Block a user