refactor: move sourcing_link and standard_cost from item columns to revision properties
- Add migration 013 to copy sourcing_link/standard_cost values into current revision properties JSONB and drop the columns from items table - Remove SourcingLink/StandardCost from Go Item struct and all DB queries (items.go, audit_queries.go, projects.go) - Remove from API request/response structs and handlers - Update CSV/ODS/BOM export/import to read these from revision properties - Update audit handlers to score as regular property fields - Remove from frontend Item type and hardcoded form fields - MainTab now reads sourcing_link/standard_cost from item.properties - CreateItemPane/EditItemPane no longer have dedicated fields for these; they will be rendered as schema-driven property fields
This commit is contained in:
@@ -24,11 +24,9 @@ type Item struct {
|
||||
CADFilePath *string
|
||||
CreatedBy *string
|
||||
UpdatedBy *string
|
||||
SourcingType string // "manufactured" or "purchased"
|
||||
SourcingLink *string // URL to supplier/datasheet
|
||||
LongDescription *string // extended description
|
||||
StandardCost *float64 // baseline unit cost
|
||||
ThumbnailKey *string // MinIO key for item thumbnail
|
||||
SourcingType string // "manufactured" or "purchased"
|
||||
LongDescription *string // extended description
|
||||
ThumbnailKey *string // MinIO key for item thumbnail
|
||||
}
|
||||
|
||||
// Revision represents a revision record.
|
||||
@@ -96,11 +94,11 @@ func (r *ItemRepository) Create(ctx context.Context, item *Item, properties map[
|
||||
}
|
||||
err := tx.QueryRow(ctx, `
|
||||
INSERT INTO items (part_number, schema_id, item_type, description, created_by,
|
||||
sourcing_type, sourcing_link, long_description, standard_cost)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
sourcing_type, long_description)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, created_at, updated_at, current_revision
|
||||
`, item.PartNumber, item.SchemaID, item.ItemType, item.Description, item.CreatedBy,
|
||||
sourcingType, item.SourcingLink, item.LongDescription, item.StandardCost,
|
||||
sourcingType, item.LongDescription,
|
||||
).Scan(
|
||||
&item.ID, &item.CreatedAt, &item.UpdatedAt, &item.CurrentRevision,
|
||||
)
|
||||
@@ -133,7 +131,7 @@ func (r *ItemRepository) GetByPartNumber(ctx context.Context, partNumber string)
|
||||
SELECT id, part_number, schema_id, item_type, description,
|
||||
created_at, updated_at, archived_at, current_revision,
|
||||
cad_synced_at, cad_file_path,
|
||||
sourcing_type, sourcing_link, long_description, standard_cost,
|
||||
sourcing_type, long_description,
|
||||
thumbnail_key
|
||||
FROM items
|
||||
WHERE part_number = $1 AND archived_at IS NULL
|
||||
@@ -141,7 +139,7 @@ func (r *ItemRepository) GetByPartNumber(ctx context.Context, partNumber string)
|
||||
&item.ID, &item.PartNumber, &item.SchemaID, &item.ItemType, &item.Description,
|
||||
&item.CreatedAt, &item.UpdatedAt, &item.ArchivedAt, &item.CurrentRevision,
|
||||
&item.CADSyncedAt, &item.CADFilePath,
|
||||
&item.SourcingType, &item.SourcingLink, &item.LongDescription, &item.StandardCost,
|
||||
&item.SourcingType, &item.LongDescription,
|
||||
&item.ThumbnailKey,
|
||||
)
|
||||
if err == pgx.ErrNoRows {
|
||||
@@ -160,7 +158,7 @@ func (r *ItemRepository) GetByID(ctx context.Context, id string) (*Item, error)
|
||||
SELECT id, part_number, schema_id, item_type, description,
|
||||
created_at, updated_at, archived_at, current_revision,
|
||||
cad_synced_at, cad_file_path,
|
||||
sourcing_type, sourcing_link, long_description, standard_cost,
|
||||
sourcing_type, long_description,
|
||||
thumbnail_key
|
||||
FROM items
|
||||
WHERE id = $1
|
||||
@@ -168,7 +166,7 @@ func (r *ItemRepository) GetByID(ctx context.Context, id string) (*Item, error)
|
||||
&item.ID, &item.PartNumber, &item.SchemaID, &item.ItemType, &item.Description,
|
||||
&item.CreatedAt, &item.UpdatedAt, &item.ArchivedAt, &item.CurrentRevision,
|
||||
&item.CADSyncedAt, &item.CADFilePath,
|
||||
&item.SourcingType, &item.SourcingLink, &item.LongDescription, &item.StandardCost,
|
||||
&item.SourcingType, &item.LongDescription,
|
||||
&item.ThumbnailKey,
|
||||
)
|
||||
if err == pgx.ErrNoRows {
|
||||
@@ -192,7 +190,7 @@ func (r *ItemRepository) List(ctx context.Context, opts ListOptions) ([]*Item, e
|
||||
query = `
|
||||
SELECT DISTINCT i.id, i.part_number, i.schema_id, i.item_type, i.description,
|
||||
i.created_at, i.updated_at, i.archived_at, i.current_revision,
|
||||
i.sourcing_type, i.sourcing_link, i.long_description, i.standard_cost,
|
||||
i.sourcing_type, i.long_description,
|
||||
i.thumbnail_key
|
||||
FROM items i
|
||||
JOIN item_projects ip ON ip.item_id = i.id
|
||||
@@ -205,7 +203,7 @@ func (r *ItemRepository) List(ctx context.Context, opts ListOptions) ([]*Item, e
|
||||
query = `
|
||||
SELECT id, part_number, schema_id, item_type, description,
|
||||
created_at, updated_at, archived_at, current_revision,
|
||||
sourcing_type, sourcing_link, long_description, standard_cost,
|
||||
sourcing_type, long_description,
|
||||
thumbnail_key
|
||||
FROM items
|
||||
WHERE archived_at IS NULL
|
||||
@@ -257,7 +255,7 @@ func (r *ItemRepository) List(ctx context.Context, opts ListOptions) ([]*Item, e
|
||||
err := rows.Scan(
|
||||
&item.ID, &item.PartNumber, &item.SchemaID, &item.ItemType, &item.Description,
|
||||
&item.CreatedAt, &item.UpdatedAt, &item.ArchivedAt, &item.CurrentRevision,
|
||||
&item.SourcingType, &item.SourcingLink, &item.LongDescription, &item.StandardCost,
|
||||
&item.SourcingType, &item.LongDescription,
|
||||
&item.ThumbnailKey,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -659,9 +657,7 @@ type UpdateItemFields struct {
|
||||
Description string
|
||||
UpdatedBy *string
|
||||
SourcingType *string
|
||||
SourcingLink *string
|
||||
LongDescription *string
|
||||
StandardCost *float64
|
||||
}
|
||||
|
||||
// Update modifies an item's fields. The UUID remains stable.
|
||||
@@ -670,16 +666,12 @@ func (r *ItemRepository) Update(ctx context.Context, id string, fields UpdateIte
|
||||
UPDATE items
|
||||
SET part_number = $2, item_type = $3, description = $4, updated_by = $5,
|
||||
sourcing_type = COALESCE($6, sourcing_type),
|
||||
sourcing_link = CASE WHEN $7::boolean THEN $8 ELSE sourcing_link END,
|
||||
long_description = CASE WHEN $9::boolean THEN $10 ELSE long_description END,
|
||||
standard_cost = CASE WHEN $11::boolean THEN $12 ELSE standard_cost END,
|
||||
long_description = CASE WHEN $7::boolean THEN $8 ELSE long_description END,
|
||||
updated_at = now()
|
||||
WHERE id = $1 AND archived_at IS NULL
|
||||
`, id, fields.PartNumber, fields.ItemType, fields.Description, fields.UpdatedBy,
|
||||
fields.SourcingType,
|
||||
fields.SourcingLink != nil, fields.SourcingLink,
|
||||
fields.LongDescription != nil, fields.LongDescription,
|
||||
fields.StandardCost != nil, fields.StandardCost,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("updating item: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user