Skip to content

BOM backend continuation: BOM Items CRUD, circular reference guard, single-active BOM enforcement, and new API controllers#45

Open
SashaCoder wants to merge 4 commits intogo2ismail:ASP.NET-9.0from
SashaCoder:add_bom
Open

BOM backend continuation: BOM Items CRUD, circular reference guard, single-active BOM enforcement, and new API controllers#45
SashaCoder wants to merge 4 commits intogo2ismail:ASP.NET-9.0from
SashaCoder:add_bom

Conversation

@SashaCoder
Copy link
Copy Markdown

Summary
This PR continues the Bill of Materials (BOM) implementation per the Technical Implementation Plan. It introduces a circular reference guard for component hierarchies, completes CRUD for BOM Items, enforces the single-active-BOM-per-product rule, and exposes new API endpoints for BOM and BOM Items. These changes align with the plan and integrate cleanly with the existing Application/Infrastructure patterns.

Context

Scope of changes
Added

  • Application
    • Core/Application/Features/BillOfMaterialManager/BillOfMaterialService.cs
      • ValidateCircularReferenceAsync to detect cycles between a parent product and a candidate component using a visited set and recursive traversal of active BOMs.
    • BOM Item features (Core/Application/Features/BillOfMaterialItemManager)
      • Commands:
        • CreateBillOfMaterialItem.cs
          • Validates BOM and component existence.
          • Prevents circular references using BillOfMaterialService.
          • Auto-increments sequence if not provided.
        • UpdateBillOfMaterialItem.cs
        • DeleteBillOfMaterialItem.cs
      • Queries:
        • GetBillOfMaterialItemList.cs (includes component product and unit measure fields; orders by Sequence)
  • Presentation (API)
    • Presentation/ASPNET/BackEnd/Controllers/BillOfMaterialController.cs
      • Endpoints: Create, Update, Delete, GetBillOfMaterialList, GetBillOfMaterialByProduct, GetBillOfMaterialExplosion
    • Presentation/ASPNET/BackEnd/Controllers/BillOfMaterialItemController.cs
      • Endpoints: CreateBillOfMaterialItem, UpdateBillOfMaterialItem, DeleteBillOfMaterialItem, GetBillOfMaterialItemList

Changed

  • Application/BOM command handlers:
    • CreateBillOfMaterial
      • Enforces only one active BOM per product by deactivating other active BOMs on create when IsActive == true.
      • Sets Product.HasBOM = true when creating the first BOM for a product.
    • UpdateBillOfMaterial
      • When setting IsActive == true, deactivates any other active BOMs for the same product.
    • DeleteBillOfMaterial
      • After soft-deleting a BOM, unsets Product.HasBOM if no other non-deleted BOMs exist for that product.

Not in this PR (deferred)

  • Frontend pages (BOM list, BOM item editor, BOM explosion).
  • Navigation menu entries for BOM modules.
  • Demo seeders for multi-level BOMs (BillOfMaterialSeeder, BillOfMaterialItemSeeder).
  • Copy/versioning workflow for BOMs.
  • Test projects and automated tests.

API overview

  • BillOfMaterialController (all endpoints [Authorize])
    • POST api/BillOfMaterial/CreateBillOfMaterial
      • Body: { ProductId, Name, Version?, Description?, IsActive?, EffectiveFrom?, EffectiveTo?, CreatedById? }
    • POST api/BillOfMaterial/UpdateBillOfMaterial
      • Body: { Id, Name?, Version?, Description?, IsActive?, EffectiveFrom?, EffectiveTo?, UpdatedById? }
    • POST api/BillOfMaterial/DeleteBillOfMaterial
      • Body: { Id, DeletedById? }
    • GET api/BillOfMaterial/GetBillOfMaterialList?isDeleted=false&productId={id?}&isActive={true|false|null}
    • GET api/BillOfMaterial/GetBillOfMaterialByProduct?productId={id}&getActiveOnly=true
    • GET api/BillOfMaterial/GetBillOfMaterialExplosion?productId={id}&quantity=1
  • BillOfMaterialItemController (all endpoints [Authorize])
    • POST api/BillOfMaterialItem/CreateBillOfMaterialItem
      • Body: { BillOfMaterialId, ComponentProductId, Quantity>0, Sequence?, UnitMeasureId?, ScrapPercentage 0..100?, Notes?, CreatedById? }
    • POST api/BillOfMaterialItem/UpdateBillOfMaterialItem
      • Body: { Id, Quantity>0?, Sequence?, UnitMeasureId?, ScrapPercentage 0..100?, Notes?, UpdatedById? }
    • POST api/BillOfMaterialItem/DeleteBillOfMaterialItem
      • Body: { Id, DeletedById? }
    • GET api/BillOfMaterialItem/GetBillOfMaterialItemList?billOfMaterialId={id}

Business rules enforced

  • Single active BOM per product:
    • On create or update when IsActive is true, other active BOMs for the same product are deactivated.
  • Product.HasBOM lifecycle:
    • Set to true on first BOM creation for a product.
    • Set to false when the last BOM for the product is deleted.
  • No circular references:
    • Creating a BOM Item is blocked if it would create a cycle (direct or indirect) in product-component relationships.

Validation

  • FluentValidation rules on BOM Item commands:
    • Required IDs (BOM, component).
    • Quantity > 0.
    • ScrapPercentage 0–100 inclusive.

Performance considerations

  • Read-side queries use AsNoTracking and Include only required navigation properties.
  • Circular reference validation uses a visited set to prevent repeated traversal; complexity proportional to depth/width of the active BOM graph.
  • Explosion query remains source of truth for recursive material breakdown and cost calculation.

Security

  • All new endpoints are protected with [Authorize].
  • No changes to auth config.

Database/migration impact

  • No new tables or migrations introduced in this PR.
  • Relies on existing configurations and relationships for BOM and BOM Items.

Backward compatibility

  • Non-breaking API addition; existing modules unaffected.
  • Product.HasBOM may flip to false if a product’s last BOM is deleted (consistent with plan).

Testing notes and scenarios

  • Create a product P1 and multiple components Cx, ensure they exist.
  • Create BOM B1 for P1 with IsActive = true.
  • Add items referencing Cx; verify sequence auto-increments when not provided.
  • Attempt to add P1 as a component under its own tree; expect validation error for circular reference.
  • Create BOM B2 for P1 with IsActive = true; verify B1 becomes IsActive = false.
  • Delete the only remaining BOM for P1; verify Product.HasBOM becomes false.
  • Run GetBillOfMaterialExplosion for P1 and verify the multi-level explosion and cost sums.

Known limitations

  • No UI pages/menu updates included yet.
  • No seed data for BOMs; manual setup may be required for local testing.
  • No automated tests included in this PR.

Risk and rollback

  • Risk: Logic for deactivating other active BOMs executes within the same unit of work; unintended side effects are minimal but should be reviewed.
  • Rollback: Revert added controllers and Application handlers/service; revert modifications in BOM command handlers.

Changelog

  • Add: BillOfMaterialService with circular-reference guard.
  • Add: BOM Item commands and query.
  • Add: BillOfMaterial and BillOfMaterialItem API controllers.
  • Change: Enforce single active BOM and sync Product.HasBOM toggling in BOM command handlers.

Housekeeping

  • Ensure any tmp_rovodev_* files are not committed; they are local artifacts from plan review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant