diff --git a/db.sqlite3 b/db.sqlite3
index 35a321a..3567da4 100644
Binary files a/db.sqlite3 and b/db.sqlite3 differ
diff --git a/sheets/services/halfyear_calc.py b/sheets/services/halfyear_calc.py
index 705809f..e3ba478 100644
--- a/sheets/services/halfyear_calc.py
+++ b/sheets/services/halfyear_calc.py
@@ -13,8 +13,37 @@ from django.db.models import Sum
from django.db.models.functions import Coalesce
from django.db.models import DecimalField, Value
HALFYEAR_CLIENTS = ["AG Vogel", "AG Halfm", "IKP"]
-TR_RUECKF_FLUESSIG_ROW = 2 # confirmed by your March value 172.840560
+TR_RUECKF_FLUESSIG_ROW = 2
TR_BESTAND_KANNEN_ROW = 5
+GASBESTAND_ROW_INDEX = 9
+GASBESTAND_COL_NM3 = 3
+
+# In top_left / top_right, "Bestand in Kannen-1 (Lit. L-He)" is row_index 5
+BESTAND_KANNEN_ROW_INDEX = 5
+HALFYEAR_RIGHT_CLIENTS = [
+ "Dr. Fohrer",
+ "AG Buntk.",
+ "AG Alff",
+ "AG Gutfl.",
+ "M3 Thiele",
+ "M3 Buntkowsky",
+ "M3 Gutfleisch",
+ "Merck"
+]
+BOTTOM1_COL_VOLUME = 0
+BOTTOM1_COL_BAR = 1
+BOTTOM1_COL_KORR = 2
+BOTTOM1_COL_NM3 = 3
+BOTTOM1_COL_LHE = 4
+BOTTOM2_ROW_ANLAGE = 0
+BOTTOM2_COL_G39 = 0 # "Gefäss 2,5" (cell id shows column_index=0)
+BOTTOM2_COL_I39 = 1 # "Gefäss 1,0" (cell id shows column_index=1)
+BOTTOM2_ROW_INPUTS = {
+ "g39": (0, 0), # row_index=0, column_index=0 (your G39)
+ "i39": (0, 1), # row_index=0, column_index=1 (your I39)
+}
+FACTOR_NM3_TO_LHE = Decimal("0.75")
+RIGHT_CLIENT_INDEX = {name: idx for idx, name in enumerate(HALFYEAR_RIGHT_CLIENTS)}
def get_top_right_value(sheet, client_name: str, row_index: int) -> Decimal:
"""
Read a numeric value from the top_right table of a MonthlySheet for
@@ -128,34 +157,7 @@ def pick_sheet_by_gasbestand(window, sheets_by_ym, prev_sheet):
return sheet
return prev_sheet
# NEW: clients for the top-right half-year table
-GASBESTAND_ROW_INDEX = 9 # <-- adjust if your bottom_1 has a different row index
-GASBESTAND_COL_NM3 = 3 # <-- adjust to the column index for Nm³ in bottom_1
-# In top_left / top_right, "Bestand in Kannen-1 (Lit. L-He)" is row_index 5
-BESTAND_KANNEN_ROW_INDEX = 5
-HALFYEAR_RIGHT_CLIENTS = [
- "Dr. Fohrer",
- "AG Buntk.",
- "AG Alff",
- "AG Gutfl.",
- "M3 Thiele",
- "M3 Buntkowsky",
- "M3 Gutfleisch",
-]
-BOTTOM1_COL_VOLUME = 0
-BOTTOM1_COL_BAR = 1
-BOTTOM1_COL_KORR = 2
-BOTTOM1_COL_NM3 = 3
-BOTTOM1_COL_LHE = 4
-BOTTOM2_ROW_ANLAGE = 0
-BOTTOM2_COL_G39 = 0 # "Gefäss 2,5" (cell id shows column_index=0)
-BOTTOM2_COL_I39 = 1 # "Gefäss 1,0" (cell id shows column_index=1)
-BOTTOM2_ROW_INPUTS = {
- "g39": (0, 0), # row_index=0, column_index=0 (your G39)
- "i39": (0, 1), # row_index=0, column_index=1 (your I39)
-}
-FACTOR_NM3_TO_LHE = Decimal("0.75")
-RIGHT_CLIENT_INDEX = {name: idx for idx, name in enumerate(HALFYEAR_RIGHT_CLIENTS)}
def build_halfyear_window(interval_year: int, start_month: int):
"""
@@ -171,7 +173,53 @@ def build_halfyear_window(interval_year: int, start_month: int):
return window
# Import ONLY models + pure helpers here
from sheets.models import MonthlySheet, Cell, Client, SecondTableEntry, BetriebskostenSummary
+def sum_right_row_without_duplicates(label: str, clients_right: list[str], values: list):
+ """
+ For specific rows, clients are logically merged, so we must only count one copy.
+ """
+ # rows where the PAIRS are merged:
+ # - Bestand in Kannen-1
+ # - Summe Bestand
+ # - Best. in Kannen Vormonat
+ merged_pair_labels = {
+ "Bestand in Kannen-1 (Lit. L-He)",
+ "Summe Bestand (Lit. L-He)",
+ "Best. in Kannen Vormonat (Lit. L-He)",
+ "Verbraucherverluste (Liter L-He)",
+ # ✅ Sammel is also duplicated for the merged PAIRS (Fohrer+Buntk, Alff+Gutfl)
+ "Sammelrückführungen (Lit. L-He)",
+ "Sammelrückführung (Lit. L-He)", # safety (singular)
+}
+
+ merged_m3_labels = {
+ # ✅ Sammel is duplicated for the merged M3 triple
+ "Sammelrückführungen (Lit. L-He)",
+ "Sammelrückführung (Lit. L-He)", # safety (singular)
+ }
+
+ skip_indices = set()
+
+ # skip second column of each merged PAIR
+ if label in merged_pair_labels:
+ for right_name in ("AG Buntk.", "AG Gutfl."):
+ if right_name in clients_right:
+ skip_indices.add(clients_right.index(right_name))
+
+ # skip 2nd+3rd of the merged TRIPLE
+ if label in merged_m3_labels:
+ for name in ("M3 Buntkowsky", "M3 Gutfleisch"):
+ if name in clients_right:
+ skip_indices.add(clients_right.index(name))
+
+ total = Decimal("0")
+ for i, v in enumerate(values):
+ if i in skip_indices:
+ continue
+ if v in (None, ""):
+ continue
+ total += Decimal(str(v).replace(",", "."))
+ return total
def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[str, Any]:
"""
Returns a context dict with the SAME keys your current halfyear_balance.html expects.
@@ -227,8 +275,8 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
# ----------------------------
chosen_sheet_bottom1 = pick_sheet_by_gasbestand(window, sheets_by_ym, prev_sheet)
- # IMPORTANT: define which bottom_1 row_index corresponds to Excel rows 27..35
- # If your bottom_1 starts at Excel row 27 => row_index 0 == Excel 27
+ # define which bottom_1 row_index corresponds to Excel rows 27..35
+ # If bottom_1 starts at Excel row 27 => row_index 0 == Excel 27
# then row_index = excel_row - 27
BOTTOM1_EXCEL_START_ROW = 27
@@ -671,6 +719,20 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
right_data["M3 Gutfleisch"]['sammel'] = group3_total
def safe_div(a: Decimal, b: Decimal) -> Decimal:
return (a / b) if b != 0 else Decimal("0")
+
+ # Merck: Sammelrückführung = total helium input (ExcelEntry.lhe_ges) over the 6-month window
+ merck_sammel_total = Decimal("0")
+ for (y, m) in window:
+ qs = ExcelEntry.objects.filter(
+ client__name="Merck",
+ date__year=y,
+ date__month=m,
+ ).aggregate(
+ total=Coalesce(Sum("lhe_ges"), Value(0, output_field=DecimalField()))
+ )
+ merck_sammel_total += Decimal(str(qs["total"]))
+
+ right_data["Merck"]["sammel"] = merck_sammel_total
# --- Rückführung flüssig (Lit. L-He) for Halbjahres-Bilanz top-right ---
# Uses your exact formulas.
@@ -741,6 +803,9 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
right_data["M3 Thiele"]["bestand_kannen"] = pick_bestand_top_right("M3 Thiele")
right_data["M3 Buntkowsky"]["bestand_kannen"] = pick_bestand_top_right("M3 Buntkowsky")
right_data["M3 Gutfleisch"]["bestand_kannen"] = pick_bestand_top_right("M3 Gutfleisch")
+ # Merck should stay empty in Bestand in Kannen-1
+ right_data["Merck"]["bestand_kannen"] = None
+ right_data["Merck"]["best_kannen_vormonat"] = None
# Summe Bestand = same as previous row
for cname in RIGHT_CLIENTS:
@@ -807,9 +872,23 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
b11 = right_data[cname]['summe_bestand']
# Excel: P13+P12-P11 etc.
right_data[cname]['rueckf_soll'] = b13 + b12 - b11
-
+ # Merck: only selected rows should have values in Top Right Halbjahresbilanz
+ right_data["Merck"]["stand_prev_share"] = None
+ right_data["Merck"]["rueckf_fluessig"] = None
+ right_data["Merck"]["sonder"] = None
+ right_data["Merck"]["bestand_kannen"] = None
+ right_data["Merck"]["summe_bestand"] = None
+ right_data["Merck"]["best_kannen_vormonat"] = None
+ right_data["Merck"]["rueckf_soll"] = None
+ right_data["Merck"]["verluste"] = None
+ right_data["Merck"]["fuellungen_warm"] = None
+ right_data["Merck"]["kaltgas_rueckgabe"] = None
# --- Verluste (Soll-Rückf.) (Lit. L-He) = B14 - B6 - B7 ---
for cname in RIGHT_CLIENTS:
+ if cname == "Merck":
+ right_data[cname]['verluste'] = None
+ continue
+
b14 = right_data[cname]['rueckf_soll']
b6 = right_data[cname]['rueckf_fluessig']
b7 = right_data[cname]['sonder']
@@ -829,17 +908,22 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
b13 = right_data[cname]['bezug']
right_data[cname]['kaltgas_rueckgabe'] = b13 * factor
- # --- Verbraucherverluste (Liter L-He) = Verluste - Kaltgas Rückgabe ---
+ # --- Verbraucherverluste (Liter L-He) ---
for cname in RIGHT_CLIENTS:
- b15 = right_data[cname]['verluste']
- b17 = right_data[cname]['kaltgas_rueckgabe']
- right_data[cname]['verbraucherverluste'] = b15 - b17
+ if cname == "Merck":
+ bezug = right_data[cname].get("bezug") or Decimal("0")
+ sammel = right_data[cname].get("sammel") or Decimal("0")
+ right_data[cname]["verbraucherverluste"] = bezug - sammel
+ else:
+ b15 = right_data[cname]['verluste']
+ b17 = right_data[cname]['kaltgas_rueckgabe']
+ right_data[cname]['verbraucherverluste'] = b15 - b17
# --- % = Verbraucherverluste / Bezug ---
for cname in RIGHT_CLIENTS:
- bezug = right_data[cname]['bezug']
- verb = right_data[cname]['verbraucherverluste']
- if bezug != 0:
+ bezug = right_data[cname].get('bezug') or Decimal("0")
+ verb = right_data[cname].get('verbraucherverluste')
+ if bezug != 0 and verb is not None:
right_data[cname]['percent'] = verb / bezug
else:
right_data[cname]['percent'] = None
@@ -910,50 +994,78 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
def safe_pct(verb, bez):
return (verb / bez) if bez != 0 else None
+ def sum_right_key(label_for_merge: str, clients: list[str], key: str) -> Decimal:
+ vals = [right_data[c].get(key) for c in clients]
+ return sum_right_row_without_duplicates(label_for_merge, clients, vals)
rows_sum = []
def d(x):
return x if isinstance(x, Decimal) else Decimal("0")
- for label, key in SUM_TABLE_ROWS:
+ for row_index, (label, key) in enumerate(SUM_TABLE_ROWS):
if key == "factor_row":
lichtwiese = chemie = mawi = m3 = total = Decimal("0.06")
elif key == "percent":
- # Right totals
- rw_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_ALL)
- rw_verb = sum(d(right_data[c].get("verbraucherverluste")) for c in RIGHT_ALL)
+ # We want % = Verbraucherverluste / Bezug (for each group)
+
+ # LEFT totals (no merge on left)
+ left_bez = sum(d(client_data_left[c].get("bezug")) for c in LEFT_ALL)
+ left_verb = sum(d(client_data_left[c].get("verbraucherverluste")) for c in LEFT_ALL)
+
+ # RIGHT totals (must skip merged duplicates!)
+ rw_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_ALL)
+
+ rw_verb = sum_right_key("Verbraucherverluste (Liter L-He)", RIGHT_ALL, "verbraucherverluste")
+
lichtwiese = safe_pct(rw_verb, rw_bez)
- # Chemie
- ch_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_GROUPS["chemie"])
- ch_verb = sum(d(right_data[c].get("verbraucherverluste")) for c in RIGHT_GROUPS["chemie"])
+ # Chemie group (Fohrer+Buntk)
+ ch_clients = RIGHT_GROUPS["chemie"]
+ ch_bez = sum_right_key("Bezug (Liter L-He)", ch_clients, "bezug")
+ ch_verb = sum_right_key("Verbraucherverluste (Liter L-He)", ch_clients, "verbraucherverluste")
chemie = safe_pct(ch_verb, ch_bez)
- # MaWi
- mw_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_GROUPS["mawi"])
- mw_verb = sum(d(right_data[c].get("verbraucherverluste")) for c in RIGHT_GROUPS["mawi"])
+ # MaWi group (Alff+Gutfl)
+ mw_clients = RIGHT_GROUPS["mawi"]
+ mw_bez = sum_right_key("Bezug (Liter L-He)", mw_clients, "bezug")
+ mw_verb = sum_right_key("Verbraucherverluste (Liter L-He)", mw_clients, "verbraucherverluste")
mawi = safe_pct(mw_verb, mw_bez)
- # M3
- m3_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_GROUPS["m3"])
- m3_verb = sum(d(right_data[c].get("verbraucherverluste")) for c in RIGHT_GROUPS["m3"])
+ # M3 group (triple)
+ m3_clients = RIGHT_GROUPS["m3"]
+ m3_bez = sum_right_key("Bezug (Liter L-He)", m3_clients, "bezug")
+ m3_verb = sum_right_key("Verbraucherverluste (Liter L-He)", m3_clients, "verbraucherverluste")
m3 = safe_pct(m3_verb, m3_bez)
- # Σ column = (left verb + right verb) / (left bez + right bez)
- left_bez = sum(d(client_data_left[c].get("bezug")) for c in LEFT_ALL)
- left_verb = sum(d(client_data_left[c].get("verbraucherverluste")) for c in LEFT_ALL)
+ # Overall Σ (%)
total = safe_pct(left_verb + rw_verb, left_bez + rw_bez)
+
else:
- # normal rows = sums
- lichtwiese = sum(d(right_data[c].get(key)) for c in RIGHT_ALL)
- chemie = sum(d(right_data[c].get(key)) for c in RIGHT_GROUPS["chemie"])
- mawi = sum(d(right_data[c].get(key)) for c in RIGHT_GROUPS["mawi"])
- m3 = sum(d(right_data[c].get(key)) for c in RIGHT_GROUPS["m3"])
+ # normal rows = sums (BUT skip duplicates for merged logical cells)
+ rw_values = [right_data[c].get(key) for c in RIGHT_ALL]
+ lichtwiese = sum_right_row_without_duplicates(label, RIGHT_ALL, rw_values)
+
+ ch_clients = RIGHT_GROUPS["chemie"]
+ ch_values = [right_data[c].get(key) for c in ch_clients]
+ chemie = sum_right_row_without_duplicates(label, ch_clients, ch_values)
+
+ mw_clients = RIGHT_GROUPS["mawi"]
+ mw_values = [right_data[c].get(key) for c in mw_clients]
+ mawi = sum_right_row_without_duplicates(label, mw_clients, mw_values)
+
+ m3_clients = RIGHT_GROUPS["m3"]
+ m3_values = [right_data[c].get(key) for c in m3_clients]
+ m3 = sum_right_row_without_duplicates(label, m3_clients, m3_values)
left_total = sum(d(client_data_left[c].get(key)) for c in LEFT_ALL)
- total = left_total + lichtwiese
+ # Merck should count ONLY in the overall total, not in Lichtwiese
+ merck_val = d(right_data["Merck"].get(key))
+
+ total = left_total + lichtwiese + merck_val
+
+ # ✅ THIS MUST BE OUTSIDE THE IF/ELIF/ELSE
rows_sum.append({
"row_index": row_index,
"label": label,
@@ -964,6 +1076,7 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
"m3": m3,
"is_percent": (key == "percent"),
})
+
def find_sum_row(rows, label_startswith: str):
for r in rows:
if str(r.get("label", "")).strip().startswith(label_startswith):
@@ -999,8 +1112,8 @@ def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[st
bottom2["k44"] = k44
bottom2["j44"] = j44
- def d(x):
- return x if isinstance(x, Decimal) else Decimal("0")
+ def d_or_none(x):
+ return x if isinstance(x, Decimal) else None
# ---- Bottom2: J38/K38 depend on rows_sum (overall summary), so do it HERE ----
k38 = Decimal("0")
diff --git a/sheets/templates/clients_table.html b/sheets/templates/clients_table.html
index 28078dc..4af89dc 100644
--- a/sheets/templates/clients_table.html
+++ b/sheets/templates/clients_table.html
@@ -3,10 +3,10 @@
{% block content %}
diff --git a/sheets/templates/monthly_sheet.html b/sheets/templates/monthly_sheet.html
index 35f73ce..cab20fd 100644
--- a/sheets/templates/monthly_sheet.html
+++ b/sheets/templates/monthly_sheet.html
@@ -28,6 +28,7 @@
+
@@ -320,7 +332,9 @@
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% else %}
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
|
{% endif %}
@@ -339,7 +355,9 @@
data-table="bottom_1"
data-row="{{ forloop.parentloop.counter0 }}"
data-col="{{ forloop.counter0 }}">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endif %}
{% endif %}
@@ -379,7 +397,9 @@
data-col="0"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endwith %}
Gefäss 1,0 |
@@ -392,7 +412,9 @@
data-col="1"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endwith %}
|
@@ -454,7 +476,9 @@
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
|
{% endwith %}
@@ -490,7 +514,9 @@
data-col="1"
data-cell-id="{{ cell.id|default:'' }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endwith %}
@@ -503,7 +529,9 @@
data-col="2"
data-cell-id="{{ cell.id|default:'' }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endwith %}
@@ -546,7 +574,9 @@
data-col="2"
data-client-id="{{ cell.client.id|default:'' }}"
contenteditable="true">
- {{ cell.value|default:"" }}
+ {% if cell.value is not None %}
+ {{ cell.value|floatformat:2 }}
+ {% endif %}
{% endwith %}
@@ -800,6 +830,12 @@ $(document).ready(function() {
const v = parseFloat(t);
return isNaN(v) ? null : v;
}
+ function formatNumber(value) {
+ if (value === null || value === undefined || value === '') return '';
+ const num = parseFloat(String(value).replace(',', '.'));
+ if (isNaN(num)) return value;
+ return num.toFixed(2);
+}
// Recalculate Sum cell (last column) for a given row
function recalcRowSum($row) {
@@ -837,7 +873,7 @@ $(document).ready(function() {
});
if (hasValue) {
- $row.find('.sum-cell').text(total);
+ $row.find('.sum-cell').text(total.toFixed(2));
} else {
$row.find('.sum-cell').text('');
}
@@ -1243,8 +1279,9 @@ $(document).ready(function() {
const targetCell = $('[data-cell-id="' + cellData.id + '"]');
if (!targetCell.length) return;
- targetCell.text(cellData.value || '');
- targetCell.data('original-value', cellData.value || '');
+ const formattedValue = formatNumber(cellData.value);
+ targetCell.text(formattedValue);
+ targetCell.data('original-value', formattedValue);
if (cellData.is_calculated) {
targetCell.addClass('calculated-cell');
diff --git a/sheets/urls.py b/sheets/urls.py
index f046683..390b17b 100644
--- a/sheets/urls.py
+++ b/sheets/urls.py
@@ -1,5 +1,5 @@
from django.urls import path
-from .views import DebugTopRightView
+
from .views import SaveCellsView , SaveMonthSummaryView, halfyear_settings,MonthlySheetView, monthly_sheet_root,set_halfyear_interval,AbrechnungView, SaveAbrechnungCellsView
from . import views
from .views import RechnungView
@@ -19,9 +19,9 @@ urlpatterns = [
path("abrechnung/autosave/", SaveAbrechnungCellsView.as_view(), name="abrechnung_autosave"),
path("abrechnung/save/", SaveAbrechnungCellsView.as_view(), name="save_abrechnung"),
path('check-sheets/', views.CheckSheetView.as_view(), name='check_sheets'),
- path('quick-debug/', views.QuickDebugView.as_view(), name='quick_debug'),
+
path('test-formula/', views.TestFormulaView.as_view(), name='test_formula'),
- path('simple-debug/', views.SimpleDebugView.as_view(), name='simple_debug'),
+
path("rechnung/", RechnungView.as_view(), name="rechnung"),
path('sheet/', monthly_sheet_root, name='monthly_sheet_root'),
path('set-halfyear-interval/', set_halfyear_interval, name='set_halfyear_interval'),
@@ -33,6 +33,5 @@ urlpatterns = [
path("save-cells/", SaveCellsView.as_view(), name="save_cells"), path("save-cells/", SaveCellsView.as_view(), name="save_cells"),path('save-month-summary/', SaveMonthSummaryView.as_view(), name='save_month_summary'),
path('save-month-summary/', SaveMonthSummaryView.as_view(), name='save_month_summary'),
path('calculate/', views.CalculateView.as_view(), name='calculate'),
- path('debug-calculation/', views.DebugCalculationView.as_view(), name='debug_calculation'),
- path('debug-top-right/', DebugTopRightView.as_view(), name='debug_top_right'),
+
]
\ No newline at end of file
diff --git a/sheets/views.py b/sheets/views.py
index c6f8e82..d9d4903 100644
--- a/sheets/views.py
+++ b/sheets/views.py
@@ -59,6 +59,12 @@ CLIENT_GROUPS = {
'M3 Gutfleisch',
],
},
+ 'merck': {
+ 'label': 'Merck',
+ 'names': [
+ 'Merck',
+ ],
+ },
}
# Add this CALCULATION_CONFIG at the top of views.py
@@ -275,12 +281,12 @@ def build_halfyear_window(interval_year: int, start_month: int):
# Halbjahres-Bilanz helpers
# ---------------------------------------------------------------------------
-# You can adjust these indices if needed.
+
# Assuming:
# - bottom_1.table has row "Gasbestand" at some fixed row index,
# and columns: ... Nm³, Lit. LHe
-GASBESTAND_ROW_INDEX = 9 # <-- adjust if your bottom_1 has a different row index
-GASBESTAND_COL_NM3 = 3 # <-- adjust to the column index for Nm³ in bottom_1
+GASBESTAND_ROW_INDEX = 9
+GASBESTAND_COL_NM3 = 3
# In top_left / top_right, "Bestand in Kannen-1 (Lit. L-He)" is row_index 5
BESTAND_KANNEN_ROW_INDEX = 5
@@ -382,6 +388,7 @@ HALFYEAR_RIGHT_CLIENTS = [
"M3 Thiele",
"M3 Buntkowsky",
"M3 Gutfleisch",
+ "Merck",
]
BOTTOM1_COL_VOLUME = 0
BOTTOM1_COL_BAR = 1
@@ -461,6 +468,7 @@ def get_group_clients(group_key):
group = CLIENT_GROUPS.get(group_key)
if not group:
return Client.objects.none()
+
return Client.objects.filter(name__in=group['names'])
def calculate_summation(sheet, table_type, row_index, sum_column_index):
@@ -575,6 +583,7 @@ class MonthlySheetView(TemplateView):
"M3 Thiele", # Column index 4 (P)
"M3 Buntkowsky", # Column index 5 (Q)
"M3 Gutfleisch", # Column index 6 (R)
+ "Merck",
]
# For each client in top-right table
@@ -735,6 +744,7 @@ class MonthlySheetView(TemplateView):
"M3 Thiele",
"M3 Buntkowsky",
"M3 Gutfleisch",
+ "Merck",
]
current_summary = MonthlySummary.objects.filter(sheet=sheet).first()
@@ -765,6 +775,10 @@ class MonthlySheetView(TemplateView):
("Dr. Fohrer", "AG Buntk."),
("AG Alff", "AG Gutfl."),
]
+
+ MERGED_TRIPLES = [
+ ("M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"),
+ ]
rows = []
# Determine row count
@@ -813,13 +827,29 @@ class MonthlySheetView(TemplateView):
has_value = False
merged_second_indices = set()
+
if table_type == 'top_right' and row_idx in MERGED_ROWS:
+
+ # Handle pairs
for left_name, right_name in MERGED_PAIRS:
try:
right_idx = client_names.index(right_name)
merged_second_indices.add(right_idx)
except ValueError:
- # client not in this table; just ignore
+ pass
+
+ # Handle M3 triple group
+ MERGED_TRIPLES = [
+ ("M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"),
+ ]
+
+ for a, b, c in MERGED_TRIPLES:
+ try:
+ b_idx = client_names.index(b)
+ c_idx = client_names.index(c)
+ merged_second_indices.add(b_idx)
+ merged_second_indices.add(c_idx)
+ except ValueError:
pass
for col_idx, cell in enumerate(display_cells):
@@ -1250,100 +1280,8 @@ def get_factor_value(table_type, row_index):
# Save Cells View
# views.py - Updated SaveCellsView
# views.py - Update SaveCellsView class
-def debug_cell_values(self, sheet, client_id):
- """Debug method to check cell values"""
- from .models import Cell
- cells = Cell.objects.filter(
- sheet=sheet,
- table_type='top_left',
- client_id=client_id
- ).order_by('row_index')
-
- debug_info = {}
- for cell in cells:
- debug_info[f"row_{cell.row_index}"] = {
- 'value': str(cell.value) if cell.value else 'None',
- 'ui_row': cell.row_index + 1,
- 'excel_ref': f"B{cell.row_index + 3}"
- }
-
- return debug_info
-class DebugCalculationView(View):
- """Debug view to test calculations directly"""
- def get(self, request):
- sheet_id = request.GET.get('sheet_id', 1)
- client_name = request.GET.get('client', 'AG Vogel')
-
- try:
- sheet = MonthlySheet.objects.get(id=sheet_id)
- client = Client.objects.get(name=client_name)
-
- # Get SaveCellsView instance
- save_view = SaveCellsView()
-
- # Create a dummy cell to trigger calculations
- dummy_cell = Cell.objects.filter(
- sheet=sheet,
- table_type='top_left',
- client=client,
- row_index=0 # B3
- ).first()
-
- if not dummy_cell:
- return JsonResponse({'error': 'No cells found for this client'})
-
- # Trigger calculation
- updated = save_view.calculate_top_left_dependents(sheet, dummy_cell)
-
- # Get updated cell values
- cells = Cell.objects.filter(
- sheet=sheet,
- table_type='top_left',
- client=client
- ).order_by('row_index')
-
- cell_data = []
- for cell in cells:
- cell_data.append({
- 'row_index': cell.row_index,
- 'ui_row': cell.row_index + 1,
- 'excel_ref': f"B{cell.row_index + 3}",
- 'value': str(cell.value) if cell.value else 'None',
- 'description': self.get_row_description(cell.row_index)
- })
-
- return JsonResponse({
- 'sheet': f"{sheet.year}-{sheet.month:02d}",
- 'client': client.name,
- 'cells': cell_data,
- 'updated_count': len(updated),
- 'calculation': 'B5 = IF(B3>0; B3-B4; 0)'
- })
-
- except Exception as e:
- return JsonResponse({'error': str(e)}, status=400)
-
- def get_row_description(self, row_index):
- """Get description for row index"""
- descriptions = {
- 0: "B3: Stand der Gaszähler (Nm³)",
- 1: "B4: Stand der Gaszähler (Vormonat) (Nm³)",
- 2: "B5: Gasrückführung (Nm³)",
- 3: "B6: Rückführung flüssig (Lit. L-He)",
- 4: "B7: Sonderrückführungen (Lit. L-He)",
- 5: "B8: Bestand in Kannen-1 (Lit. L-He)",
- 6: "B9: Summe Bestand (Lit. L-He)",
- 7: "B10: Best. in Kannen Vormonat (Lit. L-He)",
- 8: "B11: Bezug (Liter L-He)",
- 9: "B12: Rückführ. Soll (Lit. L-He)",
- 10: "B13: Verluste (Soll-Rückf.) (Lit. L-He)",
- 11: "B14: Füllungen warm (Lit. L-He)",
- 12: "B15: Kaltgas Rückgabe (Lit. L-He) – Faktor",
- 13: "B16: Faktor",
- 14: "B17: Verbraucherverluste (Liter L-He)",
- 15: "B18: %"
- }
- return descriptions.get(row_index, f"Row {row_index}")
+
+
def recalculate_stand_der_gaszahler(self, sheet):
"""Recalculate Stand der Gaszähler for all client pairs"""
from decimal import Decimal
@@ -1443,82 +1381,7 @@ def recalculate_stand_der_gaszahler(self, sheet):
ag_gutfl_row0.save()
except Exception as e:
print(f"Error recalculating Stand der Gaszähler for AG Alff/AG Gutfl.: {e}")
-# In your SaveCellsView class in views.py
-class DebugTopRightView(View):
- """Debug view to check top_right calculations"""
- def get(self, request):
- sheet_id = request.GET.get('sheet_id', 1)
- client_name = request.GET.get('client', 'Dr. Fohrer')
-
- try:
- sheet = MonthlySheet.objects.get(id=sheet_id)
- client = Client.objects.get(name=client_name)
-
- # Get all cells for this client in top_right
- cells = Cell.objects.filter(
- sheet=sheet,
- table_type='top_right',
- client=client
- ).order_by('row_index')
-
- cell_data = []
- descriptions = {
- 0: "Stand der Gaszähler (Vormonat)",
- 1: "Gasrückführung (Nm³)",
- 2: "Rückführung flüssig",
- 3: "Sonderrückführungen",
- 4: "Sammelrückführungen",
- 5: "Bestand in Kannen-1",
- 6: "Summe Bestand",
- 7: "Best. in Kannen Vormonat",
- 8: "Same as row 9 from prev sheet",
- 9: "Bezug",
- 10: "Rückführ. Soll",
- 11: "Verluste",
- 12: "Füllungen warm",
- 13: "Kaltgas Rückgabe",
- 14: "Faktor 0.06",
- 15: "Verbraucherverluste",
- 16: "%"
- }
-
- for cell in cells:
- cell_data.append({
- 'row_index': cell.row_index,
- 'ui_row': cell.row_index + 1,
- 'description': descriptions.get(cell.row_index, f"Row {cell.row_index}"),
- 'value': str(cell.value) if cell.value else 'Empty',
- 'cell_id': cell.id
- })
-
- # Test calculation
- row3_cell = cells.filter(row_index=3).first()
- row5_cell = cells.filter(row_index=5).first()
- row6_cell = cells.filter(row_index=6).first()
-
- calculation_info = {
- 'row3_value': str(row3_cell.value) if row3_cell and row3_cell.value else '0',
- 'row5_value': str(row5_cell.value) if row5_cell and row5_cell.value else '0',
- 'row6_value': str(row6_cell.value) if row6_cell and row6_cell.value else '0',
- 'expected_sum': '0'
- }
-
- if row3_cell and row5_cell and row6_cell:
- row3_val = Decimal(str(row3_cell.value)) if row3_cell.value else Decimal('0')
- row5_val = Decimal(str(row5_cell.value)) if row5_cell.value else Decimal('0')
- expected = row3_val + row5_val
- calculation_info['expected_sum'] = str(expected)
- calculation_info['is_correct'] = row6_cell.value == expected
-
- return JsonResponse({
- 'sheet': f"{sheet.year}-{sheet.month}",
- 'client': client.name,
- 'cells': cell_data,
- 'calculation': calculation_info
- })
-
- except Exception as e:
- return JsonResponse({'error': str(e)}, status=400)
+
ABRECHNUNG_COL_CLIENTS = {
# first 3 columns
"pkm_vogel": ["AG Vogel"],
@@ -1582,7 +1445,12 @@ class AbrechnungView(TemplateView):
("rechnungsbetrag", "Rechnungsbetrag", "EUR"),
("eff_lhe_preis", "eff. L-He-Preis", "EUR/L"),
]
-
+ SUMMARY_ROWS = {
+ "bezogen_menge",
+ "kaltg_warmfuell",
+ "he_verbrauch",
+ "lhe_verluste",
+ }
# Editable rows = your yellow rows
EDITABLE_ROW_KEYS = {"ghe_bezug", "betrag", "gutschriften"}
@@ -1706,9 +1574,12 @@ class AbrechnungView(TemplateView):
def sum_all_cols(values_dict):
return sum(v for k, v in values_dict.items() if k != "gesamt_summe")
- bezogen["gesamt_summe"] = sum_all_cols(bezogen)
- warmfills["gesamt_summe"] = sum_all_cols(warmfills)
-
+ bezogen["gesamt_summe"] = (
+ d(bezogen.get("chemie")) + d(bezogen.get("mawi")) + d(bezogen.get("physik"))
+ )
+ warmfills["gesamt_summe"] = (
+ d(warmfills.get("chemie")) + d(warmfills.get("mawi")) + d(warmfills.get("physik"))
+ )
# ---- Row: Bezogen. Menge ----
for col_key in bezogen:
computed[("bezogen_menge", col_key)] = bezogen[col_key]
@@ -1765,12 +1636,30 @@ class AbrechnungView(TemplateView):
for col_key in he_verbrauch:
if col_key in first3:
row1_vals[col_key] = instandhaltung * safe_div(he_verbrauch[col_key], physik_hv) / Decimal("3")
+
elif col_key in next3:
row1_vals[col_key] = instandhaltung / Decimal("9")
+
elif col_key in next2:
row1_vals[col_key] = instandhaltung / Decimal("6")
+
+ # ✅ NEW: summary columns
+ elif col_key in ("chemie", "mawi"):
+ row1_vals[col_key] = instandhaltung / Decimal("3")
+
+ elif col_key == "physik":
+ row1_vals[col_key] = (
+ d(row1_vals.get("pkm_vogel")) +
+ d(row1_vals.get("iap_halfmann")) +
+ d(row1_vals.get("ikp"))
+ )
+
elif col_key == "gesamt_summe":
- row1_vals[col_key] = sum(row1_vals.get(k, Decimal("0")) for k in first3)
+ # keep whatever you want here; example: chemie+mawi+physik
+ row1_vals[col_key] = (
+ d(row1_vals.get("chemie")) + d(row1_vals.get("mawi")) + d(row1_vals.get("physik"))
+ )
+
else:
row1_vals[col_key] = Decimal("0")
@@ -1820,23 +1709,21 @@ class AbrechnungView(TemplateView):
elif col_key == "chemie":
v = (
d(verbrauch_right.get("Dr. Fohrer")) +
- d(verbrauch_right.get("AG Buntk.")) +
- d(verbrauch_right.get("M3 Buntkowsky")) +
- d(verbrauch_right.get("M3 Thiele"))
+ d(verbrauch_right.get("AG Buntk."))
)
elif col_key == "mawi":
+ # MaWi = MaWi Gutfl + MaWi Alff (Abrechnung columns)
v = (
- d(verbrauch_right.get("AG Alff")) +
- d(verbrauch_right.get("AG Gutfl.")) +
- d(verbrauch_right.get("M3 Gutfleisch"))
+ d(lhe_verluste.get("AG Gutfl")) +
+ d(lhe_verluste.get("mawi_alff"))
)
elif col_key == "physik":
- v = (
- d(verbrauch_left.get("AG Vogel")) +
- d(verbrauch_left.get("AG Halfm")) +
- d(verbrauch_left.get("IKP"))
+ v = (
+ d(verbrauch_right.get("M3 Thiele")) +
+ d(verbrauch_right.get("M3 Buntkowsky")) +
+ d(verbrauch_right.get("M3 Gutfleisch"))
)
elif col_key == "gesamt_summe":
@@ -1851,14 +1738,41 @@ class AbrechnungView(TemplateView):
# --- Gesamt-summe ---
- lhe_verluste["gesamt_summe"] = sum(v for k, v in lhe_verluste.items())
+ lhe_verluste["gesamt_summe"] = (
+ d(lhe_verluste.get("chemie")) + d(lhe_verluste.get("mawi")) + d(lhe_verluste.get("physik"))
+ )
computed[("lhe_verluste", "gesamt_summe")] = lhe_verluste["gesamt_summe"]
# ---- Row: 3 Umlage Heliumkosten = heliumkosten * (LHe-Verluste col / LHe-Verluste gesamt_summe) ----
- for col_key in lhe_verluste:
- computed[("umlage_heliumkosten_3", col_key)] = heliumkosten * safe_div(lhe_verluste[col_key], lhe_verluste["gesamt_summe"])
+ FIRST8 = [
+ "pkm_vogel",
+ "iap_halfmann",
+ "ikp",
+ "orgchem_thiele",
+ "phychem_m3_buntkow",
+ "orgchem_fohrer",
+ "mawi_m3_gutfl",
+ "mawi_alff",
+ ]
+ den = sum(d(lhe_verluste.get(k)) for k in FIRST8) # denominator = sum of first 8 LHe–Verluste
+
+ # 1) compute first 8 columns
+ for k in FIRST8:
+ computed[("umlage_heliumkosten_3", k)] = heliumkosten * safe_div(d(lhe_verluste.get(k)), den)
+
+ # 2) compute the 3 summary columns from those first 8 (so they stay consistent)
+ # 2) compute the 3 summary columns directly from their LHe–Verluste shares (Excel logic)
+ computed[("umlage_heliumkosten_3", "chemie")] = heliumkosten * safe_div(d(lhe_verluste.get("chemie")), den)
+ computed[("umlage_heliumkosten_3", "mawi")] = heliumkosten * safe_div(d(lhe_verluste.get("mawi")), den)
+ computed[("umlage_heliumkosten_3", "physik")] = heliumkosten * safe_div(d(lhe_verluste.get("physik")), den)
+
+
+ # 3) last column = sum of first 8 columns (your requirement)
+ computed[("umlage_heliumkosten_3", "gesamt_summe")] = sum(
+ d(computed.get(("umlage_heliumkosten_3", k))) for k in FIRST8
+ )
# ---- Row: 4-Kosten He-Gas-Bezug = Umlage Heliumkosten * Bezugskosten-GasHe ----
for col_key, _label in self.COLUMNS:
ghe = d(value_map.get(("ghe_bezug", col_key)))
@@ -1901,7 +1815,17 @@ class AbrechnungView(TemplateView):
elif col_key in ("chemie", "mawi", "physik"):
v = safe_div(he_verbrauch[col_key], sum3) * umlage_personal_total
elif col_key == "gesamt_summe":
- v = sum(d(computed.get(("umlage_personal_5", k))) for k in he_verbrauch if k != "gesamt_summe")
+ # sum of the FIRST 8 columns only (exclude chemie/mawi/physik/gesamt_summe)
+ v = (
+ d(computed.get(("umlage_personal_5", "pkm_vogel"))) +
+ d(computed.get(("umlage_personal_5", "iap_halfmann"))) +
+ d(computed.get(("umlage_personal_5", "ikp"))) +
+ d(computed.get(("umlage_personal_5", "orgchem_thiele"))) +
+ d(computed.get(("umlage_personal_5", "phychem_m3_buntkow"))) +
+ d(computed.get(("umlage_personal_5", "orgchem_fohrer"))) +
+ d(computed.get(("umlage_personal_5", "mawi_m3_gutfl"))) +
+ d(computed.get(("umlage_personal_5", "mawi_alff")))
+ )
else:
v = Decimal("0")
computed[("umlage_personal_5", col_key)] = v
@@ -1932,6 +1856,19 @@ class AbrechnungView(TemplateView):
else:
sonstiges_text[col_key] = "Nachzahlung"
# overwrite display values for non-editable computed rows
+ FIRST4 = {"bezogen_menge", "kaltg_warmfuell", "anzahl_15", "he_verbrauch"}
+ FIRST8 = ["pkm_vogel", "iap_halfmann", "ikp", "orgchem_thiele",
+ "phychem_m3_buntkow", "orgchem_fohrer", "mawi_m3_gutfl", "mawi_alff"]
+
+ for rk, _label, _unit in self.ROWS:
+ if rk in FIRST4:
+ computed[(rk, "gesamt_summe")] = (
+ d(computed.get((rk, "chemie"))) +
+ d(computed.get((rk, "mawi"))) +
+ d(computed.get((rk, "physik")))
+ )
+ else:
+ computed[(rk, "gesamt_summe")] = sum(d(computed.get((rk, ck))) for ck in FIRST8)
non_editable_formula_rows = {
"bezogen_menge",
"kaltg_warmfuell",
@@ -1981,19 +1918,31 @@ class AbrechnungView(TemplateView):
# -------------------------------
GROUP_IJKL = ["orgchem_thiele", "phychem_m3_buntkow", "orgchem_fohrer", "mawi_m3_gutfl", "mawi_alff"]
- GROUP_NOP = GROUP_IJKL + ["chemie", "mawi", "physik"]
+ GROUP_NOP = ["chemie", "mawi", "physik"]
GROUP_STADT = ["pkm_vogel", "iap_halfmann", "ikp"]
+ def nop_cols_for_row(row_key: str):
+ # For gutschriften, NOP should sum the 5 IJKL client columns
+ if row_key == "gutschriften":
+ return GROUP_IJKL
+ # otherwise NOP is the 3 summary columns (Chemie/MaWi/Physik)
+ return GROUP_NOP
def val(row_key, col_key):
- """Get the final numeric value for a cell (computed if available, else stored)."""
- v = value_map.get((row_key, col_key))
- return d(v)
+ """Get the final numeric value for a cell (prefer computed, fallback to stored)."""
+ if (row_key, col_key) in computed:
+ return d(computed.get((row_key, col_key)))
+ return d(value_map.get((row_key, col_key)))
def sum_group(row_key, cols):
return sum(val(row_key, ck) for ck in cols)
right_rows = []
-
+ def nop_cols_for_row(row_key: str):
+ # For gutschriften, NOP should sum the 5 IJKL client columns
+ if row_key == "gutschriften":
+ return GROUP_IJKL
+ # otherwise NOP is the 3 summary columns
+ return GROUP_NOP
# These are your normal rows (same order as UI)
# We will create one summary row per Abrechnung row_key.
for row_key, label, unit in self.ROWS:
@@ -2011,14 +1960,27 @@ class AbrechnungView(TemplateView):
continue
ijkl = sum_group(row_key, GROUP_IJKL)
- nop = sum_group(row_key, GROUP_NOP)
+ if row_key == "umlage_heliumkosten_3":
+ nop = (
+ val(row_key, "chemie") +
+ val(row_key, "mawi") +
+ val(row_key, "physik")
+ )
+ else:
+ nop = sum_group(row_key, nop_cols_for_row(row_key))
stadt = sum_group(row_key, GROUP_STADT)
check = nop + stadt
# Special rule: Rechnungsbetrag row gets +Betrag +Gutschriften (for NOP only)
if row_key == "rechnungsbetrag":
- nop_extra = sum_group("betrag", GROUP_NOP) + sum_group("gutschriften", GROUP_NOP)
- nop = nop + nop_extra
+ # Rechnungsbetrag (NOP) = (Chemie+MaWi+Physik Rechnungsbetrag)
+ # + (Chemie+MaWi+Physik Betrag)
+ # + (IJKL Gutschriften) <-- because you want gutschriften NOP from IJKL
+ nop = (
+ sum_group("rechnungsbetrag", GROUP_NOP)
+ + sum_group("betrag", GROUP_NOP)
+ + sum_group("gutschriften", GROUP_IJKL)
+ )
check = nop + stadt
right_rows.append({
@@ -2180,7 +2142,7 @@ class RechnungView(TemplateView):
bs = BetriebskostenSummary.objects.first()
instandhaltung = d(bs.instandhaltung) if bs else Decimal("0")
- personalkosten = d(bs.personalkosten) if bs else Decimal("0")
+ personalkosten = d(bs.umlage_personal) if bs else Decimal("0")
preis_eur_pro_l = (instandhaltung / interval_total_output_lhe) if interval_total_output_lhe != 0 else Decimal("0")
@@ -2537,6 +2499,7 @@ class SaveCellsView(View):
"M3 Thiele", # P
"M3 Buntkowsky", # Q
"M3 Gutfleisch", # R
+ "Merck"
]
# Define merged pairs
@@ -2553,6 +2516,7 @@ class SaveCellsView(View):
"fohrer_buntk": ["Dr. Fohrer", "AG Buntk."],
"alff_gutfl": ["AG Alff", "AG Gutfl."],
"m3": ["M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"],
+ "merck": ["Merck"],
}
year = sheet.year
@@ -2797,6 +2761,26 @@ class SaveCellsView(View):
else:
prozent = Decimal('0')
set_val(m3_client, 15, prozent, is_calculated=True)
+ # 9. Simple client(s): only Bezug, Sammelrückführungen, Verbraucherverluste = Sammel - Bezug
+ SIMPLE_RIGHT_CLIENTS = ["Merck"] # use the exact database name here
+
+ for client_name in SIMPLE_RIGHT_CLIENTS:
+ # Bezug (row 8)
+ bezug = get_val(client_name, 8)
+
+ # Sammelrückführungen (row 4)
+ sammel = get_val(client_name, 4)
+
+ # Verbraucherverluste (row 14) = Sammelrückführungen - Bezug
+ verbrauch = bezug - sammel
+ set_val(client_name, 14, verbrauch, is_calculated=True)
+
+ # % (row 15) = Verbraucherverluste / Bezug
+ if bezug != 0:
+ prozent = verbrauch / bezug
+ else:
+ prozent = Decimal("0")
+ set_val(client_name, 15, prozent, is_calculated=True)
return updated_cells
@@ -4360,41 +4344,7 @@ class CheckSheetView(View):
})
-class QuickDebugView(View):
- def get(self, request):
- # Get ALL sheets
- sheets = MonthlySheet.objects.all().order_by('year', 'month')
-
- result = {
- 'sheets': []
- }
-
- for sheet in sheets:
- sheet_info = {
- 'id': sheet.id,
- 'display': f"{sheet.year}-{sheet.month:02d}",
- 'url': f"/sheet/{sheet.year}/{sheet.month}/", # CHANGED THIS LINE
- 'sheet_url_pattern': 'sheet/{year}/{month}/', # Add this for clarity
- }
-
- # Count cells with data for first client in top_left table
- first_client = Client.objects.first()
- if first_client:
- test_cells = sheet.cells.filter(
- client=first_client,
- table_type='top_left',
- row_index__in=[8, 9, 10] # Rows 9, 10, 11
- ).order_by('row_index')
-
- cell_values = {}
- for cell in test_cells:
- cell_values[f"row_{cell.row_index}"] = str(cell.value) if cell.value else "Empty"
-
- sheet_info['test_cells'] = cell_values
- else:
- sheet_info['test_cells'] = "No clients"
-
- result['sheets'].append(sheet_info)
+
return JsonResponse(result)
class TestFormulaView(View):
@@ -4417,46 +4367,6 @@ class TestFormulaView(View):
})
-class SimpleDebugView(View):
- """Simplest debug view to check if things are working"""
- def get(self, request):
- sheet_id = request.GET.get('sheet_id', 1)
-
- try:
- sheet = MonthlySheet.objects.get(id=sheet_id)
-
- # Get first client
- client = Client.objects.first()
- if not client:
- return JsonResponse({'error': 'No clients found'})
-
- # Check a few cells
- cells = Cell.objects.filter(
- sheet=sheet,
- client=client,
- table_type='top_left',
- row_index__in=[8, 9, 10]
- ).order_by('row_index')
-
- cell_data = []
- for cell in cells:
- cell_data.append({
- 'row_index': cell.row_index,
- 'ui_row': cell.row_index + 1,
- 'value': str(cell.value) if cell.value is not None else 'Empty',
- 'cell_id': cell.id
- })
-
- return JsonResponse({
- 'sheet': f"{sheet.year}-{sheet.month}",
- 'sheet_id': sheet.id,
- 'client': client.name,
- 'cells': cell_data,
- 'note': 'Row 8 = UI Row 9, Row 9 = UI Row 10, Row 10 = UI Row 11'
- })
-
- except MonthlySheet.DoesNotExist:
- return JsonResponse({'error': f'Sheet with id {sheet_id} not found'})
def halfyear_settings(request):
"""