namespace EntitlementBLL.Onboarding;
// Wire-contract DTOs for calling SqlWorkbench's real HTTP endpoints (ClientDatabase.svc,
// ChangeRequest.svc). Deliberately NOT a project reference to SwDAL — no precedent anywhere
// in this repo for one module's BLL referencing another module's DAL/BLL types directly
// (confirmed: the only existing cross-module pattern, PAY -> Sales/Finance via
// MmIntegrationService, goes over a named HttpClient with its own local request/response
// shapes). Field names must match SW's own DTOs exactly — every GB5 host serializes with
// PropertyNamingPolicy = null (PascalCase preserved), confirmed live against these same
// endpoints in an earlier thread.
/// Mirrors SwDAL.DTO.ClientDatabase.ClientDatabaseDTO — only the fields
/// SaveClientDatabase actually needs from a caller; the rest are server-populated.
public class SwSaveClientDatabaseRequest
{
public int ClientDbId { get; set; }
public string ClientDbCode { get; set; } = string.Empty;
public string ClientDbName { get; set; } = string.Empty;
public int DbServerId { get; set; }
public string DatabaseName { get; set; } = string.Empty;
public int DbModelId { get; set; }
public byte ClientDbStatus { get; set; } // 0 = Pending
public string? Description { get; set; }
public byte DatabaseRole { get; set; } // 0 = Main
public int TenantId { get; set; }
}
/// Mirrors SwDAL.DTO.ChangeRequest.ChangeRequestDTO — only the fields a
/// ClientProvisioning/FromScripts submission needs.
public class SwSaveChangeRequestRequest
{
public int ChangeRequestId { get; set; }
public string Title { get; set; } = string.Empty;
public string? Description { get; set; }
public int ClientDatabaseId { get; set; }
public byte QueryType { get; set; } = 4; // DDL
public byte Category { get; set; } = 6; // ChangeRequestCategory.ClientProvisioning
public byte ProvisioningMode { get; set; } = 2; // ProvisioningMode.FromScripts
public int BaselineUpgradePackageId { get; set; }
public int TenantId { get; set; }
}
/// Just enough of ChangeRequestDTO's real shape to check status after Execute.
/// ChangeRequestStatus enum (SwDAL.Enums.SwEnums): Draft=0 Submitted=1 UnderReview=2
/// Approved=3 Rejected=4 Executed=5.
public class SwChangeRequestStatusDTO
{
public int ChangeRequestId { get; set; }
public byte CrStatus { get; set; }
/// Background-execution state (tracker §37/§43) — mirrors SwDAL's own
/// ChangeRequestExecutionStatus byte values: 0=NotQueued 1=Queued 2=Running 3=Done 4=Failed.
/// Only meaningful for a CR submitted via QueueChangeRequestExecutionAsync; every
/// synchronously-executed CR (the AutoApprove path used before this) stays 0/NotQueued even
/// after CrStatus reaches Executed. Lets ResumeOneJobAsync distinguish "still queued/running,
/// keep waiting" from "genuinely failed" — a failed background execution never reaches
/// CrStatus=Executed at all, so CrStatus alone can't tell the two apart.
public byte ExecutionStatus { get; set; }
public int ClientDatabaseId { get; set; }
/// Tracker §37 Decision 2 — real-time DDL execution progress, populated
/// server-side only when this CR's Category == ClientProvisioning. Null otherwise.
public int? ScriptsDone { get; set; }
public int? ScriptsTotal { get; set; }
}
/// Mirrors SwDAL.DTO.UpgradePackage.PackageScopeFilterDTO — all fields optional; a
/// null field simply excludes that scope's overlay packages from resolution, per
/// GetProvisioningChain's own contract. Not yet populated from any real caller-supplied
/// data (no UI collects partner/industry/country yet) — passed as an all-null filter today,
/// which resolves to Universal packages only.
public class SwPackageScopeFilterRequest
{
public string? PartnerProductCode { get; set; }
public string? IndustryCode { get; set; }
public string? CountryCode { get; set; }
public string? ClientCode { get; set; }
}
/// Mirrors SwDAL.DTO.UpgradePackage.PackageChainItemDTO.
public class SwPackageChainItemDTO
{
public int PackageId { get; set; }
public string PackageCode { get; set; } = string.Empty;
public string PackageName { get; set; } = string.Empty;
public short SequenceInChain { get; set; }
public byte ScopeType { get; set; }
}
/// Just enough of SwDAL.DTO.ClientDatabase.ClientDatabaseDTO's real shape (tracker §49
/// Decision 8's corrected design) for Entitlement to build a LoginDTO pointed directly at a
/// pooled demo instance's own physical database — DatabaseName + ServerConfigId is all
/// IQueryExecutor/ApplicationConnection need to resolve a connection, the exact same mechanism
/// every other multi-tenant call in this codebase already uses. No new SqlWorkbench endpoint:
/// GET /ClientDatabase/GetClientDatabaseById already returns this.
public class SwClientDatabaseInfoDTO
{
public int ClientDbId { get; set; }
/// Needed, not DatabaseName, to build a LoginDTO Entitlement's own IQueryExecutor
/// can actually resolve — confirmed by reading ApplicationConnection.DatabaseConnectionObject
/// directly: it looks up MSERVERCONFIG by CONNECTIONNAME, not the raw physical database name.
/// ClientDatabaseProvisioner.RegisterAndLinkServerConfigAsync registers that name as exactly
/// $"{ClientDbCode}-{DatabaseRole}".ToUpperInvariant() — "{CLIENTDBCODE}-MAIN" for every
/// pooled demo instance, since those are always Main-role databases.
public string ClientDbCode { get; set; } = string.Empty;
public string DatabaseName { get; set; } = string.Empty;
public int DbServerId { get; set; }
public int? ServerConfigId { get; set; }
}