Files
declaratrions-automatization/DeclarationAutomatization/Services/Sheet1ImportService.cs
T
Dianaka123 697ae44519 feat: единый файл Лист1+СПРАВКА, фильтры, сортировка, живой п/п
- Загрузка одного .xlsx (СПРАВКА + Лист1 в одном файле)
- Рег. номера берутся из СПРАВКА автоматически, группируются по (ТН ВЭД, Страна)
- Отдельный опциональный справочник кодов (CodesImportService)
- Фильтры: Все / Авто / Проверить / Нет кода / Без нетто
- Таблица сразу отсортирована по ТН ВЭД с живым обновлением п/п
- Начальный п/п: поле в UI, автоинкремент после экспорта
- Лист2: рамки, жёлтая строка при >1 рег. номере, итого по кол-ву
- Лист3: ТН ВЭД в колонке B вместо константы 09035
- Красный ErrorMessage под кнопкой загрузки, удалён SpravkaFileEntry
2026-04-07 11:47:31 +03:00

121 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using ClosedXML.Excel;
using DeclarationAutomatization.Models;
namespace DeclarationAutomatization.Services;
public class Sheet1ImportService
{
private const string SheetName = "Лист1";
private const string ItogoMarker = "ИТОГО";
public List<Sheet1Group> ReadSheet1(string filePath)
{
using var workbook = new XLWorkbook(filePath);
IXLWorksheet? sheet = null;
foreach (var ws in workbook.Worksheets)
{
if (ws.Name.Equals(SheetName, StringComparison.OrdinalIgnoreCase))
{ sheet = ws; break; }
}
if (sheet == null)
throw new InvalidOperationException($"Лист '{SheetName}' не найден в файле: {filePath}");
var groups = new List<Sheet1Group>();
int sequentialNumber = 1;
int lastRow = sheet.LastRowUsed()?.RowNumber() ?? 1;
for (int r = 1; r <= lastRow; r++)
{
var row = sheet.Row(r);
if (!IsItogoRow(row)) continue;
var group = BuildGroup(row, sequentialNumber);
if (group != null)
{
groups.Add(group);
sequentialNumber++;
}
}
return groups;
}
private static bool IsItogoRow(IXLRow row)
{
foreach (var cell in row.CellsUsed())
{
if (cell.GetString().Contains(ItogoMarker, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
private static Sheet1Group? BuildGroup(IXLRow row, int sequentialNumber)
{
string tnVed = FindTnVed(row);
if (string.IsNullOrWhiteSpace(tnVed)) return null;
string description = row.Cell(2).GetString().Trim();
if (string.IsNullOrWhiteSpace(description))
description = row.Cell(3).GetString().Trim();
string countryId = FindCountryId(row);
decimal qty = ParseDecimal(row.Cell(9));
decimal amount = ParseDecimal(row.Cell(10));
decimal gross = ParseDecimal(row.Cell(11));
decimal net = ParseDecimal(row.Cell(12));
return new Sheet1Group
{
SequentialNumber = sequentialNumber,
Description = description,
TnVed = tnVed,
CountryId = countryId,
Quantity = qty,
AmountWithVat = amount,
GrossWeight = gross,
NetWeight = net,
};
}
private static string FindTnVed(IXLRow row)
{
foreach (var cell in row.CellsUsed())
{
var val = cell.GetString().Trim();
if (Regex.IsMatch(val, @"^\d{10}$"))
return val;
}
return "";
}
private static string FindCountryId(IXLRow row)
{
foreach (var cell in row.CellsUsed())
{
var val = cell.GetString().Trim();
if (Regex.IsMatch(val, @"^[A-Z]{2}$"))
return val;
}
return "";
}
private static decimal ParseDecimal(IXLCell cell)
{
if (cell.IsEmpty()) return 0;
try
{
var val = cell.GetString().Trim().Replace(',', '.');
return decimal.TryParse(val, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out var d) ? d : 0;
}
catch { return 0; }
}
}