diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Accounting-Time-It-Company.csproj b/Accounting-Time-It-Company/Accounting-Time-It-Company/Accounting-Time-It-Company.csproj index e365797..23e39a2 100644 --- a/Accounting-Time-It-Company/Accounting-Time-It-Company/Accounting-Time-It-Company.csproj +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Accounting-Time-It-Company.csproj @@ -21,6 +21,7 @@ + diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.Designer.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.Designer.cs index 06a8224..138ad30 100644 --- a/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.Designer.cs +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.Designer.cs @@ -40,6 +40,7 @@ reportsToolStripMenuItem = new ToolStripMenuItem(); DirectoryReportToolStripMenuItem = new ToolStripMenuItem(); WorkAndCheelEmpToolStripMenuItem = new ToolStripMenuItem(); + VacatiobEmpToolStripMenuItem = new ToolStripMenuItem(); menuStrip1.SuspendLayout(); SuspendLayout(); // @@ -111,7 +112,7 @@ // // reportsToolStripMenuItem // - reportsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { DirectoryReportToolStripMenuItem, WorkAndCheelEmpToolStripMenuItem }); + reportsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { DirectoryReportToolStripMenuItem, WorkAndCheelEmpToolStripMenuItem, VacatiobEmpToolStripMenuItem }); reportsToolStripMenuItem.Name = "reportsToolStripMenuItem"; reportsToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.W; reportsToolStripMenuItem.Size = new Size(73, 24); @@ -133,6 +134,14 @@ WorkAndCheelEmpToolStripMenuItem.Text = "Работа и отдых сотрудников"; WorkAndCheelEmpToolStripMenuItem.Click += WorkAndCheelEmpToolStripMenuItem_Click; // + // VacatiobEmpToolStripMenuItem + // + VacatiobEmpToolStripMenuItem.Name = "VacatiobEmpToolStripMenuItem"; + VacatiobEmpToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.P; + VacatiobEmpToolStripMenuItem.Size = new Size(350, 26); + VacatiobEmpToolStripMenuItem.Text = "Отпуска работников"; + VacatiobEmpToolStripMenuItem.Click += VacatiobEmpToolStripMenuItem_Click; + // // FormCompany // AutoScaleDimensions = new SizeF(8F, 20F); @@ -165,5 +174,6 @@ private ToolStripMenuItem EmployeesToolStripMenuItem; private ToolStripMenuItem DirectoryReportToolStripMenuItem; private ToolStripMenuItem WorkAndCheelEmpToolStripMenuItem; + private ToolStripMenuItem VacatiobEmpToolStripMenuItem; } } diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.cs index ce20805..1162700 100644 --- a/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.cs +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/FormCompany.cs @@ -117,5 +117,18 @@ namespace Accounting_Time_It_Company MessageBoxButtons.OK, MessageBoxIcon.Error); } } + + private void VacatiobEmpToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + _container.Resolve().ShowDialog(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, " ", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } } } diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.Designer.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.Designer.cs new file mode 100644 index 0000000..00e5e54 --- /dev/null +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.Designer.cs @@ -0,0 +1,107 @@ +namespace Accounting_Time_It_Company.Forms +{ + partial class FormVacationEmployeeDistributionReport + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + buttonPath = new Button(); + labelPath = new Label(); + dateTimePicker = new DateTimePicker(); + labelDate = new Label(); + buttonBuild = new Button(); + SuspendLayout(); + // + // buttonPath + // + buttonPath.Location = new Point(5, 5); + buttonPath.Name = "buttonPath"; + buttonPath.Size = new Size(94, 29); + buttonPath.TabIndex = 0; + buttonPath.Text = "Выбрать"; + buttonPath.UseVisualStyleBackColor = true; + buttonPath.Click += ButtonPath_Click; + // + // labelPath + // + labelPath.AutoSize = true; + labelPath.Location = new Point(105, 9); + labelPath.Name = "labelPath"; + labelPath.Size = new Size(45, 20); + labelPath.TabIndex = 1; + labelPath.Text = "Файл"; + // + // dateTimePicker + // + dateTimePicker.Location = new Point(68, 49); + dateTimePicker.Name = "dateTimePicker"; + dateTimePicker.Size = new Size(163, 27); + dateTimePicker.TabIndex = 2; + // + // labelDate + // + labelDate.AutoSize = true; + labelDate.Location = new Point(12, 54); + labelDate.Name = "labelDate"; + labelDate.Size = new Size(41, 20); + labelDate.TabIndex = 3; + labelDate.Text = "Дата"; + // + // buttonBuild + // + buttonBuild.Location = new Point(53, 82); + buttonBuild.Name = "buttonBuild"; + buttonBuild.Size = new Size(125, 29); + buttonBuild.TabIndex = 4; + buttonBuild.Text = "Сформировать"; + buttonBuild.UseVisualStyleBackColor = true; + buttonBuild.Click += ButtonBuild_Click; + // + // FormVacationEmployeeDistributionReport + // + AutoScaleDimensions = new SizeF(8F, 20F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(374, 122); + Controls.Add(buttonBuild); + Controls.Add(labelDate); + Controls.Add(dateTimePicker); + Controls.Add(labelPath); + Controls.Add(buttonPath); + Name = "FormVacationEmployeeDistributionReport"; + Text = "FormVacationEmployeeDistributionReport"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Button buttonPath; + private Label labelPath; + private DateTimePicker dateTimePicker; + private Label labelDate; + private Button buttonBuild; + } +} \ No newline at end of file diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.cs new file mode 100644 index 0000000..8c66769 --- /dev/null +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.cs @@ -0,0 +1,58 @@ +using Accounting_Time_It_Company.Reports; +using Unity; + +namespace Accounting_Time_It_Company.Forms +{ + public partial class FormVacationEmployeeDistributionReport : Form + { + + private string _fileName = string.Empty; + private readonly IUnityContainer _container; + public FormVacationEmployeeDistributionReport(IUnityContainer container) + { + InitializeComponent(); + _container = container ?? + throw new ArgumentNullException(nameof(container)); + } + + private void ButtonBuild_Click(object sender, EventArgs e) + { + try + { + if (string.IsNullOrWhiteSpace(_fileName)) + { + throw new Exception("Отсутствует имя файла для отчета"); + } + if + (_container.Resolve().CreateChart(_fileName, dateTimePicker.Value)) + { + MessageBox.Show("Документ сформирован", "Формирование документа", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + MessageBox.Show("Возникли ошибки при формировании документа.Подробности в логах", "Формирование документа", + MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Ошибка при создании очета", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void ButtonPath_Click(object sender, EventArgs e) + { + var sfd = new SaveFileDialog() + { + Filter = "Pdf Files | *.pdf" + }; + if (sfd.ShowDialog() == DialogResult.OK) + { + _fileName = sfd.FileName; + labelPath.Text = Path.GetFileName(_fileName); + } + } + } +} diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.resx b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Forms/FormVacationEmployeeDistributionReport.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ChartReport.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ChartReport.cs new file mode 100644 index 0000000..57c9570 --- /dev/null +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ChartReport.cs @@ -0,0 +1,44 @@ +using Accounting_Time_It_Company.Repositories; +using Microsoft.Extensions.Logging; + +namespace Accounting_Time_It_Company.Reports; + +internal class ChartReport +{ + private readonly IVacationRepositories _vacationRepositories; + private readonly ILogger _logger; + public ChartReport(IVacationRepositories feedingAnimalRepository, + ILogger logger) + { + _vacationRepositories = feedingAnimalRepository ?? throw new ArgumentNullException(nameof(feedingAnimalRepository)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + } + public bool CreateChart(string filePath, DateTime dateTime) + { + try + { + new PdfBuilder(filePath) + .AddHeader("Отпуска сотрудников") + .AddPieChart("Выданные часы", GetData(dateTime)) + .Build(); + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "Ошибка при формировании документа"); + return false; + } + } + private List<(string Caption, double Value)> GetData(DateTime dateTime) + { + return _vacationRepositories + .ReadVacations() + .Where(x => x.StartDate.Date == dateTime.Date) + .GroupBy(x => x.EmployeeId, (key, group) => new { + Id = key, + Count = group.Sum(x => (x.EndDate - x.StartDate).TotalHours) + }) + .Select(x => (x.Id.ToString(), (double)x.Count)) + .ToList(); + } +} diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ExcelBuilder.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ExcelBuilder.cs index fe85f86..79ecdac 100644 --- a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ExcelBuilder.cs +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/ExcelBuilder.cs @@ -30,17 +30,15 @@ internal class ExcelBuilder public ExcelBuilder AddHeader(string header, int startIndex, int count) { CreateCell(startIndex, _rowIndex, header, - StyleIndex.SimpleTextWithoutBorder); + StyleIndex.CenteredBoldTextWithBorders); for (int i = startIndex + 1; i < startIndex + count; ++i) { CreateCell(i, _rowIndex, "", - StyleIndex.SimpleTextWithoutBorder); + StyleIndex.CenteredBoldTextWithBorders); } _mergeCells.Append(new MergeCell() { - Reference = - new - StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}") + Reference = new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}") }); _rowIndex++; return this; @@ -135,8 +133,7 @@ internal class ExcelBuilder var fonts = new Fonts() { Count = 2, - KnownFonts = - BooleanValue.FromBoolean(true) + KnownFonts = BooleanValue.FromBoolean(true) }; fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font { @@ -145,11 +142,22 @@ internal class ExcelBuilder FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 }, FontScheme = new FontScheme() { - Val = new - EnumValue(FontSchemeValues.Minor) + Val = new EnumValue(FontSchemeValues.Minor) } }); // TODO добавить шрифт с жирным + fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font + { + Bold = new Bold(), + FontSize = new FontSize() { Val = 11 }, + FontName = new FontName() { Val = "Calibri" }, + FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 }, + FontScheme = new FontScheme() + { + Val = new EnumValue(FontSchemeValues.Minor) + } + }); + workbookStylesPart.Stylesheet.Append(fonts); // Default Fill var fills = new Fills() { Count = 1 }; @@ -173,8 +181,17 @@ internal class ExcelBuilder DiagonalBorder = new DiagonalBorder() }); // TODO добавить настройку с границами + borders.Append(new Border + { + LeftBorder = new LeftBorder { Style = BorderStyleValues.Thin }, + RightBorder = new RightBorder { Style = BorderStyleValues.Thin }, + TopBorder = new TopBorder { Style = BorderStyleValues.Thin }, + BottomBorder = new BottomBorder { Style = BorderStyleValues.Thin }, + DiagonalBorder = new DiagonalBorder() + }); + workbookStylesPart.Stylesheet.Append(borders); - // Default cell format and a date cell format + var cellFormats = new CellFormats() { Count = 4 }; cellFormats.Append(new CellFormat { @@ -191,15 +208,28 @@ internal class ExcelBuilder } }); // TODO дополнить форматы + cellFormats.Append(new CellFormat + { + NumberFormatId = 1, + FormatId = 0, + FontId = 1, + BorderId = 1, + FillId = 0, + Alignment = new Alignment() + { + Horizontal = HorizontalAlignmentValues.Center, + Vertical = VerticalAlignmentValues.Center, + WrapText = true + } + }); workbookStylesPart.Stylesheet.Append(cellFormats); } private enum StyleIndex { SimpleTextWithoutBorder = 0, - // TODO дополнить стили + CenteredBoldTextWithBorders = 1 } - private void CreateCell(int columnIndex, uint rowIndex, string text, - StyleIndex styleIndex) + private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex) { var columnName = GetExcelColumnName(columnIndex); var cellReference = columnName + rowIndex; diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/PdfBuilder.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/PdfBuilder.cs new file mode 100644 index 0000000..4d9de38 --- /dev/null +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/PdfBuilder.cs @@ -0,0 +1,75 @@ +using MigraDoc.DocumentObjectModel; +using MigraDoc.DocumentObjectModel.Shapes.Charts; +using MigraDoc.Rendering; +using System.Text; + +namespace Accounting_Time_It_Company.Reports; + +internal class PdfBuilder +{ + private readonly string _filePath; + private readonly Document _document; + public PdfBuilder(string filePath) + { + if (string.IsNullOrWhiteSpace(filePath)) + { + throw new ArgumentNullException(nameof(filePath)); + } + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + _filePath = filePath; + _document = new Document(); + DefineStyles(); + } + public PdfBuilder AddHeader(string header) + { + _document.AddSection().AddParagraph(header, "NormalBold"); + return this; + } + public PdfBuilder AddPieChart(string title, List<(string Caption, double + Value)> data) + { + if (data == null || data.Count == 0) + { + return this; + } + var chart = new Chart(ChartType.Pie2D); + var series = chart.SeriesCollection.AddSeries(); + series.Add(data.Select(x => x.Value).ToArray()); + var xseries = chart.XValues.AddXSeries(); + xseries.Add(data.Select(x => x.Caption).ToArray()); + chart.DataLabel.Type = DataLabelType.Percent; + chart.DataLabel.Position = DataLabelPosition.OutsideEnd; + chart.Width = Unit.FromCentimeter(16); + chart.Height = Unit.FromCentimeter(12); + chart.TopArea.AddParagraph(title); + chart.XAxis.MajorTickMark = TickMarkType.Outside; + chart.YAxis.MajorTickMark = TickMarkType.Outside; + chart.YAxis.HasMajorGridlines = true; + chart.PlotArea.LineFormat.Width = 1; + chart.PlotArea.LineFormat.Visible = true; + chart.TopArea.AddLegend(); + _document.LastSection.Add(chart); + return this; + } + public void Build() + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + var renderer = new PdfDocumentRenderer(true) + { + Document = _document + }; + renderer.RenderDocument(); + renderer.PdfDocument.Save(_filePath); + } + private void DefineStyles() + { + // TODO задать стиль для заголовка (жирный) + var headerStyle = _document.Styles.AddStyle("HeaderStyle", "Normal"); + headerStyle.Font.Bold = true; + headerStyle.Font.Size = 14; + headerStyle.ParagraphFormat.Alignment = ParagraphAlignment.Center; + } +} diff --git a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/WordBuilder.cs b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/WordBuilder.cs index 387c465..998c26b 100644 --- a/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/WordBuilder.cs +++ b/Accounting-Time-It-Company/Accounting-Time-It-Company/Reports/WordBuilder.cs @@ -27,7 +27,12 @@ internal class WordBuilder { var paragraph = _body.AppendChild(new Paragraph()); var run = paragraph.AppendChild(new Run()); + // TODO прописать настройки под жирный текст + var runProperties = new RunProperties(); + runProperties.AppendChild(new Bold()); + run.AppendChild(runProperties); + run.AppendChild(new Text(header)); return this; }