PD and RC form with activities (#4812)
All checks were successful
continuous-integration/drone/push Build is passing

Co-authored-by: Tobias Diekershoff <tobiasd@fsfe.org>
Co-committed-by: Tobias Diekershoff <tobiasd@fsfe.org>
This commit is contained in:
tobiasd 2025-02-03 07:18:30 +00:00 committed by tobiasd
parent 57c469d0e3
commit c8efa11cce
7 changed files with 162 additions and 108 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ global/data/topbanner/.topbanner.??.xml
fsfe.org/search/index.js
fsfe.org/tags/tagged-*.en.xhtml
fsfe.org/tags/.tags.??.xml
global/data/modules/fsfe-activities-options.en.xml
# Local build stuff
output

View File

@ -22,14 +22,18 @@ require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/SMTP.php';
$html = ''; // create empty variable
$csv = array(array("Employee name", "Date", "Amount (EUR)", "Recipient name", "ER number", "Catchphrase", "Receipt number", "Remarks")); // create array for CSV
$csv = array(array("Employee name", "Date", "Amount (EUR)", "Recipient name", "Activity Tag", "Activity Text", "Category ID", "Category Text", "Description", "Receipt number", "Remarks")); // create array for CSV
$csvfile = tmpfile();
$csvfile_path = stream_get_meta_data($csvfile)['uri'];
$reimb_total = 0; // total reimbursement for early calculation
$who = isset($_POST["who"]) ? $_POST["who"] : false;
$er = isset($_POST["er"]) ? $_POST["er"] : false;
$catch = isset($_POST["catch"]) ? $_POST["catch"] : false;
$activity = isset($_POST["activity"]) ? $_POST["activity"] : false;
$activity_tag = explode(":", $activity)[0];
$activity_text = explode(":", $activity)[1];
$category_id = "6664";
$category_text = "Per diem";
$description = isset($_POST["description"]) ? $_POST["description"] : false;
$extra = isset($_POST["extra"]) ? $_POST["extra"] : false;
$mailopt = isset($_POST["mailopt"]) ? $_POST["mailopt"] : false;
$defaults = isset($_POST["defaults"]) ? $_POST["defaults"] : false;
@ -135,8 +139,11 @@ $html .= "<p>This per diem statement is made by <strong>$who_verbose</strong>.</
<th>Date</th>
<th>Amount</th>
<th>Recipient</th>
<th>ER number</th>
<th>Catchphrase</th>
<th>Activity Tag</th>
<th>Activity Text</th>
<th>Category Id</th>
<th>Category Text</th>
<th>Description</th>
<th>Receipt Name</th>
<th>Remarks</th>
</tr>";
@ -155,7 +162,8 @@ $email->Port = 25;
//$email->Password = 'fsfe_pass';
//$email->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$email->SetFrom($who . "@fsfe.org", $who_verbose);
$email->Subject = "per diem statement by $who_verbose for $catch";
$email->CharSet = "UTF-8";
$email->Subject = "=?UTF-8?B?" . base64_encode("per diem statement by $who_verbose for $activity_text") . "?=";
if ($mailopt === "normal") {
$email->addAddress("finance@lists.fsfe.org");
}
@ -240,15 +248,18 @@ foreach ($use as $d => $day) { // calculate for each day
<tr>
<td>$date[$d]</td>
<td>$reimb_day[$d]</td>
<td>$who_verbose</td>
<td>$activity_tag</td>
<td>$activity_text</td>
<td>$category_id</td>
<td>$category_text</td>
<td>$description</td>
<td></td>
<td>$er</td>
<td>$catch</td>
<td>per diem</td>
<td>$remarks[$d]</td>
</tr>";
// CSV for this receipt
$csv[$key] = array($who_verbose, $date[$d], $reimb_day[$d], "", $er, $catch, "per diem", $remarks[$d]);
$csv[$key] = array($who_verbose, $date[$d], $reimb_day[$d], $who_verbose, $activity_tag, $activity_text, $category_id, $category_text, $description, "", $remarks[$d]);
} // if day is used
} // foreach
@ -257,13 +268,13 @@ foreach ($use as $d => $day) { // calculate for each day
foreach ($csv as $fields) {
fputcsv($csvfile, $fields, ';', '"', '"');
}
$email->addAttachment($csvfile_path, filter_filename("perdiem" ."-". $who ."-". $er ."-". $catch . ".csv"));
$email->addAttachment($csvfile_path, filter_filename("perdiem" ."-". $who ."-". $activity_tag ."-". $description . ".csv"));
// Prepare email body
$email_body = "Hi,
This is a per diem statement by $who_verbose for
$catch (ER: $er),
$activity_tag ($activity_text),
sent via <https://fsfe.org/internal/pd>.
Please find the expenses attached.";
@ -273,7 +284,7 @@ $reimb_total = number_format($reimb_total, 2, ',', '');
// Finalise output table
$html .= "<tr><td><strong>Total:</strong></td><td><strong>$reimb_total $currency</strong></td>";
$html .= "<td colspan='5'></td></tr>";
$html .= "<td colspan='8'></td></tr>";
$html .= "</table>";
if ($extra) {
$html .= "<p>Extra remarks: <br />$extra</p>";

View File

@ -9,7 +9,7 @@ require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/SMTP.php';
$html = ''; // create empty variable
$csv = array(array("Employee name", "Date", "Amount (EUR)", "Recipient name", "ER number", "Catchphrase", "Receipt number", "Remarks")); // create array for CSV
$csv = array(array("Employee name", "Date", "Amount (EUR)", "Recipient name", "Activity Tag", "Activity Text", "Category ID", "Category Text", "Description", "", "Receipt number", "Remarks")); // create array for CSV
$csvfile = tmpfile();
$csvfile_path = stream_get_meta_data($csvfile)['uri'];
@ -22,10 +22,10 @@ $cc_year = isset($_POST["cc_year"]) ? $_POST["cc_year"] : false;
$entry = isset($_POST["entry"]) ? $_POST["entry"] : false; // will become $date in loop
$amount = isset($_POST["amount"]) ? $_POST["amount"] : false;
$recipient = isset($_POST["recipient"]) ? $_POST["recipient"] : false;
$er = isset($_POST["er"]) ? $_POST["er"] : false;
$catch = isset($_POST["catch"]) ? $_POST["catch"] : false;
$activity = isset($_POST["activity"]) ? $_POST["activity"] : false;
$category = isset($_POST["category"]) ? $_POST["category"] : false;
$receipt = isset($_POST["receipt"]) ? $_POST["receipt"] : false;
$remarks = isset($_POST["remarks"]) ? $_POST["remarks"] : false;
$description = isset($_POST["description"]) ? $_POST["description"] : false;
$extra = isset($_POST["extra"]) ? $_POST["extra"] : false;
$mailopt = isset($_POST["mailopt"]) ? $_POST["mailopt"] : false;
@ -123,10 +123,14 @@ $html .= "<p>This <strong>$type_verbose</strong> is made by <strong>$who_verbose
<th>Date</th>
<th>Amount</th>
<th>Recipient</th>
<th>ER number</th>
<th>Catchphrase</th>
<th>Activity Tag</th>
<th>Activity Text</th>
<th>Category ID</th>
<th>Category Text</th>
<th>Description</th>
<th></th>
<th>Receipt Name</th>
<th>Remarks</th>
<th></th>
</tr>";
// Prepare email
@ -143,7 +147,8 @@ $email->Port = 25;
//$email->Password = 'fsfe_pass';
//$email->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$email->SetFrom($who . "@fsfe.org", $who_verbose);
$email->Subject = "$type_verbose for $type_date by $who_verbose";
$email->CharSet = "UTF-8";
$email->Subject = "=?UTF-8?B?" . base64_encode("$type_verbose for $type_date by $who_verbose") . "?=";
if ($mailopt === "normal") {
$email->addAddress("finance@lists.fsfe.org");
}
@ -165,6 +170,10 @@ foreach ($entry as $key => $date) { // run over each row
$receipt_size = $_FILES["receipt"]["size"][$key];
$key1 = $key + 1;
$receipt_no = sprintf('%02d', $key1);
$activity_tag[$key] = explode(":", $activity)[0];
$activity_text[$key] = explode(":", $activity)[1];
$category_id[$key] = explode(":", $category)[0];
$category_text[$key] = explode(":", $category)[1];
// Sanity checks for receipt: upload, size, mime type
if (! $receipt_tmp) {
@ -180,7 +189,7 @@ foreach ($entry as $key => $date) { // run over each row
// Set name and temporary destination for attached receipt
$receipt_ext = pathinfo($receipt_name)['extension'];
$receipt_rename = filter_filename($type_date ."-". $type ."-". $who ."-receipt-". $receipt_no ."-". $er[$key] .".". "$receipt_ext");
$receipt_rename = filter_filename($type_date ."-". $type ."-". $who ."-receipt-". $receipt_no ."-". $activity_tag .".". "$receipt_ext");
$receipt_dest[$key] = "/tmp/" . $receipt_rename;
// Try to move file to temporary destination
@ -193,8 +202,8 @@ foreach ($entry as $key => $date) { // run over each row
}
// Remove "-" when remark empty
if ($remarks[$key] === "-") {
$remarks[$key] = "";
if ($description[$key] === "-") {
$description[$key] = "";
}
// HTML output for this receipt
@ -203,14 +212,19 @@ foreach ($entry as $key => $date) { // run over each row
<td>$date</td>
<td>$amount[$key]</td>
<td>$recipient[$key]</td>
<td>$er[$key]</td>
<td>$catch[$key]</td>
<td>$activity_tag[$key]</td>
<td>$activity_text[$key]</td>
<td>$category_id[$key]</td>
<td>$category_text[$key]</td>
<td>$description[$key]</td>
<td>$receipt_name</td>
<td>$remarks[$key]</td>
<td></td>
<td></td>
</tr>";
// CSV for this receipt
$csv[$receipt_no] = array($who_verbose, $date, $amount[$key], $recipient[$key], $er[$key], $catch[$key], $receipt_no, $remarks[$key]);
$csv[$receipt_no] = array($who_verbose, $date, $amount[$key], $recipient[$key], $activity_tag[$key], $activity_text[$key], $category_id[$key], $category_text[$key], $description[$key], "", $receipt_no, "");
// Add receipt as email attachment
$email->addAttachment($receipt_dest[$key], basename($receipt_dest[$key]));

View File

@ -38,3 +38,18 @@ input[type="file"] {
label {
font-weight: normal;
}
#category {
width: auto !important;
padding: inherit !important;
background: none !important;
margin-top: 0px !important;
}
#content input[type="radio"] {
margin: 0 0 0 -20px;
}
#description-help {
font-size: 0.8em;
color: #616161be;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<html>
<version>1</version>
<version>2</version>
<head>
<title>Per Diem / VKP statement</title>
@ -40,7 +40,7 @@
know whether a certain day counts as half/travel or full day.
</p>
<form action="/cgi-bin/perdiem.php" method="post">
<form action="/cgi-bin/perdiem.php" method="post" enctype="multipart/form-data" accept-charset="utf-8">
<!-- Define default settings and rates. Currently Germany -->
<input type="hidden" name="defaults" value="€/0.2/0.4/0.4" />
@ -48,43 +48,33 @@
<div class="row form-group form-inline">
<label class="col-sm-3">Employee:</label>
<select class="form-control col-sm-9" name="who" size="1" required="required">
<option />
<option value="Alexander Sander|alex.sander">Alexander Sander</option>
<option value="Ana Galan|anaghz">Ana Galán</option>
<option value="Bonnie Mehring|bonnie">Bonnie Mehring</option>
<option value="Carmen Bianca Bakker|carmenbianca">Carmen Bianca Bakker</option>
<option value="Dario Presutti|dario">Dario Presutti</option>
<option value="Erik Albers|eal">Erik Albers</option>
<option value="Erika Pirić|epiric">Erika Pirić</option>
<option value="Florian Snow|floriansnow">Florian Snow</option>
<option value="Francesca Indorato|fi">Francesca Indorato</option>
<option value="Gabriel Ku Wei Bin|gabriel.ku">Gabriel Ku Wei Bin</option>
<option value="Henning Fehr|hf">Henning Fehr</option>
<option value="Johannes Näder|jn">Johannes Näder</option>
<option value="Linus Sehn|linus">Linus Sehn</option>
<option value="Lucas Lasota|lucas.lasota">Lucas Lasota</option>
<option value="Max Mehl|max.mehl">Max Mehl</option>
<option value="Matthias Kirschner|mk">Matthias Kirschner</option>
<option value="Reinhard Müller|reinhard">Reinhard Müller</option>
<option value="Tobias Diekershoff|tobiasd">Tobias Diekershoff</option>
</select>
</div>
<div class="row form-group">
<label class="col-sm-3">ER number for this trip:</label>
<div class="col-sm-4">
<input type="text" name="er" class="form-control" pattern="(^\?$|^er\.[\d]{4}-[\d]{2}-[\d]{2}\.[\d.-]+)" placeholder="er.2020-..." required="required" />
</div>
<div class="col-sm-5 small">
(Enter <strong>?</strong> if you do not have it)
<div class="col-sm-9">
<select class="form-control col-sm-9" name="who" size="1" required="required">
<option />
<module id="fsfe-employee-options" />
</select>
</div>
</div>
<div class="row form-group">
<label class="col-sm-3">Catchphrase of ER:</label>
<div class="col-sm-4">
<input type="text" name="catch" class="form-control" required="required" />
<label class="col-sm-3">Activity:</label>
<div class="col-sm-9">
<select class="form-control col-sm-9" name="activity" id="activity" size="1" required="required">
<option />
<module id="fsfe-activities-options" />
</select>
</div>
</div>
<div class="row form-group">
<label class="col-sm-3" label-for="description">Description (optional):</label>
<div class="col-sm-9">
<input type="text" id="description" name="description" class="form-control" />
</div>
<div id="description-help" class="col-sm-offset-3 col-sm-9">
Leave blank for activities with only one trip (e.g. FOSDEM, SFSCON).
For activities involving more than one trip (e.g. multiple meetings),
please describe the trip in detail.
</div>
</div>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<html>
<version>1</version>
<version>2</version>
<head>
<title>Reimbursement Claim / Credit Card statement</title>
@ -22,32 +22,14 @@
selecting the correct type (Reimbursement Claim or Credit Card).
</p>
<form action="/cgi-bin/reimbursement.php" method="post" enctype="multipart/form-data">
<form id="rcform" action="/cgi-bin/reimbursement.php" method="post" enctype="multipart/form-data" accept-charset="utf-8">
<h2>1. Set general options</h2>
<div class="form-group form-inline">
<label class="col-sm-3">Employee:</label>
<select class="form-control col-sm-9" name="who" size="1" required="required">
<option />
<option value="Alexander Sander|alex.sander">Alexander Sander</option>
<option value="Ana Galan|anaghz">Ana Galán</option>
<option value="Bonnie Mehring|bonnie">Bonnie Mehring</option>
<option value="Carmen Bianca Bakker|carmenbianca">Carmen Bianca Bakker</option>
<option value="Dario Presutti|dario">Dario Presutti</option>
<option value="Erik Albers|eal">Erik Albers</option>
<option value="Erika Pirić|epiric">Erika Pirić</option>
<option value="Florian Snow|floriansnow">Florian Snow</option>
<option value="Francesca Indorato|fi">Francesca Indorato</option>
<option value="Gabriel Ku Wei Bin|gabriel.ku">Gabriel Ku Wei Bin</option>
<option value="Heiki Lõhmus|repentinus">Heiki Lõhmus</option>
<option value="Henning Fehr|hf">Henning Fehr</option>
<option value="Johannes Näder|jn">Johannes Näder</option>
<option value="Linus Sehn|linus">Linus Sehn</option>
<option value="Lucas Lasota|lucas.lasota">Lucas Lasota</option>
<option value="Max Mehl|max.mehl">Max Mehl</option>
<option value="Matthias Kirschner|mk">Matthias Kirschner</option>
<option value="Reinhard Müller|reinhard">Reinhard Müller</option>
<option value="Tobias Diekershoff|tobiasd">Tobias Diekershoff</option>
<module id="fsfe-employee-options" />
</select>
</div>
@ -75,10 +57,9 @@
<option value="12">December</option>
</select>
<select class="form-control" name="rc_year">
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024" selected="selected">2024</option>
<option value="2025">2025</option>
<option value="2024">2024</option>
<option value="2025" selected="selected">2025</option>
</select>
</label>
</div>
@ -88,19 +69,26 @@
<div class="radio form-inline col-sm-offset-3 col-sm-9">
<label>
<input type="radio" name="type" value="cc" required="required" />
Credit Card for quarter
Credit Card for month
<select class="form-control" name="cc_month">
<option />
<option value="Q1">Q1</option>
<option value="Q2">Q2</option>
<option value="Q3">Q3</option>
<option value="Q4">Q4</option>
<option value="01">January</option>
<option value="02">February</option>
<option value="03">March</option>
<option value="04">April</option>
<option value="05">May</option>
<option value="06">June</option>
<option value="07">July</option>
<option value="08">August</option>
<option value="09">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
<select class="form-control" name="cc_year">
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024" selected="selected">2024</option>
<option value="2025">2025</option>
<option value="2024">2024</option>
<option value="2025" selected="selected">2025</option>
</select>
</label>
</div>
@ -113,8 +101,8 @@
<th>Date</th>
<th>Amount</th>
<th>Recipient</th>
<th>ER number</th>
<th>Catchphrase</th>
<th>Activity</th>
<th>Category</th>
<th>Description</th>
<th>Receipt Scan</th>
<th>Rows</th>
@ -124,9 +112,9 @@
<td>"Belegdatum" for credit card statements</td>
<td>In EUR. Format: 123,00</td>
<td></td>
<td>Valid ER number</td>
<td>Catch phrase for the ER</td>
<td>What specifically was paid for. <strong>-</strong> if equal to catchphrase</td>
<td>What activity was this part of</td>
<td>What category is the expense</td>
<td>What specifically was paid for.</td>
<td>Upload receipt as PDF, max. 2MB each</td>
<td>Add a new row, or delete one</td>
</tr>
@ -135,8 +123,8 @@
<td>Example 1: 16.04.2021</td>
<td>12,34</td>
<td>Berlin Bus Company</td>
<td>er.2021-04-16.123.4567</td>
<td>Cool Conference</td>
<td>Select the activity</td>
<td>Select fitting category or "other"</td>
<td>Bus ticket from Berlin to New York</td>
<td>e.g. busticket.pdf</td>
<td></td>
@ -146,8 +134,8 @@
<td>Example 2: 17.04.2021</td>
<td>67,89</td>
<td>ACME</td>
<td>er.2021-04-17.890.1234</td>
<td>New laptop for Jane Doe</td>
<td></td>
<td></td>
<td>USB adapter for external keyboard</td>
<td>e.g. acme-adapter.pdf</td>
<td></td>
@ -157,9 +145,18 @@
<td><input type="date" name="entry[]" class="form-control" required="required" /></td>
<td><input type="text" name="amount[]" class="form-control" pattern="-?\d{0,5},\d{2}" placeholder="12,34" required="required" /></td>
<td><input type="text" name="recipient[]" class="form-control" required="required" /></td>
<td><input type="text" name="er[]" class="form-control" pattern="^er\.[\d]{4}-[\d]{2}-[\d]{2}\.[\d.-]+" placeholder="er.2020-..." required="required" /></td>
<td><input type="text" name="catch[]" class="form-control" required="required" /></td>
<td><input type="text" name="remarks[]" class="form-control" required="required" /></td>
<td><select class="form-control col-sm-3" name="activity" id="activity" size="1" required="required">
<module id="fsfe-activities-options" />
</select></td>
<td><select class="form-control col-sm-3" name="category" id="category" size="1">
<option value="????:Other / I don't know">Other / I don't know</option>
<option value="6815:Office material">Office material</option>
<option value="6710:Packaging material">Packaging material</option>
<option value="6800:Postage">Postage</option>
<option value="6660:Travel costs - hotel">Travel costs - hotel</option>
<option value="6663:Travel costs - transport">Travel costs - transport</option>
</select></td>
<td><input type="text" name="description[]" class="form-control" required="required" /></td>
<td><input type="file" name="receipt[]" class="form-control" required="required" /></td>
<td><input type="button" class="AddNewRow btn btn-primary" value="+ 1 row" /></td>
</tr>
@ -199,5 +196,4 @@
</body>
</html>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<data>
<version>1</version>
<module>
<option value="Alexander Sander|alex.sander">Alexander Sander</option>
<option value="Ana Galan|anaghz">Ana Galán</option>
<option value="Bonnie Mehring|bonnie">Bonnie Mehring</option>
<option value="Carmen Bianca Bakker|carmenbianca">Carmen Bianca Bakker</option>
<option value="Dario Presutti|dario">Dario Presutti</option>
<option value="Erik Albers|eal">Erik Albers</option>
<option value="Erika Pirić|epiric">Erika Pirić</option>
<option value="Florian Snow|floriansnow">Florian Snow</option>
<option value="Francesca Indorato|fi">Francesca Indorato</option>
<option value="Gabriel Ku Wei Bin|gabriel.ku">Gabriel Ku Wei Bin</option>
<option value="Heiki Lõhmus|repentinus">Heiki Lõhmus</option>
<option value="Henning Fehr|hf">Henning Fehr</option>
<option value="Johannes Näder|jn">Johannes Näder</option>
<option value="Linus Sehn|linus">Linus Sehn</option>
<option value="Lucas Lasota|lucas.lasota">Lucas Lasota</option>
<option value="Max Mehl|max.mehl">Max Mehl</option>
<option value="Matthias Kirschner|mk">Matthias Kirschner</option>
<option value="Reinhard Müller|reinhard">Reinhard Müller</option>
<option value="Tobias Diekershoff|tobiasd">Tobias Diekershoff</option>
</module>
</data>