diff --git a/Distribution/Migrations/20260916083241_AddOrderInvoiceLifecycle.cs b/Distribution/Migrations/20260916083241_AddOrderInvoiceLifecycle.cs new file mode 100644 index 0000000..bee5750 --- /dev/null +++ b/Distribution/Migrations/20260916083241_AddOrderInvoiceLifecycle.cs @@ -0,0 +1,306 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace Distribution.Migrations +{ + /// + public partial class AddOrderInvoiceLifecycle : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // Must run before DropPrimaryKey below: OrderItems.FK_OrderId has a foreign key to + // Orders, and MySQL requires a supporting index on that column at all times. The old + // composite PK (FK_OrderId, FK_ItemId) was providing that support; without this index + // created first, dropping the PK leaves FK_OrderId's constraint without an index and + // MySQL rejects the DROP PRIMARY KEY (errno 150). + migrationBuilder.CreateIndex( + name: "IX_OrderItems_FK_OrderId", + table: "OrderItems", + column: "FK_OrderId"); + + migrationBuilder.DropPrimaryKey( + name: "PK_OrderItems", + table: "OrderItems"); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumns: new[] { "FK_ItemId", "FK_OrderId" }, + keyValues: new object[] { new Guid("23000000-0000-0000-0000-000000000001"), new Guid("33000000-0000-0000-0000-000000000001") }); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumns: new[] { "FK_ItemId", "FK_OrderId" }, + keyValues: new object[] { new Guid("23000000-0000-0000-0000-000000000003"), new Guid("33000000-0000-0000-0000-000000000001") }); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumns: new[] { "FK_ItemId", "FK_OrderId" }, + keyValues: new object[] { new Guid("23000000-0000-0000-0000-000000000002"), new Guid("33000000-0000-0000-0000-000000000002") }); + + migrationBuilder.AlterColumn( + name: "FK_SaleId", + table: "Orders", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci", + oldClrType: typeof(Guid), + oldType: "char(36)") + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "ConfirmedAt", + table: "Orders", + type: "datetime(6)", + nullable: true); + + migrationBuilder.AddColumn( + name: "ConfirmedByUserId", + table: "Orders", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.AddColumn( + name: "CreatedByUserId", + table: "Orders", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci"); + + // Backfill every existing Order's new CreatedByUserId from its linked Sale (Order.FK_SaleId + // was required until this migration, so every pre-existing row has one). Covers every + // row generically, not just the two rows seeded via HasData below — otherwise any Order + // created outside the EF seed data would keep the temporary AddColumn default + // (Guid.Empty) and fail the FK_Orders_Users_CreatedByUserId constraint added at the end + // of this migration. + migrationBuilder.Sql(@" + UPDATE `Orders` o + INNER JOIN `Sales` s ON s.`Id` = o.`FK_SaleId` + SET o.`CreatedByUserId` = s.`CreatedByUserId` + WHERE o.`FK_SaleId` IS NOT NULL;"); + + migrationBuilder.AddColumn( + name: "InvoiceId", + table: "Orders", + type: "char(36)", + nullable: true, + collation: "ascii_general_ci"); + + migrationBuilder.AddPrimaryKey( + name: "PK_OrderItems", + table: "OrderItems", + column: "Id"); + + migrationBuilder.CreateTable( + name: "Invoices", + columns: table => new + { + Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + FK_OrderId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + Status = table.Column(type: "int", nullable: false), + CreatedByUserId = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), + PrintedAt = table.Column(type: "datetime(6)", nullable: true), + PrintedByUserId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + FinalizedAt = table.Column(type: "datetime(6)", nullable: true), + FinalizedByUserId = table.Column(type: "char(36)", nullable: true, collation: "ascii_general_ci"), + TotalAmount = table.Column(type: "decimal(65,30)", nullable: false), + CreatedAt = table.Column(type: "datetime(6)", nullable: false), + IsActive = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Invoices", x => x.Id); + table.ForeignKey( + name: "FK_Invoices_Orders_FK_OrderId", + column: x => x.FK_OrderId, + principalTable: "Orders", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Invoices_Users_CreatedByUserId", + column: x => x.CreatedByUserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Invoices_Users_FinalizedByUserId", + column: x => x.FinalizedByUserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Invoices_Users_PrintedByUserId", + column: x => x.PrintedByUserId, + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.InsertData( + table: "OrderItems", + columns: new[] { "Id", "CreatedAt", "FK_ItemId", "FK_OrderId", "IsActive", "Quantity", "QuantityFulfilled", "UnitPrice" }, + values: new object[,] + { + { new Guid("34000000-0000-0000-0000-000000000001"), new DateTime(2026, 8, 25, 9, 0, 0, 0, DateTimeKind.Unspecified), new Guid("23000000-0000-0000-0000-000000000001"), new Guid("33000000-0000-0000-0000-000000000001"), true, 30, 30, 60m }, + { new Guid("34000000-0000-0000-0000-000000000002"), new DateTime(2026, 8, 25, 9, 0, 0, 0, DateTimeKind.Unspecified), new Guid("23000000-0000-0000-0000-000000000003"), new Guid("33000000-0000-0000-0000-000000000001"), true, 24, 24, 50m }, + { new Guid("34000000-0000-0000-0000-000000000003"), new DateTime(2026, 8, 30, 10, 0, 0, 0, DateTimeKind.Unspecified), new Guid("23000000-0000-0000-0000-000000000002"), new Guid("33000000-0000-0000-0000-000000000002"), true, 10, 0, 120m } + }); + + migrationBuilder.UpdateData( + table: "Orders", + keyColumn: "Id", + keyValue: new Guid("33000000-0000-0000-0000-000000000001"), + columns: new[] { "ConfirmedAt", "ConfirmedByUserId", "CreatedByUserId", "InvoiceId" }, + values: new object[] { null, null, new Guid("29000000-0000-0000-0000-000000000002"), null }); + + migrationBuilder.UpdateData( + table: "Orders", + keyColumn: "Id", + keyValue: new Guid("33000000-0000-0000-0000-000000000002"), + columns: new[] { "ConfirmedAt", "ConfirmedByUserId", "CreatedByUserId", "InvoiceId" }, + values: new object[] { null, null, new Guid("29000000-0000-0000-0000-000000000003"), null }); + + migrationBuilder.CreateIndex( + name: "IX_Orders_ConfirmedByUserId", + table: "Orders", + column: "ConfirmedByUserId"); + + migrationBuilder.CreateIndex( + name: "IX_Orders_CreatedByUserId", + table: "Orders", + column: "CreatedByUserId"); + + migrationBuilder.CreateIndex( + name: "IX_Invoices_CreatedByUserId", + table: "Invoices", + column: "CreatedByUserId"); + + migrationBuilder.CreateIndex( + name: "IX_Invoices_FinalizedByUserId", + table: "Invoices", + column: "FinalizedByUserId"); + + migrationBuilder.CreateIndex( + name: "IX_Invoices_FK_OrderId", + table: "Invoices", + column: "FK_OrderId"); + + migrationBuilder.CreateIndex( + name: "IX_Invoices_PrintedByUserId", + table: "Invoices", + column: "PrintedByUserId"); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_Users_ConfirmedByUserId", + table: "Orders", + column: "ConfirmedByUserId", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + + migrationBuilder.AddForeignKey( + name: "FK_Orders_Users_CreatedByUserId", + table: "Orders", + column: "CreatedByUserId", + principalTable: "Users", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Orders_Users_ConfirmedByUserId", + table: "Orders"); + + migrationBuilder.DropForeignKey( + name: "FK_Orders_Users_CreatedByUserId", + table: "Orders"); + + migrationBuilder.DropTable( + name: "Invoices"); + + migrationBuilder.DropIndex( + name: "IX_Orders_ConfirmedByUserId", + table: "Orders"); + + migrationBuilder.DropIndex( + name: "IX_Orders_CreatedByUserId", + table: "Orders"); + + migrationBuilder.DropPrimaryKey( + name: "PK_OrderItems", + table: "OrderItems"); + + migrationBuilder.DropIndex( + name: "IX_OrderItems_FK_OrderId", + table: "OrderItems"); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumn: "Id", + keyValue: new Guid("34000000-0000-0000-0000-000000000001")); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumn: "Id", + keyValue: new Guid("34000000-0000-0000-0000-000000000002")); + + migrationBuilder.DeleteData( + table: "OrderItems", + keyColumn: "Id", + keyValue: new Guid("34000000-0000-0000-0000-000000000003")); + + migrationBuilder.DropColumn( + name: "ConfirmedAt", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "ConfirmedByUserId", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "CreatedByUserId", + table: "Orders"); + + migrationBuilder.DropColumn( + name: "InvoiceId", + table: "Orders"); + + migrationBuilder.AlterColumn( + name: "FK_SaleId", + table: "Orders", + type: "char(36)", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + collation: "ascii_general_ci", + oldClrType: typeof(Guid), + oldType: "char(36)", + oldNullable: true) + .OldAnnotation("Relational:Collation", "ascii_general_ci"); + + migrationBuilder.AddPrimaryKey( + name: "PK_OrderItems", + table: "OrderItems", + columns: new[] { "FK_OrderId", "FK_ItemId" }); + + migrationBuilder.InsertData( + table: "OrderItems", + columns: new[] { "FK_ItemId", "FK_OrderId", "CreatedAt", "Id", "IsActive", "Quantity", "QuantityFulfilled", "UnitPrice" }, + values: new object[,] + { + { new Guid("23000000-0000-0000-0000-000000000001"), new Guid("33000000-0000-0000-0000-000000000001"), new DateTime(2026, 8, 25, 9, 0, 0, 0, DateTimeKind.Unspecified), new Guid("34000000-0000-0000-0000-000000000001"), true, 30, 30, 60m }, + { new Guid("23000000-0000-0000-0000-000000000003"), new Guid("33000000-0000-0000-0000-000000000001"), new DateTime(2026, 8, 25, 9, 0, 0, 0, DateTimeKind.Unspecified), new Guid("34000000-0000-0000-0000-000000000002"), true, 24, 24, 50m }, + { new Guid("23000000-0000-0000-0000-000000000002"), new Guid("33000000-0000-0000-0000-000000000002"), new DateTime(2026, 8, 30, 10, 0, 0, 0, DateTimeKind.Unspecified), new Guid("34000000-0000-0000-0000-000000000003"), true, 10, 0, 120m } + }); + } + } +}