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
|
var product = new Product
|
||||||
{
|
{
|
||||||
OrganizationId = orgId,
|
OrganizationId = orgId,
|
||||||
Name = p.Name,
|
Name = Trim(p.Name, 500),
|
||||||
Article = article,
|
Article = Trim(article, 500),
|
||||||
Description = p.Description,
|
Description = p.Description,
|
||||||
UnitOfMeasureId = baseUnit.Id,
|
UnitOfMeasureId = baseUnit.Id,
|
||||||
VatRateId = vatId,
|
VatRateId = vatId,
|
||||||
|
|
@ -197,13 +197,16 @@ private static List<ProductBarcode> ExtractBarcodes(MsProduct p)
|
||||||
"upce" => BarcodeType.Upce,
|
"upce" => BarcodeType.Upce,
|
||||||
_ => BarcodeType.Other,
|
_ => 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;
|
primarySet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
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)
|
private static string? TryExtractId(string href)
|
||||||
{
|
{
|
||||||
// href like "https://api.moysklad.ru/api/remap/1.2/entity/productfolder/<guid>"
|
// 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.ToTable("products");
|
||||||
b.Property(x => x.Name).HasMaxLength(500).IsRequired();
|
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.MinStock).HasPrecision(18, 4);
|
||||||
b.Property(x => x.MaxStock).HasPrecision(18, 4);
|
b.Property(x => x.MaxStock).HasPrecision(18, 4);
|
||||||
b.Property(x => x.PurchasePrice).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)
|
private static void ConfigureBarcode(EntityTypeBuilder<ProductBarcode> b)
|
||||||
{
|
{
|
||||||
b.ToTable("product_barcodes");
|
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.HasOne(x => x.Product).WithMany(p => p.Barcodes).HasForeignKey(x => x.ProductId).OnDelete(DeleteBehavior.Cascade);
|
||||||
b.HasIndex(x => new { x.OrganizationId, x.Code }).IsUnique();
|
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");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
b.Property<string>("Article")
|
b.Property<string>("Article")
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(500)
|
||||||
.HasColumnType("character varying(100)");
|
.HasColumnType("character varying(500)");
|
||||||
|
|
||||||
b.Property<Guid?>("CountryOfOriginId")
|
b.Property<Guid?>("CountryOfOriginId")
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
@ -648,8 +648,8 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
|
||||||
b.Property<string>("Code")
|
b.Property<string>("Code")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(500)
|
||||||
.HasColumnType("character varying(100)");
|
.HasColumnType("character varying(500)");
|
||||||
|
|
||||||
b.Property<DateTime>("CreatedAt")
|
b.Property<DateTime>("CreatedAt")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue