using SmartStack.Domain.Platform.Administration.Tenants.Organisation; using SmartStack.Domain.Platform.Administration.Users; using {{ProjectName}}.Domain.Common; namespace {{ProjectName}}.Domain.Entities; /// /// Example entity demonstrating REAL navigation properties + SQL foreign keys /// to Core entities in the V1 whitelist (User, TenantOrganisation). /// /// The owning side carries the GUID FK column AND a navigation property to /// the Core principal. EF Core emits a real cross-schema FK in the migration /// (targeting core.auth_Users(Id) / core.tenant_TenantOrganisations(Id)) /// because SmartStackExtensionDbContext exposes those entities via /// ExcludeFromMigrations — see the base class. /// /// You can .Include(o => o.Customer) / .Include(o => o.Organisation) /// to hydrate the principal in the same SQL query (INNER JOIN), or query a /// nav field directly: _db.Orders.Where(o => o.Customer.Email == ...). /// public class Order : ExtensionBaseEntity { public string OrderNumber { get; private set; } = null!; /// FK to core.auth_Users(Id) — the user placing the order. public Guid CustomerUserId { get; private set; } /// FK to core.tenant_TenantOrganisations(Id) — the customer's organisation. public Guid OrganisationId { get; private set; } public OrderStatus Status { get; private set; } public decimal TotalAmount { get; private set; } public DateTime OrderDate { get; private set; } public string? Notes { get; private set; } /// Navigation to the placing User. Real cross-schema FK. public User Customer { get; private set; } = null!; /// Navigation to the TenantOrganisation (the shared organisation directory). Real cross-schema FK. public TenantOrganisation Organisation { get; private set; } = null!; // Private constructor for EF Core private Order() { } /// /// Creates a new order. The Customer / Organisation navigations are lazily /// hydrated by .Include(...) at query time — the factory only /// stores the FK GUIDs. /// public static Order Create(string orderNumber, Guid customerUserId, Guid organisationId, decimal totalAmount) { ArgumentException.ThrowIfNullOrWhiteSpace(orderNumber); return new Order { OrderNumber = orderNumber, CustomerUserId = customerUserId, OrganisationId = organisationId, Status = OrderStatus.Pending, TotalAmount = totalAmount, OrderDate = DateTime.UtcNow }; } public void Confirm() { if (Status != OrderStatus.Pending) throw new InvalidOperationException("Only pending orders can be confirmed."); Status = OrderStatus.Confirmed; } public void Ship() { if (Status != OrderStatus.Confirmed) throw new InvalidOperationException("Only confirmed orders can be shipped."); Status = OrderStatus.Shipped; } public void Complete() { if (Status != OrderStatus.Shipped) throw new InvalidOperationException("Only shipped orders can be completed."); Status = OrderStatus.Completed; } public void Cancel() { if (Status == OrderStatus.Completed) throw new InvalidOperationException("Completed orders cannot be cancelled."); Status = OrderStatus.Cancelled; } public void AddNotes(string notes) { Notes = notes; } } /// /// Order status enum. /// public enum OrderStatus { Pending = 0, Confirmed = 1, Shipped = 2, Completed = 3, Cancelled = 4 }