972123c7a2
Three bugs fixed: 1. Wrong timing — inventory items with IsIncoming=true were auto-created during quote save (in QuotePricingAssemblyService). Now deferred to quote approval so inventory only reflects powders the shop is actually going to process. 2. Duplicate records — same powder on multiple items in one quote created multiple inventory records. Now grouped by PowderCatalogItemId: one record per unique catalog powder, all matching coats linked to the same record. 3. Wrong category — category resolution used first IsCoating=true by DisplayOrder, which could land items in Cerakote or other unintended categories. Now prefers CategoryCode==POWDER explicitly, with DisplayOrder fallback. Changes: - QuoteItemCoat: add PowderCatalogItemId int? — persists catalog reference at quote save time so the approval path knows what to create - QuotePricingAssemblyService.BuildQuoteItemCoatsAsync: store PowderCatalogItemId on coat instead of calling CreateIncomingInventoryItemAsync immediately - QuotePricingAssemblyService.CreateIncomingInventoryItemAsync: signature changed from (coatDto, companyId) to (catalogItemId, companyId); category lookup prefers POWDER code; no longer clears PowderCostPerLb on the DTO - QuotePricingAssemblyService.EnsureIncomingInventoryForApprovedQuoteAsync: new public method called at approval — loads pending coats, groups by catalog ID, creates one inventory item per group, links all coats in each group - IQuotePricingAssemblyService: exposes EnsureIncomingInventoryForApprovedQuoteAsync - QuotesController.ApproveQuote: calls EnsureIncomingInventory after save - QuotesController.ChangeQuoteStatus: calls EnsureIncomingInventory on Approved - QuoteApprovalController: injects IQuotePricingAssemblyService; calls EnsureIncomingInventory in ApproveInternal (customer-facing portal path) - InventoryController.CreateIncomingFromCatalog: same category fix (prefers POWDER) - Migration: AddPowderCatalogItemIdToCoat (nullable int on QuoteItemCoats) - Tests: updated AddAsIncoming test to verify deferred behavior; new deduplication test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
25 lines
962 B
C#
25 lines
962 B
C#
using PowderCoating.Application.DTOs.Quote;
|
|
using PowderCoating.Core.Entities;
|
|
|
|
namespace PowderCoating.Application.Interfaces;
|
|
|
|
public interface IQuotePricingAssemblyService
|
|
{
|
|
void ApplyPricingSnapshot(Quote quote, QuotePricingResult pricingResult);
|
|
|
|
Task<IReadOnlyList<QuoteItem>> CreateQuoteItemsAsync(
|
|
IEnumerable<CreateQuoteItemDto> itemDtos,
|
|
int quoteId,
|
|
int companyId,
|
|
decimal? ovenRateOverride,
|
|
DateTime createdAtUtc);
|
|
|
|
/// <summary>
|
|
/// Creates one <see cref="InventoryItem"/> (IsIncoming=true) per unique powder catalog entry
|
|
/// referenced by coats on the given quote, then links those coats to the new inventory records.
|
|
/// Must be called after a quote transitions to Approved status.
|
|
/// Safe to call multiple times — coats that already have an InventoryItemId are skipped.
|
|
/// </summary>
|
|
Task EnsureIncomingInventoryForApprovedQuoteAsync(int quoteId, int companyId);
|
|
}
|