using System; using Microsoft.EntityFrameworkCore.Migrations; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; #nullable disable namespace StockMaster.Migrations { /// public partial class InitialSetup : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.EnsureSchema( name: "stock_management"); migrationBuilder.CreateTable( name: "category", schema: "stock_management", columns: table => new { category_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), description = table.Column(type: "text", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_category", x => x.category_id); }); migrationBuilder.CreateTable( name: "customer", schema: "stock_management", columns: table => new { customer_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), email = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), phone = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), address = table.Column(type: "text", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_customer", x => x.customer_id); }); migrationBuilder.CreateTable( name: "product_price_log", schema: "stock_management", columns: table => new { log_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), product_id = table.Column(type: "integer", nullable: false), product_name = table.Column(type: "text", nullable: false), old_price = table.Column(type: "numeric", nullable: false), new_price = table.Column(type: "numeric", nullable: false), changed_by = table.Column(type: "text", nullable: false), changed_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_product_price_log", x => x.log_id); }); migrationBuilder.CreateTable( name: "supplier", schema: "stock_management", columns: table => new { supplier_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), contact_person = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), phone = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), email = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), address = table.Column(type: "text", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_supplier", x => x.supplier_id); }); migrationBuilder.CreateTable( name: "users", schema: "stock_management", columns: table => new { user_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), username = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), password = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), full_name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), email = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), role = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), is_active = table.Column(type: "boolean", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_users", x => x.user_id); }); migrationBuilder.CreateTable( name: "warehouse", schema: "stock_management", columns: table => new { warehouse_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), location = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), capacity = table.Column(type: "integer", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_warehouse", x => x.warehouse_id); }); migrationBuilder.CreateTable( name: "product", schema: "stock_management", columns: table => new { product_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), name = table.Column(type: "character varying(100)", maxLength: 100, nullable: false), description = table.Column(type: "text", nullable: false), sku = table.Column(type: "character varying(50)", maxLength: 50, nullable: false), unit_price = table.Column(type: "numeric(12,2)", precision: 12, scale: 2, nullable: false), reorder_level = table.Column(type: "integer", nullable: false), category_id = table.Column(type: "integer", nullable: true), supplier_id = table.Column(type: "integer", nullable: true), is_active = table.Column(type: "boolean", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_product", x => x.product_id); table.ForeignKey( name: "FK_product_category_category_id", column: x => x.category_id, principalSchema: "stock_management", principalTable: "category", principalColumn: "category_id"); table.ForeignKey( name: "FK_product_supplier_supplier_id", column: x => x.supplier_id, principalSchema: "stock_management", principalTable: "supplier", principalColumn: "supplier_id"); }); migrationBuilder.CreateTable( name: "purchase_order", schema: "stock_management", columns: table => new { po_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), order_date = table.Column(type: "timestamp without time zone", nullable: false), expected_delivery_date = table.Column(type: "timestamp without time zone", nullable: false), actual_delivery_date = table.Column(type: "timestamp without time zone", nullable: true), status = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), supplier_id = table.Column(type: "integer", nullable: true), warehouse_id = table.Column(type: "integer", nullable: false), created_at = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_purchase_order", x => x.po_id); table.ForeignKey( name: "FK_purchase_order_supplier_supplier_id", column: x => x.supplier_id, principalSchema: "stock_management", principalTable: "supplier", principalColumn: "supplier_id"); table.ForeignKey( name: "FK_purchase_order_warehouse_warehouse_id", column: x => x.warehouse_id, principalSchema: "stock_management", principalTable: "warehouse", principalColumn: "warehouse_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "sale", schema: "stock_management", columns: table => new { sale_id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), date_time = table.Column(type: "timestamp without time zone", nullable: false), total_amount = table.Column(type: "numeric(15,2)", precision: 15, scale: 2, nullable: false), user_id = table.Column(type: "integer", nullable: true), customer_id = table.Column(type: "integer", nullable: true), warehouse_id = table.Column(type: "integer", nullable: false) }, constraints: table => { table.PrimaryKey("PK_sale", x => x.sale_id); table.ForeignKey( name: "FK_sale_customer_customer_id", column: x => x.customer_id, principalSchema: "stock_management", principalTable: "customer", principalColumn: "customer_id"); table.ForeignKey( name: "FK_sale_users_user_id", column: x => x.user_id, principalSchema: "stock_management", principalTable: "users", principalColumn: "user_id"); table.ForeignKey( name: "FK_sale_warehouse_warehouse_id", column: x => x.warehouse_id, principalSchema: "stock_management", principalTable: "warehouse", principalColumn: "warehouse_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "warehouse_stock", schema: "stock_management", columns: table => new { warehouse_id = table.Column(type: "integer", nullable: false), product_id = table.Column(type: "integer", nullable: false), quantity_on_hand = table.Column(type: "integer", nullable: false), last_updated = table.Column(type: "timestamp without time zone", nullable: false) }, constraints: table => { table.PrimaryKey("PK_warehouse_stock", x => new { x.warehouse_id, x.product_id }); table.ForeignKey( name: "FK_warehouse_stock_product_product_id", column: x => x.product_id, principalSchema: "stock_management", principalTable: "product", principalColumn: "product_id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_warehouse_stock_warehouse_warehouse_id", column: x => x.warehouse_id, principalSchema: "stock_management", principalTable: "warehouse", principalColumn: "warehouse_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "purchase_order_item", schema: "stock_management", columns: table => new { po_id = table.Column(type: "integer", nullable: false), product_id = table.Column(type: "integer", nullable: false), quantity = table.Column(type: "integer", nullable: false), unit_cost = table.Column(type: "numeric(12,2)", precision: 12, scale: 2, nullable: false), received_quantity = table.Column(type: "integer", nullable: false) }, constraints: table => { table.PrimaryKey("PK_purchase_order_item", x => new { x.po_id, x.product_id }); table.ForeignKey( name: "FK_purchase_order_item_product_product_id", column: x => x.product_id, principalSchema: "stock_management", principalTable: "product", principalColumn: "product_id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_purchase_order_item_purchase_order_po_id", column: x => x.po_id, principalSchema: "stock_management", principalTable: "purchase_order", principalColumn: "po_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( name: "sale_item", schema: "stock_management", columns: table => new { sale_id = table.Column(type: "integer", nullable: false), product_id = table.Column(type: "integer", nullable: false), quantity = table.Column(type: "integer", nullable: false), unit_price_at_sale = table.Column(type: "numeric(12,2)", precision: 12, scale: 2, nullable: false) }, constraints: table => { table.PrimaryKey("PK_sale_item", x => new { x.sale_id, x.product_id }); table.ForeignKey( name: "FK_sale_item_product_product_id", column: x => x.product_id, principalSchema: "stock_management", principalTable: "product", principalColumn: "product_id", onDelete: ReferentialAction.Cascade); table.ForeignKey( name: "FK_sale_item_sale_sale_id", column: x => x.sale_id, principalSchema: "stock_management", principalTable: "sale", principalColumn: "sale_id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateIndex( name: "IX_product_category_id", schema: "stock_management", table: "product", column: "category_id"); migrationBuilder.CreateIndex( name: "IX_product_supplier_id", schema: "stock_management", table: "product", column: "supplier_id"); migrationBuilder.CreateIndex( name: "IX_purchase_order_supplier_id", schema: "stock_management", table: "purchase_order", column: "supplier_id"); migrationBuilder.CreateIndex( name: "IX_purchase_order_warehouse_id", schema: "stock_management", table: "purchase_order", column: "warehouse_id"); migrationBuilder.CreateIndex( name: "IX_purchase_order_item_product_id", schema: "stock_management", table: "purchase_order_item", column: "product_id"); migrationBuilder.CreateIndex( name: "IX_sale_customer_id", schema: "stock_management", table: "sale", column: "customer_id"); migrationBuilder.CreateIndex( name: "IX_sale_user_id", schema: "stock_management", table: "sale", column: "user_id"); migrationBuilder.CreateIndex( name: "IX_sale_warehouse_id", schema: "stock_management", table: "sale", column: "warehouse_id"); migrationBuilder.CreateIndex( name: "IX_sale_item_product_id", schema: "stock_management", table: "sale_item", column: "product_id"); migrationBuilder.CreateIndex( name: "IX_warehouse_stock_product_id", schema: "stock_management", table: "warehouse_stock", column: "product_id"); // TABLOLAR OLUŞTUKTAN SONRA TRIGGER VE VIEWLARI OLUŞTURUYORUZ migrationBuilder.Sql(@" SET search_path TO stock_management, public; -- LOG TABLOSU CREATE TABLE IF NOT EXISTS product_price_log ( log_id SERIAL PRIMARY KEY, product_id INT NOT NULL, product_name VARCHAR(100), old_price DECIMAL(12,2), new_price DECIMAL(12,2), changed_by VARCHAR(50), changed_at TIMESTAMP DEFAULT NOW() ); -- FONKSIYONLAR VE TRIGGERLAR CREATE OR REPLACE FUNCTION trg_fn_recalculate_sale_total() RETURNS TRIGGER LANGUAGE plpgsql AS $$ DECLARE v_sale_id INT; BEGIN IF TG_OP = 'DELETE' THEN v_sale_id := OLD.sale_id; ELSE v_sale_id := NEW.sale_id; END IF; UPDATE sale SET total_amount = (SELECT COALESCE(SUM(quantity * unit_price_at_sale), 0) FROM sale_item WHERE sale_id = v_sale_id) WHERE sale_id = v_sale_id; RETURN NULL; END; $$; CREATE OR REPLACE TRIGGER trg_recalculate_sale_total AFTER INSERT OR UPDATE OR DELETE ON sale_item FOR EACH ROW EXECUTE FUNCTION trg_fn_recalculate_sale_total(); CREATE OR REPLACE FUNCTION trg_fn_prevent_negative_stock() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN IF NEW.quantity_on_hand < 0 THEN RAISE EXCEPTION 'Stock cannot be negative!'; END IF; RETURN NEW; END; $$; CREATE OR REPLACE TRIGGER trg_prevent_negative_stock BEFORE INSERT OR UPDATE ON warehouse_stock FOR EACH ROW EXECUTE FUNCTION trg_fn_prevent_negative_stock(); CREATE OR REPLACE FUNCTION prevent_self_delete() RETURNS TRIGGER AS $$ BEGIN IF OLD.username = current_setting('app.current_user', true) THEN RAISE EXCEPTION 'You cannot delete your own account.'; END IF; RETURN OLD; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE TRIGGER trg_prevent_self_delete BEFORE DELETE ON users FOR EACH ROW EXECUTE FUNCTION prevent_self_delete(); CREATE OR REPLACE FUNCTION log_price_change() RETURNS TRIGGER AS $$ BEGIN IF NEW.unit_price <> OLD.unit_price THEN INSERT INTO product_price_log (product_id, product_name, old_price, new_price, changed_by) VALUES (OLD.product_id, OLD.name, OLD.unit_price, NEW.unit_price, current_setting('app.current_user', true)); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE OR REPLACE TRIGGER trg_price_change BEFORE UPDATE ON product FOR EACH ROW EXECUTE FUNCTION log_price_change(); -- VIEWS CREATE OR REPLACE VIEW vw_sales_by_day_of_week AS SELECT EXTRACT(ISODOW FROM s.date_time)::INT AS day_number, CASE EXTRACT(ISODOW FROM s.date_time)::INT WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' WHEN 6 THEN 'Saturday' WHEN 7 THEN 'Sunday' END AS day_name, COUNT(DISTINCT s.sale_id) AS total_sales, COALESCE(SUM(s.total_amount), 0) AS total_revenue, ROUND(COALESCE(AVG(s.total_amount), 0), 2) AS avg_sale_value, COALESCE(SUM(si.quantity), 0) AS total_items_sold FROM sale s JOIN sale_item si ON s.sale_id = si.sale_id GROUP BY EXTRACT(ISODOW FROM s.date_time) ORDER BY day_number; CREATE OR REPLACE VIEW vw_employee_sales_ranking AS SELECT u.user_id, u.full_name, u.role, COUNT(DISTINCT s.sale_id) AS total_sales, COALESCE(SUM(s.total_amount), 0) AS total_revenue, ROUND(COALESCE(AVG(s.total_amount), 0), 2) AS avg_sale_value, COUNT(DISTINCT s.customer_id) AS unique_customers, RANK() OVER (ORDER BY COALESCE(SUM(s.total_amount), 0) DESC) AS revenue_rank FROM users u LEFT JOIN sale s ON u.user_id = s.user_id GROUP BY u.user_id, u.full_name, u.role HAVING COUNT(s.sale_id) > 0; CREATE OR REPLACE VIEW vw_todays_sales_summary AS SELECT COUNT(DISTINCT s.sale_id) AS total_transactions_today, COALESCE(SUM(s.total_amount), 0) AS total_revenue_today, COALESCE(SUM(si.quantity), 0) AS total_items_sold_today, COUNT(DISTINCT s.customer_id) AS unique_customers_today, COUNT(DISTINCT s.warehouse_id) AS active_warehouses_today FROM sale s JOIN sale_item si ON s.sale_id = si.sale_id WHERE s.date_time::DATE = CURRENT_DATE; "); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "product_price_log", schema: "stock_management"); migrationBuilder.DropTable( name: "purchase_order_item", schema: "stock_management"); migrationBuilder.DropTable( name: "sale_item", schema: "stock_management"); migrationBuilder.DropTable( name: "warehouse_stock", schema: "stock_management"); migrationBuilder.DropTable( name: "purchase_order", schema: "stock_management"); migrationBuilder.DropTable( name: "sale", schema: "stock_management"); migrationBuilder.DropTable( name: "product", schema: "stock_management"); migrationBuilder.DropTable( name: "customer", schema: "stock_management"); migrationBuilder.DropTable( name: "users", schema: "stock_management"); migrationBuilder.DropTable( name: "warehouse", schema: "stock_management"); migrationBuilder.DropTable( name: "category", schema: "stock_management"); migrationBuilder.DropTable( name: "supplier", schema: "stock_management"); } } }