You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.0 KiB
174 lines
5.0 KiB
""" Views for the create overview part """ |
|
|
|
from tempfile import NamedTemporaryFile |
|
|
|
from pyramid.view import view_config |
|
from pyramid.httpexceptions import HTTPFound |
|
from pyramid_mailer.message import Message, Attachment |
|
|
|
from . import XLSX_CONTENT_TYPE, Root |
|
from ..budget import parse_budget_file |
|
from ..superx import parse_exported_file |
|
from ..helpers import find_recipients, find_budget_file, get_sheet_of_file |
|
from ..overview import create_overview # noqa: F401 |
|
from ..exceptions import BudgetParserError, SuperXParserError # noqa: F401 |
|
|
|
MAIL_MESSAGE_BODY = """Hallo an Alle, |
|
|
|
anbei ist eine aktuelle Übersicht unserer Verbrauchsmittel-Budgets. |
|
|
|
Frohes Bestellen! |
|
|
|
-- |
|
Dies ist eine automatisch generierte Email, |
|
bei Fragen bitte an Holgi wenden |
|
|
|
""" |
|
|
|
|
|
def _map_from_form_data(request, prefix): |
|
if not prefix.endswith("-"): |
|
prefix = f"{prefix}-" |
|
result = {} |
|
for key, value in request.POST.items(): |
|
if key.startswith(prefix): |
|
row_str = key.split("-")[-1] |
|
row = int(row_str) |
|
try: |
|
value = float(value) |
|
except ValueError: |
|
value = 0 |
|
result[row] = value |
|
return result |
|
|
|
|
|
@view_config( |
|
context=Root, |
|
request_method="GET", |
|
renderer="superx_budget:pyramid/templates/start.jinja2", |
|
permission="view", |
|
) |
|
def index(context, request): |
|
return {} |
|
|
|
|
|
@view_config( |
|
context=Root, |
|
request_method="POST", |
|
renderer="superx_budget:pyramid/templates/overview.jinja2", |
|
permission="view", |
|
) |
|
def superx_upload(context, request): |
|
upload = request.POST.get("superx") |
|
|
|
if upload == b"" or not upload.filename.endswith(".xlsx"): |
|
request.session.flash("No Excel file uploaded.", "error") |
|
return HTTPFound("/") |
|
|
|
try: |
|
superx_export = parse_exported_file(upload.file) |
|
except SuperXParserError: |
|
request.session.flash( |
|
"File does not appear to be the required SuperX export.", "error" |
|
) |
|
return HTTPFound("/") |
|
|
|
budget_file = find_budget_file( |
|
request.budgets_dir, superx_export.account_year |
|
) |
|
if budget_file is None: |
|
request.session.flash( |
|
f"No budget file for year {superx_export.account_year} found.", |
|
"error", |
|
) |
|
return HTTPFound("/") |
|
|
|
try: |
|
budget_data = parse_budget_file(budget_file) |
|
except BudgetParserError: |
|
request.session.flash( |
|
"Budget File does not appear to be in the required format.", |
|
"error", |
|
) |
|
return HTTPFound("/") |
|
|
|
overview_map = create_overview(budget_data, superx_export) |
|
overview = sorted(overview_map.values(), key=lambda i: i.row) |
|
|
|
if any(not (item.found) for item in overview): |
|
request.session.flash( |
|
( |
|
"Some projects in the budget template were not in the SuperX " |
|
"export. Please adjust their expenses manually." |
|
), |
|
"info", |
|
) |
|
|
|
recipients = find_recipients(request.budgets_dir) |
|
|
|
return { |
|
"account_year": superx_export.account_year, |
|
"export_date": superx_export.export_date.strftime("%Y-%m-%d"), |
|
"overview": overview, |
|
"template": budget_file.name, |
|
"recipients": recipients, |
|
} |
|
|
|
|
|
@view_config( |
|
context=Root, |
|
name="send", |
|
request_method="POST", |
|
renderer="superx_budget:pyramid/templates/sent.jinja2", |
|
permission="view", |
|
) |
|
def send_overview(context, request): |
|
export_date = request.POST.get("export_date").strip() |
|
tmp_recipients = request.POST.get("recipients").strip() |
|
recipients = tmp_recipients.splitlines() |
|
budget_template = request.POST.get("template") |
|
budget_file = request.budgets_dir / budget_template |
|
|
|
budgets = _map_from_form_data(request, "budget-") |
|
expenses = _map_from_form_data(request, "expense-") |
|
available = {k: (v - expenses[k]) for k, v in budgets.items()} |
|
|
|
# sanity check |
|
if ( |
|
not export_date |
|
or not recipients |
|
or not expenses |
|
or not available |
|
or not budget_file.is_file() |
|
): |
|
request.session.flash( |
|
f"There was an error with your submisssion, please try again.", |
|
"error", |
|
) |
|
return HTTPFound("/") |
|
|
|
sheet = get_sheet_of_file(budget_file) |
|
for row, value in expenses.items(): |
|
cell = f"F{row}" |
|
sheet[cell] = value |
|
for row, value in available.items(): |
|
cell = f"G{row}" |
|
sheet[cell] = value |
|
|
|
budget_year = budget_file.stem.split("-")[-1] |
|
message = Message( |
|
subject=f"Budget Übersicht {budget_year}, Stand {export_date}", |
|
sender="cpiserver@imtek.uni-freiburg.de", |
|
recipients=recipients, |
|
body=MAIL_MESSAGE_BODY, |
|
) |
|
|
|
xls_name = f"{export_date}-Budget-Overview-{budget_year}.xlsx" |
|
with NamedTemporaryFile() as tmp: |
|
sheet._parent.save(tmp.name) |
|
tmp.seek(0) |
|
attachment = Attachment(xls_name, XLSX_CONTENT_TYPE, tmp) |
|
message.attach(attachment) |
|
request.mailer.send_immediately(message, fail_silently=False) |
|
|
|
return {"recipients": recipients, "xls_name": xls_name}
|
|
|