diff --git a/FurnitureCompany/FurnitureCompany/Entities/Delivery.cs b/FurnitureCompany/FurnitureCompany/Entities/Delivery.cs
index 9608fb5..454617d 100644
--- a/FurnitureCompany/FurnitureCompany/Entities/Delivery.cs
+++ b/FurnitureCompany/FurnitureCompany/Entities/Delivery.cs
@@ -26,4 +26,16 @@ public class Delivery
             DeliveryProducts = deliveryProducts
         };
     }
+
+    public static Delivery CreateOperation(TempDeliveryProduct tempDeliveryProduct,
+        IEnumerable<DeliveryProduct> deliveryProducts)
+    {
+        return new Delivery
+        {
+            Id = tempDeliveryProduct.Id,
+            WorkerId = tempDeliveryProduct.WorkerId,
+            DateDelivery = tempDeliveryProduct.DateDelivery,
+            DeliveryProducts = deliveryProducts
+        };
+    }
 }
diff --git a/FurnitureCompany/FurnitureCompany/Entities/DeliveryProduct.cs b/FurnitureCompany/FurnitureCompany/Entities/DeliveryProduct.cs
index eb07acf..48dfac4 100644
--- a/FurnitureCompany/FurnitureCompany/Entities/DeliveryProduct.cs
+++ b/FurnitureCompany/FurnitureCompany/Entities/DeliveryProduct.cs
@@ -12,17 +12,14 @@ public class DeliveryProduct
 
     public int ProductId { get; private set; }
 
-    public int DeliveryId { get; private set; }
-
     public int Count { get; private set; }
 
-    public static DeliveryProduct CreateElement(int id, int productId, int deliveryId, int count)
+    public static DeliveryProduct CreateElement(int id, int productId, int count)
     {
         return new DeliveryProduct
         {
             Id = id,
             ProductId = productId,
-            DeliveryId = deliveryId,
             Count = count
         };
     }
diff --git a/FurnitureCompany/FurnitureCompany/Entities/TempDeliveryProduct.cs b/FurnitureCompany/FurnitureCompany/Entities/TempDeliveryProduct.cs
new file mode 100644
index 0000000..9d80363
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Entities/TempDeliveryProduct.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FurnitureCompany.Entities;
+
+public class TempDeliveryProduct
+{
+    public int Id { get; private set; }
+
+    public int WorkerId { get; private set; }
+
+    public DateTime DateDelivery { get; private set; }
+
+    public int ProductId { get; private set; }
+
+    public int Count { get; private set; }
+}
diff --git a/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.Designer.cs b/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.Designer.cs
index 226092d..10264be 100644
--- a/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.Designer.cs
+++ b/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.Designer.cs
@@ -37,6 +37,8 @@
             InvoicesToolStripMenuItem = new ToolStripMenuItem();
             DeliveryToolStripMenuItem = new ToolStripMenuItem();
             отчётыToolStripMenuItem = new ToolStripMenuItem();
+            DirectoryReportToolStripMenuItem = new ToolStripMenuItem();
+            productReportToolStripMenuItem = new ToolStripMenuItem();
             menuStrip1.SuspendLayout();
             SuspendLayout();
             // 
@@ -101,10 +103,27 @@
             // 
             // отчётыToolStripMenuItem
             // 
+            отчётыToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { DirectoryReportToolStripMenuItem, productReportToolStripMenuItem });
             отчётыToolStripMenuItem.Name = "отчётыToolStripMenuItem";
             отчётыToolStripMenuItem.Size = new Size(73, 24);
             отчётыToolStripMenuItem.Text = "Отчёты";
             // 
+            // DirectoryReportToolStripMenuItem
+            // 
+            DirectoryReportToolStripMenuItem.Name = "DirectoryReportToolStripMenuItem";
+            DirectoryReportToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.W;
+            DirectoryReportToolStripMenuItem.Size = new Size(350, 26);
+            DirectoryReportToolStripMenuItem.Text = "Документ со справочниками";
+            DirectoryReportToolStripMenuItem.Click += DirectoryReportToolStripMenuItem_Click;
+            // 
+            // productReportToolStripMenuItem
+            // 
+            productReportToolStripMenuItem.Name = "productReportToolStripMenuItem";
+            productReportToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.E;
+            productReportToolStripMenuItem.Size = new Size(350, 26);
+            productReportToolStripMenuItem.Text = "Движение изделий";
+            productReportToolStripMenuItem.Click += ProductReportToolStripMenuItem_Click;
+            // 
             // FormFurnitureCompany
             // 
             AutoScaleDimensions = new SizeF(8F, 20F);
@@ -134,5 +153,7 @@
         private ToolStripMenuItem отчётыToolStripMenuItem;
         private ToolStripMenuItem InvoicesToolStripMenuItem;
         private ToolStripMenuItem DeliveryToolStripMenuItem;
+        private ToolStripMenuItem DirectoryReportToolStripMenuItem;
+        private ToolStripMenuItem productReportToolStripMenuItem;
     }
 }
diff --git a/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.cs b/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.cs
index 4ae0ee5..13c81aa 100644
--- a/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.cs
+++ b/FurnitureCompany/FurnitureCompany/FormFurnitureCompany.cs
@@ -20,7 +20,7 @@ namespace FurnitureCompany
             {
                 _container.Resolve<FormWorkers>().ShowDialog();
             }
-            catch(Exception ex)
+            catch (Exception ex)
             {
                 MessageBox.Show(ex.Message, "������ ��� ��������", MessageBoxButtons.OK, MessageBoxIcon.Error);
             }
@@ -73,5 +73,29 @@ namespace FurnitureCompany
                 MessageBox.Show(ex.Message, "������ ��� ��������", MessageBoxButtons.OK, MessageBoxIcon.Error);
             }
         }
+
+        private void DirectoryReportToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                _container.Resolve<FormDirectoryReport>().ShowDialog();
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "������ ��� ��������", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            }
+        }
+
+        private void ProductReportToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                _container.Resolve<FormProductReport>().ShowDialog();
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "������ ��� ��������", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            }
+        }
     }
 }
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormDelivery.cs b/FurnitureCompany/FurnitureCompany/Forms/FormDelivery.cs
index 18d7b1f..70663e1 100644
--- a/FurnitureCompany/FurnitureCompany/Forms/FormDelivery.cs
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormDelivery.cs
@@ -68,10 +68,11 @@ namespace FurnitureCompany.Forms
                 }
 
                 list.Add(DeliveryProduct.CreateElement(0, Convert.ToInt32(row.Cells["ColumnProduct"].Value),
-                Convert.ToInt32(row.Cells["ColumnCount"].Value), 0));
+                Convert.ToInt32(row.Cells["ColumnCount"].Value)));
             }
 
-            return list;
+            return list.GroupBy(x => x.ProductId, x => x.Count, (id, counts) =>
+                DeliveryProduct.CreateElement(0, id, counts.Sum())).ToList();
         }
     }
 }
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.Designer.cs b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.Designer.cs
new file mode 100644
index 0000000..275db51
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.Designer.cs
@@ -0,0 +1,99 @@
+namespace FurnitureCompany.Forms
+{
+    partial class FormDirectoryReport
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            checkBoxClients = new CheckBox();
+            checkBoxWorkers = new CheckBox();
+            checkBoxProducts = new CheckBox();
+            buttonBuild = new Button();
+            SuspendLayout();
+            // 
+            // checkBoxClients
+            // 
+            checkBoxClients.AutoSize = true;
+            checkBoxClients.Location = new Point(55, 31);
+            checkBoxClients.Name = "checkBoxClients";
+            checkBoxClients.Size = new Size(91, 24);
+            checkBoxClients.TabIndex = 0;
+            checkBoxClients.Text = "Клиенты";
+            checkBoxClients.UseVisualStyleBackColor = true;
+            // 
+            // checkBoxWorkers
+            // 
+            checkBoxWorkers.AutoSize = true;
+            checkBoxWorkers.Location = new Point(55, 82);
+            checkBoxWorkers.Name = "checkBoxWorkers";
+            checkBoxWorkers.Size = new Size(105, 24);
+            checkBoxWorkers.TabIndex = 1;
+            checkBoxWorkers.Text = "Работники";
+            checkBoxWorkers.UseVisualStyleBackColor = true;
+            // 
+            // checkBoxProducts
+            // 
+            checkBoxProducts.AutoSize = true;
+            checkBoxProducts.Location = new Point(55, 138);
+            checkBoxProducts.Name = "checkBoxProducts";
+            checkBoxProducts.Size = new Size(90, 24);
+            checkBoxProducts.TabIndex = 2;
+            checkBoxProducts.Text = "Изделия";
+            checkBoxProducts.UseVisualStyleBackColor = true;
+            // 
+            // buttonBuild
+            // 
+            buttonBuild.Location = new Point(257, 77);
+            buttonBuild.Name = "buttonBuild";
+            buttonBuild.Size = new Size(125, 29);
+            buttonBuild.TabIndex = 3;
+            buttonBuild.Text = "Сформировать";
+            buttonBuild.UseVisualStyleBackColor = true;
+            buttonBuild.Click += ButtonBuild_Click;
+            // 
+            // FormDirectoryReport
+            // 
+            AutoScaleDimensions = new SizeF(8F, 20F);
+            AutoScaleMode = AutoScaleMode.Font;
+            ClientSize = new Size(453, 214);
+            Controls.Add(buttonBuild);
+            Controls.Add(checkBoxProducts);
+            Controls.Add(checkBoxWorkers);
+            Controls.Add(checkBoxClients);
+            Name = "FormDirectoryReport";
+            Text = "FormDirectoryReport";
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+
+        private CheckBox checkBoxClients;
+        private CheckBox checkBoxWorkers;
+        private CheckBox checkBoxProducts;
+        private Button buttonBuild;
+    }
+}
\ No newline at end of file
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.cs b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.cs
new file mode 100644
index 0000000..482582a
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.cs
@@ -0,0 +1,63 @@
+using FurnitureCompany.Reports;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Unity;
+
+namespace FurnitureCompany.Forms
+{
+    public partial class FormDirectoryReport : Form
+    {
+        private readonly IUnityContainer _container;
+
+        public FormDirectoryReport(IUnityContainer container)
+        {
+            InitializeComponent();
+            _container = container ??
+                throw new ArgumentNullException(nameof(container));
+        }
+
+        private void ButtonBuild_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                if (!checkBoxClients.Checked && !checkBoxWorkers.Checked && !checkBoxProducts.Checked)
+                {
+                    throw new Exception("Не выбран ни один справочник для выгрузки");
+                }
+
+                var sfd = new SaveFileDialog()
+                {
+                    Filter = "Docx Files | *.docx"
+                };
+
+                if (sfd.ShowDialog() != DialogResult.OK)
+                {
+                    throw new Exception("Не выбран файла для отчета");
+                }
+
+                if (_container.Resolve<DocReport>().CreateDoc(sfd.FileName, checkBoxClients.Checked,
+                    checkBoxWorkers.Checked, checkBoxProducts.Checked))
+                {
+                    MessageBox.Show("Документ сформирован", "Формирование документа",
+                                    MessageBoxButtons.OK, MessageBoxIcon.Information);
+                }
+                else
+                {
+                    MessageBox.Show("Возникли ошибки при формировании документа.Подробности в логах",
+                                    "Формирование документа", MessageBoxButtons.OK, MessageBoxIcon.Information);
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "Ошибка при создании отчета", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            }
+        }
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.resx b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormDirectoryReport.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.Designer.cs b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.Designer.cs
new file mode 100644
index 0000000..def70c0
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.Designer.cs
@@ -0,0 +1,163 @@
+namespace FurnitureCompany.Forms
+{
+    partial class FormProductReport
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            dateTimePickerDateFrom = new DateTimePicker();
+            dateTimePickerDateTo = new DateTimePicker();
+            labelFilePath = new Label();
+            labelProduct = new Label();
+            labelDateFrom = new Label();
+            labelDateTo = new Label();
+            buttonMakeReport = new Button();
+            buttonSelectFilePath = new Button();
+            textBoxFilePath = new TextBox();
+            comboBoxProduct = new ComboBox();
+            SuspendLayout();
+            // 
+            // dateTimePickerDateFrom
+            // 
+            dateTimePickerDateFrom.Location = new Point(158, 146);
+            dateTimePickerDateFrom.Name = "dateTimePickerDateFrom";
+            dateTimePickerDateFrom.Size = new Size(248, 27);
+            dateTimePickerDateFrom.TabIndex = 0;
+            // 
+            // dateTimePickerDateTo
+            // 
+            dateTimePickerDateTo.Location = new Point(158, 201);
+            dateTimePickerDateTo.Name = "dateTimePickerDateTo";
+            dateTimePickerDateTo.Size = new Size(248, 27);
+            dateTimePickerDateTo.TabIndex = 1;
+            // 
+            // labelFilePath
+            // 
+            labelFilePath.AutoSize = true;
+            labelFilePath.Location = new Point(40, 34);
+            labelFilePath.Name = "labelFilePath";
+            labelFilePath.Size = new Size(112, 20);
+            labelFilePath.TabIndex = 2;
+            labelFilePath.Text = "Путь до файла:";
+            // 
+            // labelProduct
+            // 
+            labelProduct.AutoSize = true;
+            labelProduct.Location = new Point(40, 94);
+            labelProduct.Name = "labelProduct";
+            labelProduct.Size = new Size(71, 20);
+            labelProduct.TabIndex = 3;
+            labelProduct.Text = "Изделие:";
+            // 
+            // labelDateFrom
+            // 
+            labelDateFrom.AutoSize = true;
+            labelDateFrom.Location = new Point(40, 151);
+            labelDateFrom.Name = "labelDateFrom";
+            labelDateFrom.Size = new Size(97, 20);
+            labelDateFrom.TabIndex = 4;
+            labelDateFrom.Text = "Дата начала:";
+            // 
+            // labelDateTo
+            // 
+            labelDateTo.AutoSize = true;
+            labelDateTo.Location = new Point(40, 206);
+            labelDateTo.Name = "labelDateTo";
+            labelDateTo.Size = new Size(90, 20);
+            labelDateTo.TabIndex = 5;
+            labelDateTo.Text = "Дата конца:";
+            // 
+            // buttonMakeReport
+            // 
+            buttonMakeReport.Location = new Point(158, 265);
+            buttonMakeReport.Name = "buttonMakeReport";
+            buttonMakeReport.Size = new Size(126, 29);
+            buttonMakeReport.TabIndex = 6;
+            buttonMakeReport.Text = "Сформировать";
+            buttonMakeReport.UseVisualStyleBackColor = true;
+            buttonMakeReport.Click += ButtonMakeReport_Click;
+            // 
+            // buttonSelectFilePath
+            // 
+            buttonSelectFilePath.Location = new Point(379, 31);
+            buttonSelectFilePath.Name = "buttonSelectFilePath";
+            buttonSelectFilePath.Size = new Size(27, 27);
+            buttonSelectFilePath.TabIndex = 7;
+            buttonSelectFilePath.Text = "..";
+            buttonSelectFilePath.UseVisualStyleBackColor = true;
+            buttonSelectFilePath.Click += ButtonSelectFilePath_Click;
+            // 
+            // textBoxFilePath
+            // 
+            textBoxFilePath.Location = new Point(158, 31);
+            textBoxFilePath.Name = "textBoxFilePath";
+            textBoxFilePath.ReadOnly = true;
+            textBoxFilePath.Size = new Size(215, 27);
+            textBoxFilePath.TabIndex = 8;
+            // 
+            // comboBoxProduct
+            // 
+            comboBoxProduct.FormattingEnabled = true;
+            comboBoxProduct.Location = new Point(158, 91);
+            comboBoxProduct.Name = "comboBoxProduct";
+            comboBoxProduct.Size = new Size(248, 28);
+            comboBoxProduct.TabIndex = 9;
+            // 
+            // FormProductReport
+            // 
+            AutoScaleDimensions = new SizeF(8F, 20F);
+            AutoScaleMode = AutoScaleMode.Font;
+            ClientSize = new Size(460, 337);
+            Controls.Add(comboBoxProduct);
+            Controls.Add(textBoxFilePath);
+            Controls.Add(buttonSelectFilePath);
+            Controls.Add(buttonMakeReport);
+            Controls.Add(labelDateTo);
+            Controls.Add(labelDateFrom);
+            Controls.Add(labelProduct);
+            Controls.Add(labelFilePath);
+            Controls.Add(dateTimePickerDateTo);
+            Controls.Add(dateTimePickerDateFrom);
+            Name = "FormProductReport";
+            Text = "Отчёт по изделиям";
+            ResumeLayout(false);
+            PerformLayout();
+        }
+
+        #endregion
+
+        private DateTimePicker dateTimePickerDateFrom;
+        private DateTimePicker dateTimePickerDateTo;
+        private Label labelFilePath;
+        private Label labelProduct;
+        private Label labelDateFrom;
+        private Label labelDateTo;
+        private Button buttonMakeReport;
+        private Button buttonSelectFilePath;
+        private TextBox textBoxFilePath;
+        private ComboBox comboBoxProduct;
+    }
+}
\ No newline at end of file
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.cs b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.cs
new file mode 100644
index 0000000..e2b5426
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.cs
@@ -0,0 +1,82 @@
+using FurnitureCompany.Reports;
+using FurnitureCompany.Repositories;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Unity;
+
+namespace FurnitureCompany.Forms
+{
+    public partial class FormProductReport : Form
+    {
+        private readonly IUnityContainer _container;
+
+        public FormProductReport(IUnityContainer container, IProductRepository productRepository)
+        {
+            InitializeComponent();
+            _container = container;
+
+            comboBoxProduct.DataSource = productRepository.ReadProducts();
+            comboBoxProduct.DisplayMember = "Name";
+            comboBoxProduct.ValueMember = "Id";
+        }
+
+        private void ButtonSelectFilePath_Click(object sender, EventArgs e)
+        {
+            var sfd = new SaveFileDialog()
+            {
+                Filter = "Excel Files | *.xlsx"
+            };
+
+            if (sfd.ShowDialog() != DialogResult.OK)
+            {
+                return;
+            }
+
+            textBoxFilePath.Text = sfd.FileName;
+        }
+
+        private void ButtonMakeReport_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                if (string.IsNullOrWhiteSpace(textBoxFilePath.Text))
+                {
+                    throw new Exception("Отсутствует имя файла для отчета");
+                }
+
+                if (comboBoxProduct.SelectedIndex < 0)
+                {
+                    throw new Exception("Не выбран корм");
+                }
+
+                if (dateTimePickerDateTo.Value <= dateTimePickerDateFrom.Value)
+                {
+                    throw new Exception("Дата начала должна быть раньше даты окончания");
+                }
+
+                if (_container.Resolve<TableReport>().CreateTable(textBoxFilePath.Text,
+                    (int)comboBoxProduct.SelectedValue!, dateTimePickerDateFrom.Value, dateTimePickerDateTo.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);
+            }
+        }
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.resx b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Forms/FormProductReport.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!--
+    Microsoft ResX Schema
+
+    Version 2.0
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
+    associated with the data types.
+
+    Example:
+
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+
+    There are any number of "resheader" rows that contain simple
+    name/value pairs.
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
+    mimetype set.
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
+    extensible. For a given mimetype the value must be set accordingly:
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
+    read any of the formats listed below.
+
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/FurnitureCompany/FurnitureCompany/FurnitureCompany.csproj b/FurnitureCompany/FurnitureCompany/FurnitureCompany.csproj
index 11eb0f9..b531b1e 100644
--- a/FurnitureCompany/FurnitureCompany/FurnitureCompany.csproj
+++ b/FurnitureCompany/FurnitureCompany/FurnitureCompany.csproj
@@ -10,6 +10,7 @@
 
   <ItemGroup>
     <PackageReference Include="Dapper" Version="2.1.35" />
+    <PackageReference Include="DocumentFormat.OpenXml" Version="3.2.0" />
     <PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
     <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
     <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
diff --git a/FurnitureCompany/FurnitureCompany/Reports/DocReport.cs b/FurnitureCompany/FurnitureCompany/Reports/DocReport.cs
new file mode 100644
index 0000000..bf99055
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Reports/DocReport.cs
@@ -0,0 +1,98 @@
+using FurnitureCompany.Repositories;
+using FurnitureCompany.Repositories.Implementations;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FurnitureCompany.Reports;
+
+internal class DocReport
+{
+    private readonly IClientRepository _clientRepository;
+
+    private readonly IWorkerRepository _workerRepository;
+
+    private readonly IProductRepository _productRepository;
+
+    private readonly ILogger<DocReport> _logger;
+
+    public DocReport(IClientRepository clientRepository, IWorkerRepository workerRepository, IProductRepository productRepository, ILogger<DocReport> logger)
+    {
+        _clientRepository = clientRepository ??
+            throw new ArgumentNullException(nameof(clientRepository));
+        _workerRepository = workerRepository ??
+            throw new ArgumentNullException(nameof(workerRepository));
+        _productRepository = productRepository ??
+            throw new ArgumentNullException(nameof(productRepository));
+        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+    }
+
+    public bool CreateDoc(string filePath, bool includeClients, bool includeWorkers, bool includeProducts)
+    {
+        try
+        {
+            var wordBuilder = new WordBuilder(filePath)
+                .AddHeader("Документ со справочниками");
+
+            if (includeClients)
+            {
+                wordBuilder.AddParagraph("Клиенты")
+                    .AddTable([2400, 2400, 2400, 2400], GetClients());
+            }
+
+            if (includeWorkers)
+            {
+                wordBuilder.AddParagraph("Работники")
+                    .AddTable([2400, 2400, 2400], GetWorkers());
+            }
+
+            if (includeProducts)
+            {
+                wordBuilder.AddParagraph("Изделия")
+                    .AddTable([2400, 2400, 2400], GetProducts());
+            }
+
+            wordBuilder.Build();
+
+            return true;
+        }
+        catch (Exception ex)
+        {
+            _logger.LogError(ex, "Ошибка при формировании документа");
+            return false;
+        }
+    }
+
+    private List<string[]> GetClients()
+    {
+        return [
+            ["Имя", "Адрес", "Возраст", "Прибыль"],
+            .. _clientRepository
+                .ReadClients()
+                .Select(x => new string[] { x.Name, x.Address, x.Age.ToString(), x.Earnings.ToString() }),
+        ];
+    }
+
+    private List<string[]> GetWorkers()
+    {
+        return [
+            ["Имя", "Фамилия", "Уровень опыта"],
+            .. _workerRepository
+                .ReadWorkers()
+                .Select(x => new string[] { x.FirstName, x.LastName, x.WorkerPost.ToString() }),
+        ];
+    }
+
+    private List<string[]> GetProducts()
+    {
+        return [
+            ["Тип материала", "Названия", "Цена"],
+            .. _productRepository
+                .ReadProducts()
+                .Select(x => new string[] { x.Material.ToString(), x.Name, x.Price.ToString() }),
+        ];
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Reports/ExcelBuilder.cs b/FurnitureCompany/FurnitureCompany/Reports/ExcelBuilder.cs
new file mode 100644
index 0000000..a0bf727
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Reports/ExcelBuilder.cs
@@ -0,0 +1,333 @@
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FurnitureCompany.Reports;
+
+internal class ExcelBuilder
+{
+    private readonly string _filePath;
+
+    private readonly SheetData _sheetData;
+
+    private readonly MergeCells _mergeCells;
+
+    private readonly Columns _columns;
+
+    private uint _rowIndex = 0;
+
+    public ExcelBuilder(string filePath)
+    {
+        if (string.IsNullOrWhiteSpace(filePath))
+        {
+            throw new ArgumentNullException(nameof(filePath));
+        }
+
+        if (File.Exists(filePath))
+        {
+            File.Delete(filePath);
+        }
+
+        _filePath = filePath;
+        _sheetData = new SheetData();
+        _mergeCells = new MergeCells();
+        _columns = new Columns();
+        _rowIndex = 1;
+    }
+
+    public ExcelBuilder AddHeader(string header, int startIndex, int count)
+    {
+        CreateCell(startIndex, _rowIndex, header, StyleIndex.BoldTextWithoutBorder);
+        for (int i = startIndex + 1; i < startIndex + count; ++i)
+        {
+            CreateCell(i, _rowIndex, "", StyleIndex.SimpleTextWithoutBorder);
+        }
+
+        _mergeCells.Append(new MergeCell()
+        {
+            Reference = new StringValue($"{GetExcelColumnName(startIndex)}{_rowIndex}:{GetExcelColumnName(startIndex + count - 1)}{_rowIndex}")
+        });
+
+        _rowIndex++;
+        return this;
+    }
+
+    public ExcelBuilder AddParagraph(string text, int columnIndex)
+    {
+        CreateCell(columnIndex, _rowIndex++, text, StyleIndex.SimpleTextWithoutBorder);
+        return this;
+    }
+
+    public ExcelBuilder AddTable(int[] columnsWidths, List<string[]> data)
+    {
+        if (columnsWidths == null || columnsWidths.Length == 0)
+        {
+            throw new ArgumentNullException(nameof(columnsWidths));
+        }
+
+        if (data == null || data.Count == 0)
+        {
+            throw new ArgumentNullException(nameof(data));
+        }
+
+        if (data.Any(x => x.Length != columnsWidths.Length))
+        {
+            throw new InvalidOperationException("widths.Length != data.Length");
+        }
+
+        uint counter = 1;
+        int coef = 2;
+        _columns.Append(columnsWidths.Select(x => new Column
+        {
+            Min = counter,
+            Max = counter++,
+            Width = x * coef,
+            CustomWidth = true
+        }));
+
+        for (var j = 0; j < data.First().Length; ++j)
+        {
+            CreateCell(j, _rowIndex, data.First()[j], StyleIndex.BoldTextWithBorder);
+        }
+
+        _rowIndex++;
+
+        for (var i = 1; i < data.Count - 1; ++i)
+        {
+            for (var j = 0; j < data[i].Length; ++j)
+            {
+                CreateCell(j, _rowIndex, data[i][j], StyleIndex.SimpleTextWithBorder);
+            }
+            _rowIndex++;
+        }
+
+        for (var j = 0; j < data.Last().Length; ++j)
+        {
+            CreateCell(j, _rowIndex, data.Last()[j], StyleIndex.BoldTextWithBorder);
+        }
+
+        _rowIndex++;
+        return this;
+    }
+
+    public void Build()
+    {
+        using var spreadsheetDocument = SpreadsheetDocument.Create(_filePath, SpreadsheetDocumentType.Workbook);
+        var workbookpart = spreadsheetDocument.AddWorkbookPart();
+        GenerateStyle(workbookpart);
+        workbookpart.Workbook = new Workbook();
+        var worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
+        worksheetPart.Worksheet = new Worksheet();
+
+        if (_columns.HasChildren)
+        {
+            worksheetPart.Worksheet.Append(_columns);
+        }
+
+        worksheetPart.Worksheet.Append(_sheetData);
+        var sheets = spreadsheetDocument.WorkbookPart!.Workbook.AppendChild(new Sheets());
+        var sheet = new Sheet()
+        {
+            Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
+            SheetId = 1,
+            Name = "Лист 1"
+        };
+        sheets.Append(sheet);
+        if (_mergeCells.HasChildren)
+        {
+            worksheetPart.Worksheet.InsertAfter(_mergeCells,
+            worksheetPart.Worksheet.Elements<SheetData>().First());
+        }
+    }
+
+    private static void GenerateStyle(WorkbookPart workbookPart)
+    {
+        var workbookStylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
+        workbookStylesPart.Stylesheet = new Stylesheet();
+
+        var fonts = new Fonts()
+        {
+            Count = 2,
+            KnownFonts = BooleanValue.FromBoolean(true)
+        };
+        fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
+        {
+            FontSize = new FontSize() { Val = 11 },
+            FontName = new FontName() { Val = "Calibri" },
+            FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
+            FontScheme = new FontScheme()
+            {
+                Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor)
+            }
+        });
+        fonts.Append(new DocumentFormat.OpenXml.Spreadsheet.Font
+        {
+            FontSize = new FontSize() { Val = 11 },
+            FontName = new FontName() { Val = "Calibri" },
+            FontFamilyNumbering = new FontFamilyNumbering() { Val = 2 },
+            FontScheme = new FontScheme()
+            {
+                Val = new EnumValue<FontSchemeValues>(FontSchemeValues.Minor)
+            },
+            Bold = new Bold() { Val = true }
+        });
+        workbookStylesPart.Stylesheet.Append(fonts);
+
+        // Default Fill
+        var fills = new Fills() { Count = 1 };
+        fills.Append(new Fill
+        {
+            PatternFill = new PatternFill()
+            {
+                PatternType = new EnumValue<PatternValues>(PatternValues.None)
+            }
+        });
+        workbookStylesPart.Stylesheet.Append(fills);
+
+        // Default Border
+        var borders = new Borders() { Count = 2 };
+        borders.Append(new Border
+        {
+            LeftBorder = new LeftBorder(),
+            RightBorder = new RightBorder(),
+            TopBorder = new TopBorder(),
+            BottomBorder = new BottomBorder(),
+            DiagonalBorder = new DiagonalBorder()
+        });
+        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
+        {
+            NumberFormatId = 0,
+            FormatId = 0,
+            FontId = 0,
+            BorderId = 0,
+            FillId = 0,
+            Alignment = new Alignment()
+            {
+                Horizontal = HorizontalAlignmentValues.Left,
+                Vertical = VerticalAlignmentValues.Center,
+                WrapText = true
+            }
+        });
+        cellFormats.Append(new CellFormat
+        {
+            NumberFormatId = 0,
+            FormatId = 0,
+            FontId = 0,
+            BorderId = 1,
+            FillId = 0,
+            Alignment = new Alignment()
+            {
+                Horizontal = HorizontalAlignmentValues.Right,
+                Vertical = VerticalAlignmentValues.Center,
+                WrapText = true
+            }
+        });
+        cellFormats.Append(new CellFormat
+        {
+            NumberFormatId = 0,
+            FormatId = 0,
+            FontId = 1,
+            BorderId = 0,
+            FillId = 0,
+            Alignment = new Alignment()
+            {
+                Horizontal = HorizontalAlignmentValues.Center,
+                Vertical = VerticalAlignmentValues.Center,
+                WrapText = true
+            }
+        });
+        cellFormats.Append(new CellFormat
+        {
+            NumberFormatId = 0,
+            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,
+        SimpleTextWithBorder = 1,
+        BoldTextWithoutBorder = 2,
+        BoldTextWithBorder = 3
+    }
+
+    private void CreateCell(int columnIndex, uint rowIndex, string text, StyleIndex styleIndex)
+    {
+        var columnName = GetExcelColumnName(columnIndex);
+        var cellReference = columnName + rowIndex;
+        var row = _sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex! == rowIndex);
+        if (row == null)
+        {
+            row = new Row() { RowIndex = rowIndex };
+            _sheetData.Append(row);
+        }
+
+        var newCell = row.Elements<Cell>().FirstOrDefault(c => c.CellReference != null &&
+                                                          c.CellReference.Value == columnName + rowIndex);
+        if (newCell == null)
+        {
+            Cell? refCell = null;
+            foreach (Cell cell in row.Elements<Cell>())
+            {
+                if (cell.CellReference?.Value != null &&
+                    cell.CellReference.Value.Length == cellReference.Length)
+                {
+                    if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
+                    {
+                        refCell = cell;
+                        break;
+                    }
+                }
+            }
+            newCell = new Cell() { CellReference = cellReference };
+            row.InsertBefore(newCell, refCell);
+        }
+        newCell.CellValue = new CellValue(text);
+        newCell.DataType = CellValues.String;
+        newCell.StyleIndex = (uint)styleIndex;
+    }
+
+    private static string GetExcelColumnName(int columnNumber)
+    {
+        columnNumber += 1;
+        int dividend = columnNumber;
+        string columnName = string.Empty;
+        int modulo;
+
+        while (dividend > 0)
+        {
+            modulo = (dividend - 1) % 26;
+            columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
+            dividend = (dividend - modulo) / 26;
+        }
+
+        return columnName;
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Reports/TableReport.cs b/FurnitureCompany/FurnitureCompany/Reports/TableReport.cs
new file mode 100644
index 0000000..4eb75b5
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Reports/TableReport.cs
@@ -0,0 +1,72 @@
+using FurnitureCompany.Repositories;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FurnitureCompany.Reports;
+
+internal class TableReport
+{
+    private readonly IDeliveryRepository _deliveryRepository;
+
+    private readonly IInvoiceRepository _invoiceRepository;
+
+    private readonly ILogger<TableReport> _logger;
+
+    internal static readonly string[] item = ["Сотрудник", "Дата", "Количество пришло", "Количество ушло"];
+
+    public TableReport(IDeliveryRepository deliveryRepository,
+                        IInvoiceRepository invoiceRepository, ILogger<TableReport> logger)
+    {
+        _deliveryRepository = deliveryRepository ??
+            throw new ArgumentNullException(nameof(deliveryRepository));
+        _invoiceRepository = invoiceRepository ??
+            throw new ArgumentNullException(nameof(invoiceRepository));
+        _logger = logger ??
+            throw new ArgumentNullException(nameof(logger));
+    }
+
+    public bool CreateTable(string filePath, int productId, DateTime startDate, DateTime endDate)
+    {
+        try
+        {
+            new ExcelBuilder(filePath)
+                .AddHeader("Сводка по доставке изделий", 0, 2)
+                .AddParagraph("за период", 0)
+                .AddTable([10, 10, 15], GetData(productId, startDate, endDate))
+                .Build();
+
+            return true;
+        }
+        catch (Exception ex)
+        {
+            _logger.LogError(ex, "Ошибка при формировании документа");
+            return false;
+        }
+    }
+
+    private List<string[]> GetData(int productId, DateTime startDate, DateTime endDate)
+    {
+        var data = _deliveryRepository
+            .ReadDeliverys()
+            .Where(x => x.DateDelivery >= startDate && x.DateDelivery <= endDate && x.DeliveryProducts.Any(y => y.ProductId == productId))
+            .Select(x => new { x.WorkerId, Date = x.DateDelivery, CountIn = x.DeliveryProducts.FirstOrDefault(y => y.ProductId == productId)?.Count, CountOut = (int?)null })
+            .Union(
+                _invoiceRepository
+                    .ReadInvoices()
+                    .Where(x => x.Date >= startDate && x.Date <= endDate)
+                    .Select(x => new { x.WorkerId, Date = x.Date, CountIn = (int?)null, CountOut = (int?)x.CountProduct }))
+            .OrderBy(x => x.Date);
+
+        return new List<string[]>() { item }
+                .Union(
+                    data
+                        .Select(x => new string[] { x.WorkerId.ToString(), x.Date.ToString(), x.CountIn?.ToString() ?? string.Empty, x.CountOut?.ToString() ?? string.Empty }))
+                .Union(
+                    [["Всего", data.Sum(x => x.CountIn ?? 0).ToString(), data.Sum(x => x.CountOut ?? 0).ToString()]])
+                .ToList();
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Reports/WordBuilder.cs b/FurnitureCompany/FurnitureCompany/Reports/WordBuilder.cs
new file mode 100644
index 0000000..683a6da
--- /dev/null
+++ b/FurnitureCompany/FurnitureCompany/Reports/WordBuilder.cs
@@ -0,0 +1,115 @@
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Packaging;
+using DocumentFormat.OpenXml.Wordprocessing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection.Metadata;
+using System.Text;
+using System.Threading.Tasks;
+using Document = DocumentFormat.OpenXml.Wordprocessing.Document;
+
+
+namespace FurnitureCompany.Reports;
+
+internal class WordBuilder
+{
+    private readonly string _filePath;
+
+    private readonly Document _document;
+
+    private readonly Body _body;
+
+    public WordBuilder(string filePath)
+    {
+        if (string.IsNullOrWhiteSpace(filePath))
+        {
+            throw new ArgumentNullException(nameof(filePath));
+        }
+
+        if (File.Exists(filePath))
+        {
+            File.Delete(filePath);
+        }
+
+        _filePath = filePath;
+        _document = new Document();
+        _body = _document.AppendChild(new Body());
+    }
+
+    public WordBuilder AddHeader(string header)
+    {
+        var paragraph = _body.AppendChild(new Paragraph());
+        var run = paragraph.AppendChild(new Run());
+        // TODO прописать настройки под жирный текст
+        var runProperties = run.AppendChild(new RunProperties());
+        runProperties.AppendChild(new Bold());
+        run.AppendChild(new Text(header));
+
+        return this;
+    }
+
+    public WordBuilder AddParagraph(string text)
+    {
+        var paragraph = _body.AppendChild(new Paragraph());
+        var run = paragraph.AppendChild(new Run());
+        run.AppendChild(new Text(text));
+
+        return this;
+    }
+
+    public WordBuilder AddTable(int[] widths, List<string[]> data)
+    {
+        if (widths == null || widths.Length == 0)
+        {
+            throw new ArgumentNullException(nameof(widths));
+        }
+
+        if (data == null || data.Count == 0)
+        {
+            throw new ArgumentNullException(nameof(data));
+        }
+
+        if (data.Any(x => x.Length != widths.Length))
+        {
+            throw new InvalidOperationException("widths.Length != data.Length");
+        }
+
+        var table = new Table();
+        table.AppendChild(new TableProperties(
+            new TableBorders(
+                new TopBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
+                new BottomBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
+                new LeftBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
+                new RightBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
+                new InsideHorizontalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 },
+                new InsideVerticalBorder() { Val = new EnumValue<BorderValues>(BorderValues.Single), Size = 12 }
+            )
+        ));
+
+        // Заголовок
+        var tr = new TableRow();
+        for (var j = 0; j < widths.Length; ++j)
+        {
+            tr.Append(new TableCell(
+                new TableCellProperties(new TableCellWidth() { Width = widths[j].ToString() }),
+            new Paragraph(new Run(new RunProperties(new Bold()), new Text(data.First()[j])))));
+        }
+        table.Append(tr);
+
+        // Данные
+        table.Append(data.Skip(1).Select(x =>
+            new TableRow(x.Select(y => new TableCell(new Paragraph(new Run(new Text(y))))))));
+
+        _body.Append(table);
+
+        return this;
+    }
+
+    public void Build()
+    {
+        using var wordDocument = WordprocessingDocument.Create(_filePath, WordprocessingDocumentType.Document);
+        var mainPart = wordDocument.AddMainDocumentPart();
+        mainPart.Document = _document;
+    }
+}
diff --git a/FurnitureCompany/FurnitureCompany/Repositories/Implementations/DeliveryRepository.cs b/FurnitureCompany/FurnitureCompany/Repositories/Implementations/DeliveryRepository.cs
index 0209f54..a007a85 100644
--- a/FurnitureCompany/FurnitureCompany/Repositories/Implementations/DeliveryRepository.cs
+++ b/FurnitureCompany/FurnitureCompany/Repositories/Implementations/DeliveryRepository.cs
@@ -85,10 +85,13 @@ public class DeliveryRepository : IDeliveryRepository
         {
             using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
             var querySelect = @"
-                SELECT * FROM Deliverys";
-            var deliverys = connection.Query<Delivery>(querySelect);
+                SELECT fr.*, ffr.ProductId, ffr.Count FROM Deliverys fr
+                INNER JOIN DeliveryProducts ffr ON ffr.DeliveryId = fr.Id";
+            var deliverys = connection.Query<TempDeliveryProduct>(querySelect);
             _logger.LogDebug("Полученные объекты: {json}", JsonConvert.SerializeObject(deliverys));
-            return deliverys;
+            return deliverys.GroupBy(x => x.Id, y => y,
+                (key, value) => Delivery.CreateOperation(value.First(),
+                    value.Select(z => DeliveryProduct.CreateElement(0, z.ProductId, z.Count)))).ToList();
         }
         catch (Exception ex)
         {