< Summary

Information
Class: Services.Builders.PdfBuilder.Builders.TransactionTablePdfBuilder
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/Builders/PdfBuilder/Builders/TransactionTablePdfBuilder.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 180
Coverable lines: 180
Total lines: 315
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 78
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()0%506220%
TryLoadSystemFonts()0%2040%
GeneratePdfWithStocks(...)0%2550500%
CreateFallbackPdf(...)0%620%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/Builders/PdfBuilder/Builders/TransactionTablePdfBuilder.cs

#LineLine coverage
 1using iText.IO.Font;
 2using iText.Kernel.Font;
 3using iText.Kernel.Pdf;
 4using iText.Layout;
 5using iText.Layout.Element;
 6using System.IO;
 7using iText.IO.Font.Constants;
 8using iText.Layout.Properties;
 9using iText.Kernel.Colors;
 10using OzonDomains.Models;
 11
 12namespace Services.Builders.PdfBuilder.Builders;
 13
 14public class TransactionTablePdfBuilder
 15{
 16    private MemoryStream _memoryStream = null!;
 17    private PdfWriter _writer = null!;
 18    private PdfDocument _pdf = null!;
 19    private Document _document = null!;
 20    private PdfFont _font = null!;
 21    private PdfFont _boldFont = null!;
 22    private ICollection<Order> _orders = null!;
 23
 024    public TransactionTablePdfBuilder()
 25    {
 026        _memoryStream = new MemoryStream();
 027        _writer = new PdfWriter(_memoryStream);
 028        _pdf = new PdfDocument(_writer);
 029        _document = new Document(_pdf);
 030        _document.SetMargins(20, 20, 20, 20);
 31
 32        try
 33        {
 34            // Попробуем использовать шрифты, которые точно поддерживают кириллицу
 035            string[] knownCyrillicFonts = {
 036                "times.ttf", "timesbd.ttf",
 037                "dejavu-sans.ttf", "dejavu-sans-bold.ttf",
 038                "liberation-sans.ttf", "liberation-sans-bold.ttf",
 039                "freesans.ttf", "freesansbold.ttf",
 040                "arial.ttf", "arialbd.ttf"
 041            };
 42
 043            string? regularFontPath = null;
 044            string? boldFontPath = null;
 45
 46            // Ищем папку со шрифтами
 047            string[] possibleFontFolders = {
 048                Path.Combine(Directory.GetCurrentDirectory(), "Fonts"),
 049                Path.Combine(Directory.GetCurrentDirectory(), "fonts"),
 050                Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "fonts"),
 051                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Fonts"),
 052                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fonts")
 053            };
 54
 055            foreach (var folder in possibleFontFolders)
 56            {
 057                if (Directory.Exists(folder))
 58                {
 059                    foreach (var fontFile in knownCyrillicFonts)
 60                    {
 061                        string path = Path.Combine(folder, fontFile);
 062                        if (File.Exists(path))
 63                        {
 064                            if (fontFile.Contains("bold") || fontFile.Contains("bd"))
 65                            {
 066                                boldFontPath = path;
 67                            }
 068                            else if (!fontFile.Contains("bold") && !fontFile.Contains("bd"))
 69                            {
 070                                regularFontPath = path;
 71                            }
 72                        }
 73                    }
 74
 075                    if (regularFontPath != null) break;
 76                }
 77            }
 78
 079            if (regularFontPath != null)
 80            {
 081                _font = PdfFontFactory.CreateFont(regularFontPath, PdfEncodings.IDENTITY_H);
 082                _boldFont = boldFontPath != null
 083                    ? PdfFontFactory.CreateFont(boldFontPath, PdfEncodings.IDENTITY_H)
 084                    : PdfFontFactory.CreateFont(regularFontPath, PdfEncodings.IDENTITY_H);
 85            }
 86            else
 87            {
 088                TryLoadSystemFonts();
 89            }
 090        }
 091        catch (Exception ex)
 92        {
 093            TryLoadSystemFonts();
 094            Console.WriteLine($"Ошибка загрузки шрифтов: {ex.Message}");
 095        }
 096    }
 97
 98    private void TryLoadSystemFonts()
 99    {
 100        try
 101        {
 0102            string[] linuxFontPaths = {
 0103                "/usr/share/fonts/truetype/freefont/FreeSans.ttf",
 0104                "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
 0105                "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
 0106                "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf"
 0107            };
 108
 0109            foreach (var path in linuxFontPaths)
 110            {
 0111                if (File.Exists(path))
 112                {
 0113                    _font = PdfFontFactory.CreateFont(path, PdfEncodings.IDENTITY_H);
 0114                    _boldFont = PdfFontFactory.CreateFont(path, PdfEncodings.IDENTITY_H);
 0115                    return;
 116                }
 117            }
 118
 0119            _font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
 0120            _boldFont = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
 0121        }
 0122        catch
 123        {
 0124            _font = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
 0125            _boldFont = PdfFontFactory.CreateFont(StandardFonts.HELVETICA_BOLD);
 0126        }
 0127    }
 128
 129    public byte[] GeneratePdfWithStocks(ICollection<Order> orders, Dictionary<string, int> articleToStock)
 130    {
 131        try
 132        {
 0133            _orders = orders ?? new List<Order>();
 134
 135            // Заголовок документа
 0136            _document.Add(new Paragraph("Таблица заказов")
 0137                .SetFont(_boldFont)
 0138                .SetFontSize(16)
 0139                .SetTextAlignment(TextAlignment.CENTER)
 0140                .SetMarginBottom(10));
 141
 142            // Сортируем заказы: сначала по производителю, затем по артикулу
 0143            var sortedOrders = _orders
 0144                .OrderBy(o => o.EtProducer?.Name ?? "")
 0145                .ThenBy(o => o.Article ?? "")
 0146                .ToList();
 147
 148            // Создаем таблицу с колонками: Номер заказа, Клиент, Наименование товара, Артикул, Производитель, Количеств
 149            // Уменьшаем ширину столбцов "Количество" и "Сумма отправления"
 0150            Table table = new Table(UnitValue.CreatePercentArray(new float[] { 12, 12, 30, 10, 12, 5, 5, 7 }))
 0151                .UseAllAvailableWidth();
 152
 153            // Стиль для заголовков таблицы
 0154            var headerStyle = new Style()
 0155                .SetBackgroundColor(ColorConstants.LIGHT_GRAY)
 0156                .SetPadding(6)
 0157                .SetTextAlignment(TextAlignment.CENTER)
 0158                .SetFont(_boldFont)
 0159                .SetFontSize(9);
 160
 161            // Стиль для ячеек с данными
 0162            var cellStyle = new Style()
 0163                .SetPadding(5)
 0164                .SetTextAlignment(TextAlignment.LEFT)
 0165                .SetFont(_font)
 0166                .SetFontSize(8);
 167
 168            // Заголовки таблицы
 0169            table.AddHeaderCell(new Cell().Add(new Paragraph("Номер заказа")).AddStyle(headerStyle));
 0170            table.AddHeaderCell(new Cell().Add(new Paragraph("Клиент")).AddStyle(headerStyle));
 0171            table.AddHeaderCell(new Cell().Add(new Paragraph("Наименование товара")).AddStyle(headerStyle));
 0172            table.AddHeaderCell(new Cell().Add(new Paragraph("Артикул")).AddStyle(headerStyle));
 0173            table.AddHeaderCell(new Cell().Add(new Paragraph("Производитель")).AddStyle(headerStyle));
 0174            table.AddHeaderCell(new Cell().Add(new Paragraph("Кол.")).AddStyle(headerStyle));
 0175            table.AddHeaderCell(new Cell().Add(new Paragraph("Остаток")).AddStyle(headerStyle));
 0176            table.AddHeaderCell(new Cell().Add(new Paragraph("Сумма")).AddStyle(headerStyle));
 177
 178            // Данные таблицы
 0179            decimal totalAmount = 0;
 0180            int totalQuantity = 0;
 181
 0182            foreach (var order in sortedOrders)
 183            {
 184                // Номер заказа
 0185                table.AddCell(new Cell()
 0186                    .Add(new Paragraph(order.ShipmentNumber ?? ""))
 0187                    .AddStyle(cellStyle));
 188
 189                // Клиент
 0190                var clientName = order.OzonClient?.Name ?? "";
 0191                table.AddCell(new Cell()
 0192                    .Add(new Paragraph(clientName))
 0193                    .AddStyle(cellStyle));
 194
 195                // Наименование товара (ограничить двумя строками)
 0196                var productName = order.ProductName ?? "";
 0197                int maxSymbolsPerLine = 32;
 0198                int maxLines = 2;
 0199                string[] words = productName.Split(' ');
 0200                List<string> lines = new List<string>();
 0201                string currentLine = "";
 0202                foreach (var word in words)
 203                {
 0204                    if ((currentLine + (currentLine.Length > 0 ? " " : "") + word).Length > maxSymbolsPerLine)
 205                    {
 0206                        if (!string.IsNullOrWhiteSpace(currentLine))
 207                        {
 0208                            lines.Add(currentLine);
 0209                            currentLine = word;
 0210                            if (lines.Count == maxLines - 1) break;
 211                        }
 212                    }
 213                    else
 214                    {
 0215                        currentLine += (currentLine.Length > 0 ? " " : "") + word;
 216                    }
 217                }
 0218                if (lines.Count < maxLines && !string.IsNullOrWhiteSpace(currentLine))
 0219                    lines.Add(currentLine);
 0220                string resultProductName = string.Join("\n", lines);
 0221                if (lines.Count == maxLines && words.Length > 0 && (lines[0] + lines[1]).Length < productName.Length)
 0222                    resultProductName = resultProductName.TrimEnd() + "...";
 0223                table.AddCell(new Cell()
 0224                    .Add(new Paragraph(resultProductName))
 0225                    .AddStyle(cellStyle));
 226
 227                // Артикул
 0228                var article = order.Article ?? "";
 0229                table.AddCell(new Cell()
 0230                    .Add(new Paragraph(article))
 0231                    .AddStyle(cellStyle));
 232
 233                // Производитель
 0234                var producerName = order.EtProducer?.Name ?? "";
 0235                table.AddCell(new Cell()
 0236                    .Add(new Paragraph(producerName))
 0237                    .AddStyle(cellStyle));
 238
 239                // Количество
 0240                var quantity = order.Quantity ?? 0;
 0241                totalQuantity += quantity;
 0242                table.AddCell(new Cell()
 0243                    .Add(new Paragraph(quantity.ToString()).SetTextAlignment(TextAlignment.CENTER))
 0244                    .AddStyle(cellStyle));
 245
 246                // Остаток Bitrix
 0247                var stock = 0;
 0248                if (!string.IsNullOrWhiteSpace(order.ProductKey))
 249                {
 0250                    var articleKey = order.ProductKey.Split('=')[0].Trim();
 0251                    if (articleToStock.TryGetValue(articleKey, out var s))
 0252                        stock = s;
 253                }
 0254                table.AddCell(new Cell()
 0255                    .Add(new Paragraph(stock.ToString()).SetTextAlignment(TextAlignment.CENTER))
 0256                    .AddStyle(cellStyle));
 257
 258                // Сумма отправления
 0259                var shipmentAmount = order.ShipmentAmount ?? 0;
 0260                totalAmount += shipmentAmount;
 0261                table.AddCell(new Cell()
 0262                    .Add(new Paragraph(shipmentAmount.ToString("N0")).SetTextAlignment(TextAlignment.RIGHT))
 0263                    .AddStyle(cellStyle));
 264            }
 265
 0266            _document.Add(table);
 267
 268            // Итоговая строка
 0269            _document.Add(new Paragraph(" ")
 0270                .SetMarginTop(10));
 271
 0272            var totalStyle = new Style()
 0273                .SetFont(_boldFont)
 0274                .SetFontSize(10)
 0275                .SetTextAlignment(TextAlignment.RIGHT);
 276
 0277            _document.Add(new Paragraph($"Итого:")
 0278                .SetFont(_boldFont)
 0279                .SetFontSize(10)
 0280                .SetMarginTop(5));
 281
 0282            _document.Add(new Paragraph($"Количество: {totalQuantity}")
 0283                .AddStyle(totalStyle));
 284
 0285            _document.Add(new Paragraph($"Сумма отправления: {totalAmount:N0}")
 0286                .AddStyle(totalStyle));
 287
 0288            _document.Close();
 0289            return _memoryStream.ToArray();
 290        }
 0291        catch (Exception ex)
 292        {
 0293            return CreateFallbackPdf(ex.Message);
 294        }
 0295    }
 296
 297    private byte[] CreateFallbackPdf(string? errorMessage = null)
 298    {
 0299        var fallbackStream = new MemoryStream();
 0300        var fallbackWriter = new PdfWriter(fallbackStream);
 0301        var fallbackPdf = new PdfDocument(fallbackWriter);
 0302        var fallbackDoc = new Document(fallbackPdf);
 303
 0304        fallbackDoc.Add(new Paragraph("Таблица заказов").SetFontSize(16));
 305
 0306        if (!string.IsNullOrEmpty(errorMessage))
 307        {
 0308            fallbackDoc.Add(new Paragraph($"Ошибка: {errorMessage}").SetFontColor(ColorConstants.RED));
 309        }
 310
 0311        fallbackDoc.Close();
 0312        return fallbackStream.ToArray();
 313    }
 314}
 315