fix(s22): 1C-CSV detect charset из Content-Type + UpdatedAt в migration
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
- Parse1cCsv ловил Windows-1251 на UTF-8 bodies без BOM. Теперь смотрит Content-Type charset первым, потом BOM, потом WIN-1251. - Migration Phase22a_OrgExports забыл UpdatedAt колонку (Entity base имеет её). ADD COLUMN IF NOT EXISTS внутри миграции для уже созданных таблиц. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
4c1ac37a08
commit
1af4290313
|
|
@ -574,33 +574,40 @@ public record OneCImportResponse(int Created, int Skipped, IReadOnlyList<CsvImpo
|
||||||
return new OneCImportResponse(v.Created, rows.Count - v.Created, v.Errors, v.Ids);
|
return new OneCImportResponse(v.Created, rows.Count - v.Created, v.Errors, v.Ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Детект кодировки: BOM UTF-8 → utf-8; иначе предполагаем
|
/// <summary>Детект кодировки: 1) Content-Type charset (если указан),
|
||||||
/// Windows-1251 (стандарт 1С). После чтения первых байтов перематываем
|
/// 2) BOM UTF-8 — utf-8, 3) fallback Windows-1251 (стандарт 1С).
|
||||||
/// поток в начало.</summary>
|
/// После чтения первых байтов перематываем поток в начало.</summary>
|
||||||
private static System.Text.Encoding DetectEncoding(Stream s)
|
private System.Text.Encoding DetectEncoding(Stream s)
|
||||||
{
|
{
|
||||||
try
|
try { System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); }
|
||||||
{
|
|
||||||
// Регистрируем codepage providers (Windows-1251 не в default-пуле .NET 8).
|
|
||||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
|
||||||
}
|
|
||||||
catch { /* идемпотентно */ }
|
catch { /* идемпотентно */ }
|
||||||
if (!s.CanSeek)
|
|
||||||
return new System.Text.UTF8Encoding(true);
|
// 1. Content-Type charset.
|
||||||
|
var ct = Request.ContentType;
|
||||||
|
if (!string.IsNullOrEmpty(ct))
|
||||||
|
{
|
||||||
|
var m = System.Text.RegularExpressions.Regex.Match(ct, @"charset=([^;\s]+)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
||||||
|
if (m.Success)
|
||||||
|
{
|
||||||
|
try { return System.Text.Encoding.GetEncoding(m.Groups[1].Value); }
|
||||||
|
catch { /* fall through */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. BOM-based detect.
|
||||||
|
if (s.CanSeek)
|
||||||
|
{
|
||||||
var pos = s.Position;
|
var pos = s.Position;
|
||||||
var buf = new byte[3];
|
var buf = new byte[3];
|
||||||
var n = s.Read(buf, 0, 3);
|
var n = s.Read(buf, 0, 3);
|
||||||
s.Position = pos;
|
s.Position = pos;
|
||||||
if (n >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
|
if (n >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
|
||||||
return System.Text.Encoding.UTF8;
|
return System.Text.Encoding.UTF8;
|
||||||
try
|
|
||||||
{
|
|
||||||
return System.Text.Encoding.GetEncoding("windows-1251");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return System.Text.Encoding.UTF8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. Fallback — Windows-1251 (стандарт 1С).
|
||||||
|
try { return System.Text.Encoding.GetEncoding("windows-1251"); }
|
||||||
|
catch { return System.Text.Encoding.UTF8; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Парсер 1С-CSV → CsvProductRow. Возвращает (rows, errors).
|
/// <summary>Парсер 1С-CSV → CsvProductRow. Возвращает (rows, errors).
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,15 @@ protected override void Up(MigrationBuilder b)
|
||||||
""DownloadTokenExpiresAt"" timestamp with time zone NULL,
|
""DownloadTokenExpiresAt"" timestamp with time zone NULL,
|
||||||
""NotifyEmail"" varchar(200) NULL,
|
""NotifyEmail"" varchar(200) NULL,
|
||||||
""Error"" varchar(2000) NULL,
|
""Error"" varchar(2000) NULL,
|
||||||
""CreatedAt"" timestamp with time zone NOT NULL DEFAULT now()
|
""CreatedAt"" timestamp with time zone NOT NULL DEFAULT now(),
|
||||||
|
""UpdatedAt"" timestamp with time zone NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Идемпотентно — для случая когда таблица уже создана без UpdatedAt
|
||||||
|
-- (миграция была запущена до её добавления в схему).
|
||||||
|
ALTER TABLE public.org_exports
|
||||||
|
ADD COLUMN IF NOT EXISTS ""UpdatedAt"" timestamp with time zone NULL;
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS ""IX_org_exports_Org_CreatedAt""
|
CREATE INDEX IF NOT EXISTS ""IX_org_exports_Org_CreatedAt""
|
||||||
ON public.org_exports (""OrganizationId"", ""CreatedAt"" DESC);
|
ON public.org_exports (""OrganizationId"", ""CreatedAt"" DESC);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS ""IX_org_exports_DownloadToken""
|
CREATE UNIQUE INDEX IF NOT EXISTS ""IX_org_exports_DownloadToken""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue