fix(catalog): widen Article + Barcode.Code to 500 chars for real-world catalogs
Import against a live MoySklad account crashed with PostgreSQL 22001 after loading 21500/~N products: Article column was varchar(100), but some MoySklad items have longer internal codes, and Barcode.Code needed to grow for future GS1 DataMatrix / Честный ЗНАК tracking codes (up to ~300 chars). - EF config: Product.Article 100 → 500, ProductBarcode.Code 100 → 500. - Migration Phase1e_WidenArticleBarcode (applied to dev DB). - Defensive Trim() in the MoySklad importer for Name/Article/Barcode so even future schema drift won't take the whole import down. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
22502c11fd
commit
c47826e015
|
|
@ -126,8 +126,8 @@ await foreach (var p in _client.StreamProductsAsync(token, ct))
|
|||
var product = new Product
|
||||
{
|
||||
OrganizationId = orgId,
|
||||
Name = p.Name,
|
||||
Article = article,
|
||||
Name = Trim(p.Name, 500),
|
||||
Article = Trim(article, 500),
|
||||
Description = p.Description,
|
||||
UnitOfMeasureId = baseUnit.Id,
|
||||
VatRateId = vatId,
|
||||
|
|
@ -197,13 +197,16 @@ private static List<ProductBarcode> ExtractBarcodes(MsProduct p)
|
|||
"upce" => BarcodeType.Upce,
|
||||
_ => BarcodeType.Other,
|
||||
};
|
||||
list.Add(new ProductBarcode { Code = code, Type = type, IsPrimary = !primarySet });
|
||||
list.Add(new ProductBarcode { Code = code.Length > 500 ? code[..500] : code, Type = type, IsPrimary = !primarySet });
|
||||
primarySet = true;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static string? Trim(string? s, int max)
|
||||
=> string.IsNullOrEmpty(s) ? s : (s.Length <= max ? s : s[..max]);
|
||||
|
||||
private static string? TryExtractId(string href)
|
||||
{
|
||||
// href like "https://api.moysklad.ru/api/remap/1.2/entity/productfolder/<guid>"
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ private static void ConfigureProduct(EntityTypeBuilder<Product> b)
|
|||
{
|
||||
b.ToTable("products");
|
||||
b.Property(x => x.Name).HasMaxLength(500).IsRequired();
|
||||
b.Property(x => x.Article).HasMaxLength(100);
|
||||
b.Property(x => x.Article).HasMaxLength(500);
|
||||
b.Property(x => x.MinStock).HasPrecision(18, 4);
|
||||
b.Property(x => x.MaxStock).HasPrecision(18, 4);
|
||||
b.Property(x => x.PurchasePrice).HasPrecision(18, 4);
|
||||
|
|
@ -155,7 +155,8 @@ private static void ConfigureProductPrice(EntityTypeBuilder<ProductPrice> b)
|
|||
private static void ConfigureBarcode(EntityTypeBuilder<ProductBarcode> b)
|
||||
{
|
||||
b.ToTable("product_barcodes");
|
||||
b.Property(x => x.Code).HasMaxLength(100).IsRequired();
|
||||
// Up to 500 to accommodate GS1 DataMatrix / crypto-tail tracking codes (Честный ЗНАК etc.)
|
||||
b.Property(x => x.Code).HasMaxLength(500).IsRequired();
|
||||
b.HasOne(x => x.Product).WithMany(p => p.Barcodes).HasForeignKey(x => x.ProductId).OnDelete(DeleteBehavior.Cascade);
|
||||
b.HasIndex(x => new { x.OrganizationId, x.Code }).IsUnique();
|
||||
}
|
||||
|
|
|
|||
1389
src/food-market.infrastructure/Persistence/Migrations/20260421191122_Phase1e_WidenArticleBarcode.Designer.cs
generated
Normal file
1389
src/food-market.infrastructure/Persistence/Migrations/20260421191122_Phase1e_WidenArticleBarcode.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,64 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace foodmarket.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Phase1e_WidenArticleBarcode : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Article",
|
||||
schema: "public",
|
||||
table: "products",
|
||||
type: "character varying(500)",
|
||||
maxLength: 500,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(100)",
|
||||
oldMaxLength: 100,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Code",
|
||||
schema: "public",
|
||||
table: "product_barcodes",
|
||||
type: "character varying(500)",
|
||||
maxLength: 500,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(100)",
|
||||
oldMaxLength: 100);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Article",
|
||||
schema: "public",
|
||||
table: "products",
|
||||
type: "character varying(100)",
|
||||
maxLength: 100,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(500)",
|
||||
oldMaxLength: 500,
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Code",
|
||||
schema: "public",
|
||||
table: "product_barcodes",
|
||||
type: "character varying(100)",
|
||||
maxLength: 100,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(500)",
|
||||
oldMaxLength: 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -546,8 +546,8 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
|||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Article")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("character varying(500)");
|
||||
|
||||
b.Property<Guid?>("CountryOfOriginId")
|
||||
.HasColumnType("uuid");
|
||||
|
|
@ -648,8 +648,8 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
|||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("character varying(100)");
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("character varying(500)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
|
|
|||
Loading…
Reference in a new issue