Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Database/Initial.sql
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ GO
-- **************************************************
INSERT INTO [Permission] ([Level], [Description], [DescriptionLong])
VALUES (1, 'Normal', 'Users, who can only see their own times'),
(2, 'Advanced', 'Can approve absences of Normal users'),
(3, 'High', 'Can make changes to Details and Users')
(2, 'Manager', 'Can approve absences of Normal users'),
(3, 'Admin', 'Can make changes to Details and Users')
GO

-- **************************************************
Expand Down
82 changes: 47 additions & 35 deletions Extensions/ExcelHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,23 +110,25 @@ orderby u.Username
row.CreateCell(colNum).SetCellFormula(formula);
}

// Calendar week rows
// Row 5+
// columnPerUsers stores all users of current year and adds a string with a number of each holiday for a person, where the poition in the string is the week
var columnPerUser = new Dictionary<string, string>();
var columnPerUser = new Dictionary<string, Decimal[]>();

foreach (var user in usersThisYear)
{
columnPerUser.Add(user.Username, new string('0', totalWeeks));
columnPerUser.Add(user.Username, new Decimal[totalWeeks]);

var absences = db.Absence.Where(a => (a.IdUser == user.ID) && (a.AbsentFrom.Year == year) && (user.Deactivated == false)).ToList();
var daysInWeeks = new int[totalWeeks];
var daysInWeeks = columnPerUser.GetValueOrDefault(user.Username);

foreach (var a in absences)
{
// Almost identical to Post Overtime OwnTimes.cshtml
// https://stackoverflow.com/questions/13440595/get-list-of-dates-from-startdate-to-enddate
//Counts days between a.AbsentFrom and a.AbsentTo
IEnumerable<double> daysToAdd = Enumerable.Range(0, (a.AbsentTo - a.AbsentFrom).Days + 1).ToList().ConvertAll(d => (double)d);
IEnumerable<DateTime> ListOfDates = daysToAdd.Select(a.AbsentFrom.AddDays).ToList();
// Creates a List with each number from 0 to the count of days between AbsentFrom and AbsentTo
List<double> daysToAdd = Enumerable.Range(0, (a.AbsentTo - a.AbsentFrom).Days + 1).ToList().ConvertAll(d => (double)d);
// Creates a List with every date between and including AbsentFrom and AbsentTo
List<DateTime> ListOfDates = daysToAdd.Select(a.AbsentFrom.AddDays).ToList();

foreach (var date in ListOfDates)
{
Expand All @@ -141,8 +143,16 @@ orderby u.Username
}
}
}

// Subtract or add, depending on a.Negative, half a day from AbsentFrom, if FromAfternoon is true and AbsentFrom is not on a weekend
if (a.FromAfternoon && a.AbsentFrom.DayOfWeek != DayOfWeek.Saturday && a.AbsentFrom.DayOfWeek != DayOfWeek.Sunday)
daysInWeeks[GetWeek(a.AbsentFrom) - 1] = a.Negative ? daysInWeeks[GetWeek(a.AbsentFrom) - 1] + (Decimal)0.5 : daysInWeeks[GetWeek(a.AbsentFrom) - 1] - (Decimal)0.5;

// Subtract or add, depending on a.Negative, half a day from AbsentTo, if ToAfternoon is true and AbsentTo is not on a weekend
if (!a.ToAfternoon && a.AbsentTo.DayOfWeek != DayOfWeek.Saturday && a.AbsentTo.DayOfWeek != DayOfWeek.Sunday)
daysInWeeks[GetWeek(a.AbsentTo) - 1] = a.Negative ? daysInWeeks[GetWeek(a.AbsentTo) - 1] + (Decimal)0.5 : daysInWeeks[GetWeek(a.AbsentTo) - 1] - (Decimal)0.5;
}
columnPerUser[user.Username] = string.Join("", daysInWeeks);
columnPerUser[user.Username] = daysInWeeks;
}

// Writes all holidays from all weeks into rows
Expand All @@ -153,7 +163,7 @@ orderby u.Username
row.CreateCell(colNum).SetCellValue("KW" + (i + 1).ToString("D2")); //ToString("D2") for 2 digits like 01
foreach (var user in columnPerUser)
{
row.CreateCell(++colNum).SetCellValue(Int32.Parse(user.Value[i].ToString()));
row.CreateCell(++colNum).SetCellValue(Double.Parse(user.Value[i].ToString()));
}
}

Expand Down Expand Up @@ -268,8 +278,6 @@ await Task.Run(() =>
// Workbook
var wb = new XSSFWorkbook();

// Style

// All users which are used by Overtimes in this year
var year = DateTime.Now.Year;
var users = (from u in db.User
Expand Down Expand Up @@ -325,7 +333,25 @@ orderby u.Username
RegionUtil.SetBorderBottom(border, region, sh, wb);
RegionUtil.SetBorderLeft(border, region, sh, wb);

// Row 2+
// Row 2
row = sh.CreateRow(++rowNum);
colNum = 0;
row.CreateCell(colNum);
row.CreateCell(++colNum).SetCellValue("TOTAL");
row.CreateCell(++colNum);
row.CreateCell(++colNum).SetCellFormula("F3/8.5");
row.CreateCell(++colNum).SetCellValue("<<<<");
row.CreateCell(++colNum); //.SetCellFormula($"SUM(F4:F{sh.LastRowNum + 1})"); Value set after overtimes have been written so LastRowNum is correct
var style = (XSSFCellStyle)wb.CreateCellStyle();
var font = wb.CreateFont();
font.FontHeight = wb.GetFontAt(0).FontHeight;
font.IsBold = true;
style.SetFont(font);
style.BorderTop = style.BorderRight = style.BorderBottom = style.BorderLeft = BorderStyle.Medium;
foreach (var cell in row)
cell.CellStyle = style;

// Row 3+
var overtimes = (from o in db.Overtime
where (o.Date.Year == year) && (o.IdUser == user.ID)
orderby o.Date
Expand All @@ -336,43 +362,29 @@ orderby o.Date
colNum = 0;
row.CreateCell(colNum).SetCellValue(overtime.Date.ToShortDateString());
row.CreateCell(++colNum).SetCellValue(overtime.Customer);
row.CreateCell(++colNum).SetCellValue("");
row.CreateCell(++colNum).SetCellValue(overtime.Approved ? "ok" : "");
row.CreateCell(++colNum).SetCellValue(overtime.Hours.ToString());
var rate = db.OvertimeDetail.Where(od => od.ID == overtime.IdOvertimeDetail).Select(s => s.Rate);
row.CreateCell(++colNum).SetCellValue(Convert.ToDouble(rate.Single()));
row.CreateCell(++colNum).SetCellFormula($"IF(C{rowNum + 1}=\"ok\",D{rowNum + 1}*E{rowNum + 1},0)");
}

// Last row
rowNum = 49; // Is row 50 in excel
row = sh.CreateRow(rowNum);
colNum = 1;
row.CreateCell(colNum).SetCellValue("TOTAL");
row.CreateCell(colNum += 2).SetCellFormula("F50/8.5");
row.CreateCell(++colNum).SetCellValue("<<<<");
row.CreateCell(++colNum).SetCellFormula("SUM(F3:F49)");
var style = (XSSFCellStyle)wb.CreateCellStyle();
var font = wb.CreateFont();
font.FontHeight = wb.GetFontAt(0).FontHeight;
font.IsBold = true;
style.SetFont(font);
foreach (var cell in row)
cell.CellStyle = style;

// Row 2 Col 5 gets value here, because it relies on number of written overtimes
sh.GetRow(2).GetCell(5).SetCellFormula($"SUM(F4:F{sh.LastRowNum + 1})");

// Styles for entry rows
var cs = (XSSFCellStyle)wb.CreateCellStyle();
cs.BorderTop = cs.BorderRight = cs.BorderBottom = cs.BorderLeft = BorderStyle.Thin;
border = (int)BorderStyle.Thin;
for (var i = 2; i <= 48; i++)
for (var i = 3; i <= sh.LastRowNum; i++)
{
var r = sh.GetRow(i);
if (r != null)
foreach (var cell in r.Cells)
cell.CellStyle = cs;
}

// Conditional formatting
// Conditional formatting user sheets
IConditionalFormattingRule rule;
IPatternFormatting pf;

Expand All @@ -381,7 +393,7 @@ orderby o.Date
pf.FillBackgroundColor = IndexedColors.LightTurquoise.Index;
pf.FillPattern = FillPattern.SolidForeground;
sh.SheetConditionalFormatting.AddConditionalFormatting(
new[] { CellRangeAddress.ValueOf("A50:F50"), CellRangeAddress.ValueOf("F3:F50") },
new[] { CellRangeAddress.ValueOf("A3:F3"), CellRangeAddress.ValueOf($"F4:F{sh.LastRowNum + 1}") },
rule
);

Expand All @@ -390,8 +402,8 @@ orderby o.Date
row = sh.CreateRow(sh.LastRowNum + 1);
colNum = 0;
row.CreateCell(colNum).SetCellValue(user.Username);
row.CreateCell(++colNum).SetCellFormula(user.Username + "!$F$50");
row.CreateCell(++colNum).SetCellFormula(user.Username + "!$D$50");
row.CreateCell(++colNum).SetCellFormula(user.Username + "!$F$3");
row.CreateCell(++colNum).SetCellFormula(user.Username + "!$D$3");
// Borders for these cells
style = null;
style = (XSSFCellStyle)wb.CreateCellStyle();
Expand All @@ -400,7 +412,7 @@ orderby o.Date
foreach (var cell in row.Cells)
cell.CellStyle = style;

// Conditional formatting
// Conditional formatting overview sheet
rule = sh.SheetConditionalFormatting.CreateConditionalFormattingRule(ComparisonOperator.NotBetween, "0", "5");
pf = rule.CreatePatternFormatting();
pf.FillBackgroundColor = IndexedColors.Red.Index;
Expand Down
5 changes: 4 additions & 1 deletion Model/Absence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ public class AbsenceModel
public Guid IdAbsenceDetail { get; set; }
public DateTime AbsentFrom { get; set; }
public DateTime AbsentTo { get; set; }
public bool FromAfternoon { get; set; }
public bool ToAfternoon { get; set; }
public Decimal TotalDays { get; set; }
public bool Negative { get; set; }
public string Reason { get; set; }
public bool Approved { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime LastChanged { get; set; }
}
}
10 changes: 2 additions & 8 deletions Model/AbsenceValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,9 @@ public class AbsenceValidation
[RequiredIf(relatedProperty = "AbsenceDateFrom", propertyRelation = RequiredIfAttribute.Result.dateDiffPositive, ErrorMessage = "'Abwesend bis' darf nicht vor Abwesend von sein")]
public string AbsenceDateTo { get; set; }

public bool FullDay { get; set; }
public bool FromAfternoon { get; set; }

[RequiredIf(relatedProperty = "FullDay", propertyRelation = RequiredIfAttribute.Result.mustBeTrue, ErrorMessage = "'Zeit von' darf nicht leer sein")]
[RegularExpression(@"^(\d{2})\:(\d{2})$", ErrorMessage = "Die Eingabe muss in folgendem Format sein: HH:mm")]
public string AbsenceTimeFrom { get; set; }

[RequiredIf(relatedProperty = "FullDay", propertyRelation = RequiredIfAttribute.Result.mustBeTrue, ErrorMessage = "'Zeit bis' darf nicht leer sein")]
[RegularExpression(@"^(\d{2})\:(\d{2})$", ErrorMessage = "Die Eingabe muss in folgendem Format sein: HH:mm")]
public string AbsenceTimeTo { get; set; }
public bool ToAfternoon { get; set; }

public bool Negative { get; set; }

Expand Down
3 changes: 2 additions & 1 deletion Model/Overtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class OvertimeModel
public string Customer { get; set; }
public DateTime Date { get; set; }
public decimal Hours { get; set; }
public DateTime CreatedOn { get; set; }
public bool Approved { get; set; }
public DateTime LastChanged { get; set; }
}
}
2 changes: 2 additions & 0 deletions Model/OvertimeValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ public class OvertimeValidation
[Required(ErrorMessage = "Kunde darf nicht leer sein")]
public string Customer { get; set; }

public bool Approved { get; set; }

}
}
3 changes: 1 addition & 2 deletions Pages/Controlling.cshtml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@page
@using System.Linq
@model ControllingPageModel
@{ ViewData["Title"] = "Controlling"; }
@{
Expand Down Expand Up @@ -36,7 +35,7 @@
<th>Ist I.O.</th>
</tr>
</thead>
<tbody>
<tbody style="--height: 15vh">
<!-- JS replaces this tbody -->
</tbody>
</table>
Expand Down
46 changes: 25 additions & 21 deletions Pages/OwnTimes.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,26 @@
@model OwnTimesPageModel
@{ ViewData["Title"] = "Eigene Zeiten"; }
<script>
writeOwnTimesTables('true', '@User.FindFirst(ClaimTypes.NameIdentifier).Value');
$(document).ready(() => {
writeOwnTimesTables('false', '@User.FindFirst(ClaimTypes.NameIdentifier).Value');
$(`option[value='@User.FindFirst(ClaimTypes.NameIdentifier).Value.ToUpper()']`).attr('selected', 'selected');
});
</script>
<div id="OwnTimes">
<h1>Eigene Zeiten</h1>

<a class="btn modal-trigger" href="#absenceWindow">Neue Abwesenheit</a>
<a class="btn modal-trigger" href="#overtimeWindow">Neue Überzeit</a>
@{
if (User.IsInRole("Advanced") || User.IsInRole("High"))
UserModel user = Model._db.User.Where(u => u.ID.ToString() == User.FindFirst(ClaimTypes.NameIdentifier).Value).SingleOrDefault();
if (User.IsInRole("Manager") || User.IsInRole("Admin"))
{
<select id="userDropdown" class="right browser-default btn" style="width: fit-content;">
@{
foreach (var item in Model.userList)
{
if (item.ID.ToString() == @User.FindFirst(ClaimTypes.NameIdentifier).Value)
{
<option selected value="@item.ID">@item.Username</option>
} else
{
<option value="@item.ID">@item.Username</option>
}
}
}
</select>
<select id="userDropdown" class="right browser-default btn" asp-items="Model.userList" style="width: fit-content;"></select>
}
}

<label class="right">
<input id="filter" type="checkbox" class="filled-in" checked />
<input id="filter" type="checkbox" class="filled-in" />
<span style="padding-right: 1em;">Letze 30 Tage</span>
</label>

Expand All @@ -39,8 +31,14 @@
<partial name="/Pages/OwnTimes/_OvertimePartial.cshtml" />

<!-- AbsenceGrid -->
<h4>Abwesenheiten</h4>
<div class="table-container responsive-table">
<div style="display: grid; grid-template-columns: 1fr auto;">
<h4>Abwesenheiten</h4>
<div class="right" style="margin: 1.52rem 0 .912rem 0;">
<span id="absencesRemaining"></span>
&nbsp;Tage verfügbare Abwesenheit bis 31.12.2019
</div>
</div>
<div class="table-container">
<table>
<thead>
<tr>
Expand All @@ -57,8 +55,14 @@
</table>
</div>
<!-- OvertimeGrid -->
<h4>Überzeiten</h4>
<div class="table-container responsive-table">
<div style="display: grid; grid-template-columns: 1fr auto;">
<h4>Überzeiten</h4>
<div class="right" style="margin: 1.52rem 0 .912rem 0;">
<span id="doneOvertimes"></span>
h Überzeit seit 1.1.2019
</div>
</div>
<div class="table-container">
<table>
<thead>
<tr>
Expand Down
Loading