mirror of
https://github.com/Sea-Haven-Industries/proposal-system.git
synced 2026-10-07 09:19:04 +00:00
Adds a managed pricing library so admins can seed/curate reference priced items
directly, instead of the corpus being populated only by ingesting Sent proposals.
v1 PR5.
API:
- PricingLibraryItem entity + migration; /api/pricing-library CRUD (admin), with
GET {id} reachable by internal Lambda callers (admins role via internal key).
- Create/update publish an ADDITIVE library-ingest SQS job {pricingLibraryItemId},
wrapped so a publish failure never rolls back the save.
Lambda (library-ingest):
- Additive event-shape branch: pricingLibraryItemId -> fetch item, format markdown,
upload to pricing-library/{category}/{id}.md, trigger KB sync. The existing
proposalId path is byte-for-byte unchanged. Explicit error when neither id present;
warns when both present.
Web:
- Pricing Library management page (/admin/pricing-library): list / create / edit / delete.
GPT-4.1 cross-review on the event-shape change: no BLOCK (neither/both-id handling
applied). Verified: api 159 tests; web tsc + 26 tests; lambdas ruff + 37 pytest.
552 lines
19 KiB
C#
552 lines
19 KiB
C#
// <auto-generated />
|
|
using System;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
using ProposalSystem.Infrastructure.Data;
|
|
|
|
#nullable disable
|
|
|
|
namespace ProposalSystem.Infrastructure.Data.Migrations
|
|
{
|
|
[DbContext(typeof(ProposalDbContext))]
|
|
[Migration("20260612225458_AddPricingLibrary")]
|
|
partial class AddPricingLibrary
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
{
|
|
#pragma warning disable 612, 618
|
|
modelBuilder
|
|
.HasAnnotation("ProductVersion", "8.0.27")
|
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
|
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.AuditLog", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Action")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Details")
|
|
.HasColumnType("jsonb");
|
|
|
|
b.Property<string>("IpAddress")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<Guid?>("ProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("Timestamp")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid>("UserId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("ProposalId");
|
|
|
|
b.HasIndex("Timestamp");
|
|
|
|
b.HasIndex("UserId");
|
|
|
|
b.ToTable("AuditLogs");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.Customer", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("Addresses")
|
|
.HasColumnType("jsonb");
|
|
|
|
b.Property<string>("ContactEmail")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime>("CreatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("Name")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime>("UpdatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.ToTable("Customers");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.GeneratedPdf", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("GeneratedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid>("GeneratedById")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<Guid>("ProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<int>("Revision")
|
|
.HasColumnType("integer");
|
|
|
|
b.Property<string>("S3Key")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("GeneratedById");
|
|
|
|
b.HasIndex("ProposalId");
|
|
|
|
b.ToTable("GeneratedPdfs");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.LineItem", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("CreatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("Description")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("PricingMode")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<Guid>("ProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<decimal>("Quantity")
|
|
.HasPrecision(18, 4)
|
|
.HasColumnType("numeric(18,4)");
|
|
|
|
b.Property<int>("SortOrder")
|
|
.HasColumnType("integer");
|
|
|
|
b.Property<string>("Source")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<decimal>("TotalPrice")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<string>("Unit")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<decimal?>("UnitPrice")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<DateTime>("UpdatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("ProposalId");
|
|
|
|
b.ToTable("LineItems");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.PricingLibraryItem", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("CreatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("Description")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Keywords")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("ServiceCategory")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Source")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Title")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Unit")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<decimal?>("UnitPrice")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<DateTime>("UpdatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.ToTable("PricingLibraryItems");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.Proposal", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime?>("ApprovedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid?>("ApprovedById")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<Guid?>("AssignedAdminId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("CreatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<int>("CurrentRevision")
|
|
.HasColumnType("integer");
|
|
|
|
b.Property<string>("CustomerAddress")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("CustomerName")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Notes")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<Guid?>("ParentProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("PoNumber")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Priority")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("ProposalNumber")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("RefinedScope")
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("ScopeOfWork")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime?>("SentAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("ServiceCategory")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Status")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime>("SubmittedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid>("SubmittedById")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<decimal>("TotalBidAmount")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<DateTime>("UpdatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<decimal?>("VendorTotalCost")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<string>("WorkOrderNumber")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("ApprovedById");
|
|
|
|
b.HasIndex("AssignedAdminId");
|
|
|
|
b.HasIndex("ParentProposalId");
|
|
|
|
b.HasIndex("ProposalNumber")
|
|
.IsUnique();
|
|
|
|
b.HasIndex("SubmittedById");
|
|
|
|
b.ToTable("Proposals");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.SimilarProposalReference", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<Guid>("ProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<DateTime>("ReferencedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<Guid>("ReferencedById")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("ReferencedLibraryItemId")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<float>("SimilarityScore")
|
|
.HasColumnType("real");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("ProposalId");
|
|
|
|
b.HasIndex("ReferencedById");
|
|
|
|
b.ToTable("SimilarProposalReferences");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.User", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("CognitoSub")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime>("CreatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("DisplayName")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("Email")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<bool>("IsActive")
|
|
.HasColumnType("boolean");
|
|
|
|
b.Property<string>("Role")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<DateTime>("UpdatedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("CognitoSub")
|
|
.IsUnique();
|
|
|
|
b.HasIndex("Email")
|
|
.IsUnique();
|
|
|
|
b.ToTable("Users");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.VendorProposal", b =>
|
|
{
|
|
b.Property<Guid>("Id")
|
|
.ValueGeneratedOnAdd()
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("ExtractedData")
|
|
.HasColumnType("jsonb");
|
|
|
|
b.Property<string>("FileName")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<string>("ProcessingStatus")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<Guid>("ProposalId")
|
|
.HasColumnType("uuid");
|
|
|
|
b.Property<string>("S3Key")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.Property<decimal>("TotalVendorCost")
|
|
.HasPrecision(18, 2)
|
|
.HasColumnType("numeric(18,2)");
|
|
|
|
b.Property<DateTime>("UploadedAt")
|
|
.HasColumnType("timestamp with time zone");
|
|
|
|
b.Property<string>("VendorName")
|
|
.IsRequired()
|
|
.HasColumnType("text");
|
|
|
|
b.HasKey("Id");
|
|
|
|
b.HasIndex("ProposalId");
|
|
|
|
b.ToTable("VendorProposals");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.AuditLog", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "Proposal")
|
|
.WithMany()
|
|
.HasForeignKey("ProposalId");
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "User")
|
|
.WithMany()
|
|
.HasForeignKey("UserId")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.Navigation("Proposal");
|
|
|
|
b.Navigation("User");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.GeneratedPdf", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "GeneratedBy")
|
|
.WithMany()
|
|
.HasForeignKey("GeneratedById")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "Proposal")
|
|
.WithMany()
|
|
.HasForeignKey("ProposalId")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.Navigation("GeneratedBy");
|
|
|
|
b.Navigation("Proposal");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.LineItem", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "Proposal")
|
|
.WithMany("LineItems")
|
|
.HasForeignKey("ProposalId")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.Navigation("Proposal");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.Proposal", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "ApprovedBy")
|
|
.WithMany()
|
|
.HasForeignKey("ApprovedById")
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "AssignedAdmin")
|
|
.WithMany()
|
|
.HasForeignKey("AssignedAdminId")
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "ParentProposal")
|
|
.WithMany()
|
|
.HasForeignKey("ParentProposalId")
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "SubmittedBy")
|
|
.WithMany()
|
|
.HasForeignKey("SubmittedById")
|
|
.OnDelete(DeleteBehavior.Restrict)
|
|
.IsRequired();
|
|
|
|
b.Navigation("ApprovedBy");
|
|
|
|
b.Navigation("AssignedAdmin");
|
|
|
|
b.Navigation("ParentProposal");
|
|
|
|
b.Navigation("SubmittedBy");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.SimilarProposalReference", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "Proposal")
|
|
.WithMany()
|
|
.HasForeignKey("ProposalId")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.HasOne("ProposalSystem.Domain.Entities.User", "ReferencedBy")
|
|
.WithMany()
|
|
.HasForeignKey("ReferencedById")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.Navigation("Proposal");
|
|
|
|
b.Navigation("ReferencedBy");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.VendorProposal", b =>
|
|
{
|
|
b.HasOne("ProposalSystem.Domain.Entities.Proposal", "Proposal")
|
|
.WithMany("VendorProposals")
|
|
.HasForeignKey("ProposalId")
|
|
.OnDelete(DeleteBehavior.Cascade)
|
|
.IsRequired();
|
|
|
|
b.Navigation("Proposal");
|
|
});
|
|
|
|
modelBuilder.Entity("ProposalSystem.Domain.Entities.Proposal", b =>
|
|
{
|
|
b.Navigation("LineItems");
|
|
|
|
b.Navigation("VendorProposals");
|
|
});
|
|
#pragma warning restore 612, 618
|
|
}
|
|
}
|
|
}
|