Compare commits
3 Commits
7ad09e21b7
...
polymorphi
| Author | SHA1 | Date | |
|---|---|---|---|
| 95370ed0dc | |||
| bb634d28ed | |||
| cbdf49adfd |
@@ -10,7 +10,7 @@ from typing import List
|
|||||||
|
|
||||||
from ..models.weekpref import WeekPreference
|
from ..models.weekpref import WeekPreference
|
||||||
from ..models.missions import Training
|
from ..models.missions import Training
|
||||||
from ..models.hourbuildings import HourBuilding, HourBuildingLegFlight, HourBuildingLegStop
|
from ..models.hourbuildings import HourBuilding, HourBuildingLegFlight, HourBuildingLegStop, HourBuildingLegBase
|
||||||
|
|
||||||
|
|
||||||
def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) -> HttpResponse:
|
def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) -> HttpResponse:
|
||||||
@@ -41,7 +41,7 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
|
|
||||||
# Header titles
|
# Header titles
|
||||||
days = [f"{datetime.strptime(f"{year} {week} {x}", "%G %V %u").strftime("%A")} {datetime.strptime(f"{year} {week} {x}", "%G %V %u").day}" for x in range(1,8)]
|
days = [f"{datetime.strptime(f"{year} {week} {x}", "%G %V %u").strftime("%A")} {datetime.strptime(f"{year} {week} {x}", "%G %V %u").day}" for x in range(1,8)]
|
||||||
headers = ["Week", "Student", "Course", *days, "Cell.", "Mail", "Notes"]
|
headers = ["Week", "Student", "Course", *days, "Notes", "Cell.", "Mail"]
|
||||||
|
|
||||||
# Header fields positions
|
# Header fields positions
|
||||||
week_index: int = headers.index("Week") + 1
|
week_index: int = headers.index("Week") + 1
|
||||||
@@ -59,7 +59,12 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
|
|
||||||
# Cell styles
|
# Cell styles
|
||||||
border_thick: Side = Side(style='thick', color='000000')
|
border_thick: Side = Side(style='thick', color='000000')
|
||||||
|
border_thin: Side = Side(style='thin', color='000000', border_style='dashed')
|
||||||
border_bottom: Border = Border(bottom=border_thick)
|
border_bottom: Border = Border(bottom=border_thick)
|
||||||
|
border_bottom_thin: Border = Border(bottom=border_thin)
|
||||||
|
border_left: Border = Border(left=border_thick)
|
||||||
|
border_right: Border = Border(right=border_thick)
|
||||||
|
border_right_thin: Border = Border(right=border_thin)
|
||||||
border_all: Border = Border(bottom=border_thick, top=border_thick, left=border_thick, right=None)
|
border_all: Border = Border(bottom=border_thick, top=border_thick, left=border_thick, right=None)
|
||||||
|
|
||||||
# Scrittura header
|
# Scrittura header
|
||||||
@@ -102,15 +107,14 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
mission_name if t.sunday else ""
|
mission_name if t.sunday else ""
|
||||||
]
|
]
|
||||||
mission_notes = t.notes if t.notes else "--"
|
mission_notes = t.notes if t.notes else "--"
|
||||||
mission_data.append([str(q.week), *student_data, *mission_days, student_phone, student_email, mission_notes])
|
mission_data.append([str(q.week), *student_data, *mission_days, mission_notes, student_phone, student_email, ])
|
||||||
|
|
||||||
# Fill HourBuilding rows
|
# Fill HourBuilding rows
|
||||||
hb_name: str
|
hb_name: str
|
||||||
hb_days: List[str]
|
hb_days: List[str]
|
||||||
hb_notes: str
|
|
||||||
hb_data: List[List[str]] = []
|
hb_data: List[List[str]] = []
|
||||||
for h in HourBuilding.objects.filter(weekpref = q.id):
|
for h in HourBuilding.objects.filter(weekpref = q.id):
|
||||||
hb_name = f"HB-{h.aircraft}\nVedi Note ->"
|
hb_name = f"HB - {h.aircraft}\nVedi Note ->"
|
||||||
hb_days = [
|
hb_days = [
|
||||||
hb_name if h.monday else "",
|
hb_name if h.monday else "",
|
||||||
hb_name if h.tuesday else "",
|
hb_name if h.tuesday else "",
|
||||||
@@ -120,53 +124,71 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
hb_name if h.saturday else "",
|
hb_name if h.saturday else "",
|
||||||
hb_name if h.sunday else ""
|
hb_name if h.sunday else ""
|
||||||
]
|
]
|
||||||
hb_notes = f"{h.notes}\n----\n" if h.notes else ""
|
hb_notes: List[str] = [f"{h.notes}", "---"] if h.notes else []
|
||||||
hb_legs = HourBuildingLegFlight.objects.filter(hb_id = h.id)
|
hb_legs_all = HourBuildingLegBase.objects.filter(hb_id = h.id)
|
||||||
#for hh in hb_legs:
|
for hh in hb_legs_all:
|
||||||
# hb_notes += f"{hh.departure} -> {hh.destination} [{hh.time}]\n" if not hh.stop else f"STOP at {hh.departure} [{hh.time}]\n"
|
time_str: str = ':'.join(str(hh.time).split(':')[:2]) # keep only hours and minutes
|
||||||
hb_notes.strip('\n')
|
if isinstance(hh, HourBuildingLegFlight):
|
||||||
hb_data.append([str(q.week), *student_data, *hb_days, str(q.student.phone), q.student.email, hb_notes])
|
hb_notes.append(f"{hh.departure} -> {hh.destination} [{time_str}]{f' / PAX: {hh.pax.capitalize()}' if hh.pax else ''}")
|
||||||
|
elif isinstance(hh, HourBuildingLegStop):
|
||||||
|
hb_notes.append(f"STOP [{time_str}] {"Refuel" if hh.refuel else ""}" )
|
||||||
|
hb_data.append([str(q.week), *student_data, *hb_days, "\n".join(hb_notes), str(q.student.phone), q.student.email])
|
||||||
|
|
||||||
# Build rows for table
|
# Build rows for table
|
||||||
all_data: List[List[str]] = mission_data + hb_data
|
all_data: List[List[str]] = mission_data + hb_data
|
||||||
student_start: int = row + row_offset
|
student_start: int = row + row_offset
|
||||||
for r in all_data:
|
for row_content in all_data:
|
||||||
for j, c in enumerate(r, start=1):
|
for c, cell_content in enumerate(row_content, start=1):
|
||||||
cell = ws.cell(row = row + row_offset, column = j, value = c)
|
cell = ws.cell(row = row + row_offset, column = c, value = cell_content)
|
||||||
cell.alignment = center
|
cell.alignment = center
|
||||||
# Format Student Name
|
# Format Student Name
|
||||||
if j == student_index:
|
if c == student_index:
|
||||||
cell.font = bold_black
|
cell.font = bold_black
|
||||||
# Format Course Column
|
# Format Course Column with color
|
||||||
if j == course_index and q.student.course:
|
elif c == course_index and q.student.course:
|
||||||
cell.font = bold_black
|
cell.font = bold_black
|
||||||
cell.fill = PatternFill("solid", fgColor=str(q.student.course.color).lstrip('#').lower())
|
cell.fill = PatternFill("solid", fgColor=str(q.student.course.color).lstrip('#').lower())
|
||||||
|
# Add internal borders between mix cells and notes
|
||||||
prev_cell_val: str = r[0]
|
elif c > course_index and c <= note_index:
|
||||||
|
cell.border = border_bottom_thin + border_right_thin
|
||||||
|
# Fill mix cells if the cell is not empty
|
||||||
|
if c > course_index and c < note_index:
|
||||||
|
if len(cell_content):
|
||||||
|
cell.fill = PatternFill('solid', fgColor="f0f0f0")
|
||||||
|
|
||||||
|
prev_cell_val: str = row_content[0]
|
||||||
merge_start: bool = False
|
merge_start: bool = False
|
||||||
merge_col_start: int = 1
|
merge_col_start: int = 1
|
||||||
for c, v in enumerate(r, start=1):
|
for c, cell_content in enumerate(row_content, start=1):
|
||||||
# Merge cells in the row
|
# Merge cells in the row
|
||||||
if v == prev_cell_val and not merge_start:
|
if cell_content == prev_cell_val and not merge_start:
|
||||||
merge_start = True
|
merge_start = True
|
||||||
merge_col_start = c-1 # start merge from previous column
|
merge_col_start = c-1 # start merge from previous column
|
||||||
elif v != prev_cell_val and merge_start:
|
elif cell_content != prev_cell_val and merge_start:
|
||||||
merge_start = False
|
merge_start = False
|
||||||
ws.merge_cells(start_row=row+row_offset,
|
ws.merge_cells(start_row=row+row_offset,
|
||||||
end_row=row+row_offset,
|
end_row=row+row_offset,
|
||||||
start_column=max(merge_col_start,1),
|
start_column=max(merge_col_start,1),
|
||||||
end_column=max(c-1,1)) # end merge to previous column
|
end_column=max(c-1,1)) # end merge to previous column
|
||||||
prev_cell_val = v
|
prev_cell_val = cell_content
|
||||||
|
|
||||||
# Incement row counter
|
# Incement row counter
|
||||||
row_offset += 1
|
row_offset += 1
|
||||||
|
|
||||||
# End week preferences for this student
|
# End week preferences for this student
|
||||||
student_end: int = row + row_offset -1
|
student_end: int = row + row_offset - 1
|
||||||
|
|
||||||
|
# Add thick border to the last cell row of this student
|
||||||
|
for c in range(course_index, mail_index + 1):
|
||||||
|
ws.cell(row=student_end, column=c).border = Border(bottom=border_thick, right=border_thin)
|
||||||
|
# And for last column also a vertical border all student high
|
||||||
|
if c == mail_index:
|
||||||
|
for row_content in range(student_start, student_end + 1):
|
||||||
|
ws.cell(row=row_content, column=c).border += border_right
|
||||||
|
|
||||||
# Merge Week, thick border
|
# Merge Week, thick border
|
||||||
# ws.cell(row=student_start, column=week_index).border = border_all
|
ws.cell(row=student_start, column=week_index).border = border_all
|
||||||
# ws.merge_cells(start_row=student_start, end_row=student_end, start_column=week_index, end_column=week_index)
|
ws.merge_cells(start_row=student_start, end_row=student_end, start_column=week_index, end_column=week_index)
|
||||||
# Merge Name, thick border
|
# Merge Name, thick border
|
||||||
ws.cell(row=student_start, column=student_index).border = border_all
|
ws.cell(row=student_start, column=student_index).border = border_all
|
||||||
ws.merge_cells(start_row=student_start, end_row=student_end, start_column=student_index, end_column=student_index)
|
ws.merge_cells(start_row=student_start, end_row=student_end, start_column=student_index, end_column=student_index)
|
||||||
@@ -177,13 +199,15 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
# Merge Mail
|
# Merge Mail
|
||||||
ws.merge_cells(start_row=student_start, end_row=student_end, start_column=mail_index, end_column=mail_index)
|
ws.merge_cells(start_row=student_start, end_row=student_end, start_column=mail_index, end_column=mail_index)
|
||||||
|
|
||||||
# Add thick border to the last cell row of this student
|
|
||||||
for i in range(course_index, len(all_data[0])+1):
|
|
||||||
ws.cell(row=student_end, column=i).border = border_bottom
|
|
||||||
|
|
||||||
# Keep the largest column
|
# Keep the largest column
|
||||||
|
max_len: List[int] = []
|
||||||
for column_cells in ws.columns:
|
for column_cells in ws.columns:
|
||||||
length: int = max(len(str(cell.value)) for cell in column_cells)
|
for cell in column_cells:
|
||||||
|
cell_lines = str(cell.value).splitlines()
|
||||||
|
if len(cell_lines) == 0:
|
||||||
|
continue
|
||||||
|
max_len.append(max([len(ll) for ll in cell_lines]))
|
||||||
|
length: int = max(max_len)
|
||||||
col_letter: str = "A"
|
col_letter: str = "A"
|
||||||
if column_cells[0].column:
|
if column_cells[0].column:
|
||||||
col_letter = get_column_letter(column_cells[0].column)
|
col_letter = get_column_letter(column_cells[0].column)
|
||||||
@@ -191,8 +215,7 @@ def export_selected(request: HttpRequest, queryset: QuerySet[WeekPreference]) ->
|
|||||||
|
|
||||||
### End of Student Loop ###
|
### End of Student Loop ###
|
||||||
|
|
||||||
|
|
||||||
# Save document in HttpResponse
|
# Save document in HttpResponse
|
||||||
wb.save(response)
|
wb.save(response)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
from polymorphic.models import PolymorphicModel
|
from polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
@@ -78,8 +77,17 @@ class HourBuildingLegBase(PolymorphicModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
time = models.DurationField(
|
time = models.DurationField(
|
||||||
null=False
|
null=False,
|
||||||
|
blank=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Change displayed name in the inline form
|
||||||
|
class Meta(PolymorphicModel.Meta):
|
||||||
|
verbose_name = "Flight Leg or Stop"
|
||||||
|
verbose_name_plural = "Flight Legs or Stops"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"Hour Building Leg"
|
||||||
|
|
||||||
class HourBuildingLegFlight(HourBuildingLegBase):
|
class HourBuildingLegFlight(HourBuildingLegBase):
|
||||||
departure = models.CharField(
|
departure = models.CharField(
|
||||||
@@ -102,18 +110,18 @@ class HourBuildingLegFlight(HourBuildingLegBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Change displayed name in the inline form
|
# Change displayed name in the inline form
|
||||||
class Meta(PolymorphicModel.Meta):
|
class Meta(HourBuildingLegBase.Meta):
|
||||||
verbose_name = "Flight leg"
|
verbose_name = "Flight leg"
|
||||||
verbose_name_plural = "Flight legs"
|
verbose_name_plural = "Flight legs"
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.departure = self.departure.upper().strip()
|
||||||
|
self.destination = self.destination.upper().strip()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.departure} -> {self.destination}"
|
return f"{self.departure} -> {self.destination}"
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
self.departure = self.departure.capitalize().strip()
|
|
||||||
self.destination = self.destination.capitalize().strip()
|
|
||||||
super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
class HourBuildingLegStop(HourBuildingLegBase):
|
class HourBuildingLegStop(HourBuildingLegBase):
|
||||||
|
|
||||||
refuel = models.BooleanField(
|
refuel = models.BooleanField(
|
||||||
@@ -121,7 +129,7 @@ class HourBuildingLegStop(HourBuildingLegBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Change displayed name in the inline form
|
# Change displayed name in the inline form
|
||||||
class Meta(PolymorphicModel.Meta):
|
class Meta(HourBuildingLegBase.Meta):
|
||||||
verbose_name = "Stop"
|
verbose_name = "Stop"
|
||||||
verbose_name_plural = "Stops"
|
verbose_name_plural = "Stops"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user