Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4a256a6c4 | |||
| 04d16109ae | |||
| f0f3717681 | |||
| e23b006139 | |||
| 0f35946973 |
@@ -67,9 +67,9 @@ public class SubscriptionExpiryBackgroundService : BackgroundService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens a DI scope, queries non-Stripe-managed companies with active or grace-period subscriptions,
|
/// Opens a DI scope, queries non-Stripe-managed (trial) companies with active or grace-period
|
||||||
/// and calls <see cref="ProcessCompanyAsync"/> for each. A single <c>SaveChangesAsync</c> at the
|
/// subscriptions, and calls <see cref="ProcessCompanyAsync"/> for each. Each company is saved
|
||||||
/// end batches all status mutations into one round-trip. Errors are caught to keep the loop alive.
|
/// individually so a single failure does not prevent other companies from being updated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task RunAsync(CancellationToken ct)
|
private async Task RunAsync(CancellationToken ct)
|
||||||
{
|
{
|
||||||
@@ -103,15 +103,27 @@ public class SubscriptionExpiryBackgroundService : BackgroundService
|
|||||||
|
|
||||||
_logger.LogDebug("Found {Count} companies to evaluate.", companies.Count);
|
_logger.LogDebug("Found {Count} companies to evaluate.", companies.Count);
|
||||||
|
|
||||||
|
// All companies reaching this point have no StripeSubscriptionId — they are trials.
|
||||||
|
// Paid subscribers are managed by Stripe and filtered out above.
|
||||||
|
var effectiveGraceDays = gracePeriodAppliesToTrials ? gracePeriodDays : 0;
|
||||||
|
|
||||||
foreach (var company in companies)
|
foreach (var company in companies)
|
||||||
{
|
{
|
||||||
if (ct.IsCancellationRequested) break;
|
if (ct.IsCancellationRequested) break;
|
||||||
var isTrial = string.IsNullOrEmpty(company.StripeSubscriptionId);
|
try
|
||||||
var effectiveGraceDays = isTrial && !gracePeriodAppliesToTrials ? 0 : gracePeriodDays;
|
{
|
||||||
await ProcessCompanyAsync(db, emailService, adminNotification, company, today, effectiveGraceDays, ct);
|
await ProcessCompanyAsync(db, emailService, adminNotification, company, today, effectiveGraceDays, ct);
|
||||||
|
await db.SaveChangesAsync(ct);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex,
|
||||||
|
"Failed to process subscription expiry for company {Id} ({Name}). Status change was not persisted.",
|
||||||
|
company.Id, company.CompanyName);
|
||||||
|
// Clear EF tracked changes so bad state does not bleed into the next company.
|
||||||
|
db.ChangeTracker.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.SaveChangesAsync(ct);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -121,10 +133,15 @@ public class SubscriptionExpiryBackgroundService : BackgroundService
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Evaluates a single company and performs any required status transitions or reminder sends.
|
/// Evaluates a single company and performs any required status transitions or reminder sends.
|
||||||
/// Transition logic: Active past end date → GracePeriod; GracePeriod past grace deadline → Expired + deactivated.
|
/// Transition logic:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>Active past end date, grace days = 0 → Expired + deactivated immediately (trials).</item>
|
||||||
|
/// <item>Active past end date, grace days > 0 → GracePeriod + grace-period email.</item>
|
||||||
|
/// <item>GracePeriod past grace deadline → Expired + deactivated.</item>
|
||||||
|
/// </list>
|
||||||
/// Reminder emails at <see cref="ReminderDays"/> offsets are sent only while the company is still Active.
|
/// Reminder emails at <see cref="ReminderDays"/> offsets are sent only while the company is still Active.
|
||||||
/// Platform admin is notified asynchronously (fire-and-forget) for both grace period start and full expiry
|
/// Platform admin is notified asynchronously (fire-and-forget) so that operator action can be taken
|
||||||
/// so that operator action can be taken without delaying the main processing loop.
|
/// without delaying the main processing loop.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task ProcessCompanyAsync(
|
private async Task ProcessCompanyAsync(
|
||||||
ApplicationDbContext db,
|
ApplicationDbContext db,
|
||||||
@@ -153,35 +170,55 @@ public class SubscriptionExpiryBackgroundService : BackgroundService
|
|||||||
await WriteAuditLogAsync(db, company,
|
await WriteAuditLogAsync(db, company,
|
||||||
$"Auto-expired: grace period ended {gracePeriodDays} days after subscription end {endDate:d}.");
|
$"Auto-expired: grace period ended {gracePeriodDays} days after subscription end {endDate:d}.");
|
||||||
|
|
||||||
// Notify platform admin
|
|
||||||
_ = adminNotification.NotifyCompanyExpiredAsync(
|
_ = adminNotification.NotifyCompanyExpiredAsync(
|
||||||
company.Id, company.CompanyName,
|
company.Id, company.CompanyName,
|
||||||
company.PrimaryContactEmail ?? string.Empty, expiredDate);
|
company.PrimaryContactEmail ?? string.Empty, expiredDate);
|
||||||
}
|
}
|
||||||
else if (company.SubscriptionStatus == SubscriptionStatus.Active && today > endDate)
|
else if (company.SubscriptionStatus == SubscriptionStatus.Active && today > endDate)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
if (gracePeriodDays == 0)
|
||||||
"Company {Id} ({Name}) subscription ended. Entering grace period.",
|
{
|
||||||
company.Id, company.CompanyName);
|
// No grace period configured — expire immediately without going through GracePeriod.
|
||||||
|
// Trials always land here since gracePeriodAppliesToTrials defaults to false.
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Company {Id} ({Name}) subscription ended with no grace period. Marking Expired and deactivating.",
|
||||||
|
company.Id, company.CompanyName);
|
||||||
|
|
||||||
company.SubscriptionStatus = SubscriptionStatus.GracePeriod;
|
company.SubscriptionStatus = SubscriptionStatus.Expired;
|
||||||
company.UpdatedAt = DateTime.UtcNow;
|
company.IsActive = false;
|
||||||
company.UpdatedBy = "System";
|
company.UpdatedAt = DateTime.UtcNow;
|
||||||
|
company.UpdatedBy = "System";
|
||||||
|
|
||||||
await WriteAuditLogAsync(db, company,
|
await WriteAuditLogAsync(db, company,
|
||||||
$"Auto-moved to GracePeriod: subscription ended {endDate:d}. Grace period expires {expiredDate:d}.");
|
$"Auto-expired: subscription ended {endDate:d} with no grace period.");
|
||||||
|
|
||||||
// Send "grace period started" email to company immediately
|
_ = adminNotification.NotifyCompanyExpiredAsync(
|
||||||
await SendEmailIfNotSentAsync(db, emailService, company, today,
|
company.Id, company.CompanyName,
|
||||||
NotificationType.SubscriptionExpiryReminder,
|
company.PrimaryContactEmail ?? string.Empty, endDate);
|
||||||
daysBeforeExpiry: 0,
|
}
|
||||||
gracePeriodDays,
|
else
|
||||||
ct);
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Company {Id} ({Name}) subscription ended. Entering {Days}-day grace period.",
|
||||||
|
company.Id, company.CompanyName, gracePeriodDays);
|
||||||
|
|
||||||
// Notify platform admin
|
company.SubscriptionStatus = SubscriptionStatus.GracePeriod;
|
||||||
_ = adminNotification.NotifyCompanyGracePeriodAsync(
|
company.UpdatedAt = DateTime.UtcNow;
|
||||||
company.Id, company.CompanyName,
|
company.UpdatedBy = "System";
|
||||||
company.PrimaryContactEmail ?? string.Empty, expiredDate);
|
|
||||||
|
await WriteAuditLogAsync(db, company,
|
||||||
|
$"Auto-moved to GracePeriod: subscription ended {endDate:d}. Grace period expires {expiredDate:d}.");
|
||||||
|
|
||||||
|
await SendEmailIfNotSentAsync(db, emailService, company, today,
|
||||||
|
NotificationType.SubscriptionExpiryReminder,
|
||||||
|
daysBeforeExpiry: 0,
|
||||||
|
gracePeriodDays,
|
||||||
|
ct);
|
||||||
|
|
||||||
|
_ = adminNotification.NotifyCompanyGracePeriodAsync(
|
||||||
|
company.Id, company.CompanyName,
|
||||||
|
company.PrimaryContactEmail ?? string.Empty, expiredDate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Reminder emails (only while still Active) ────────────────────
|
// ── Reminder emails (only while still Active) ────────────────────
|
||||||
|
|||||||
@@ -56,15 +56,16 @@ public class InventoryController : Controller
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays the paginated inventory list with optional keyword search, category filter,
|
/// Displays the paginated inventory list with optional keyword search, category filter,
|
||||||
/// and a low-stock quick-filter. When lowStockOnly is active the default sort switches
|
/// color family filter, and a low-stock quick-filter. When lowStockOnly is active the
|
||||||
/// to QuantityOnHand ascending so the most depleted items surface immediately. Stats
|
/// default sort switches to QuantityOnHand ascending so the most depleted items surface
|
||||||
/// (total value, active count, low-stock count) are computed directly on the DbSet
|
/// immediately. Stats (total value, active count, low-stock count) are computed directly
|
||||||
/// using aggregate SQL to avoid loading all rows into memory.
|
/// on the DbSet using aggregate SQL to avoid loading all rows into memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<IActionResult> Index(
|
public async Task<IActionResult> Index(
|
||||||
string? searchTerm,
|
string? searchTerm,
|
||||||
string? category,
|
string? category,
|
||||||
string? location,
|
string? location,
|
||||||
|
string? colorFamily,
|
||||||
string? sortColumn,
|
string? sortColumn,
|
||||||
string sortDirection = "asc",
|
string sortDirection = "asc",
|
||||||
bool lowStockOnly = false,
|
bool lowStockOnly = false,
|
||||||
@@ -88,64 +89,35 @@ public class InventoryController : Controller
|
|||||||
};
|
};
|
||||||
gridRequest.Validate();
|
gridRequest.Validate();
|
||||||
|
|
||||||
// Build filter — compose search, category, location, and low-stock predicates
|
var hasSearch = !string.IsNullOrWhiteSpace(searchTerm);
|
||||||
|
var hasCategory = !string.IsNullOrWhiteSpace(category);
|
||||||
|
var hasLocation = !string.IsNullOrWhiteSpace(location);
|
||||||
|
var hasColorFamily = !string.IsNullOrWhiteSpace(colorFamily);
|
||||||
|
|
||||||
|
var search = searchTerm?.ToLower() ?? "";
|
||||||
|
var cat = category ?? "";
|
||||||
|
var loc = location ?? "";
|
||||||
|
var colorFam = colorFamily ?? "";
|
||||||
|
|
||||||
|
// Single composable predicate — EF Core evaluates the captured booleans as constants
|
||||||
|
// so inactive conditions fold to true and are omitted from the generated SQL WHERE clause.
|
||||||
System.Linq.Expressions.Expression<Func<InventoryItem, bool>>? filter = null;
|
System.Linq.Expressions.Expression<Func<InventoryItem, bool>>? filter = null;
|
||||||
|
if (hasSearch || hasCategory || hasLocation || hasColorFamily || lowStockOnly)
|
||||||
var hasSearch = !string.IsNullOrWhiteSpace(searchTerm);
|
{
|
||||||
var hasCategory = !string.IsNullOrWhiteSpace(category);
|
filter = i =>
|
||||||
var hasLocation = !string.IsNullOrWhiteSpace(location);
|
(!lowStockOnly || (i.IsActive && i.QuantityOnHand <= i.ReorderPoint)) &&
|
||||||
|
(!hasSearch || (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
||||||
var search = searchTerm?.ToLower() ?? "";
|
|
||||||
var cat = category ?? "";
|
|
||||||
var loc = location ?? "";
|
|
||||||
|
|
||||||
if (lowStockOnly && hasSearch && hasLocation)
|
|
||||||
filter = i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint
|
|
||||||
&& (i.Location != null && i.Location.ToLower() == loc.ToLower())
|
|
||||||
&& (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)));
|
|
||||||
else if (lowStockOnly && hasSearch)
|
|
||||||
filter = i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint
|
|
||||||
&& (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)));
|
|
||||||
else if (lowStockOnly && hasLocation)
|
|
||||||
filter = i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint
|
|
||||||
&& (i.Location != null && i.Location.ToLower() == loc.ToLower());
|
|
||||||
else if (lowStockOnly)
|
|
||||||
filter = i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint;
|
|
||||||
else if (hasSearch && hasCategory && hasLocation)
|
|
||||||
filter = i => (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
|
||||||
|| (i.Description != null && i.Description.ToLower().Contains(search))
|
|| (i.Description != null && i.Description.ToLower().Contains(search))
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)))
|
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)))) &&
|
||||||
&& i.Category.ToLower() == cat.ToLower()
|
(!hasCategory || i.Category.ToLower() == cat.ToLower()) &&
|
||||||
&& (i.Location != null && i.Location.ToLower() == loc.ToLower());
|
(!hasLocation || (i.Location != null && i.Location.ToLower() == loc.ToLower())) &&
|
||||||
else if (hasSearch && hasCategory)
|
(!hasColorFamily || (i.ColorFamilies != null && (
|
||||||
filter = i => (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
i.ColorFamilies == colorFam ||
|
||||||
|| (i.Description != null && i.Description.ToLower().Contains(search))
|
i.ColorFamilies.StartsWith(colorFam + ",") ||
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
i.ColorFamilies.EndsWith("," + colorFam) ||
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)))
|
i.ColorFamilies.Contains("," + colorFam + ","))));
|
||||||
&& i.Category.ToLower() == cat.ToLower();
|
}
|
||||||
else if (hasSearch && hasLocation)
|
|
||||||
filter = i => (i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
|
||||||
|| (i.Description != null && i.Description.ToLower().Contains(search))
|
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search)))
|
|
||||||
&& (i.Location != null && i.Location.ToLower() == loc.ToLower());
|
|
||||||
else if (hasSearch)
|
|
||||||
filter = i => i.SKU.ToLower().Contains(search) || i.Name.ToLower().Contains(search)
|
|
||||||
|| (i.Description != null && i.Description.ToLower().Contains(search))
|
|
||||||
|| (i.ColorName != null && i.ColorName.ToLower().Contains(search))
|
|
||||||
|| (i.Manufacturer != null && i.Manufacturer.ToLower().Contains(search));
|
|
||||||
else if (hasCategory && hasLocation)
|
|
||||||
filter = i => i.Category.ToLower() == cat.ToLower()
|
|
||||||
&& (i.Location != null && i.Location.ToLower() == loc.ToLower());
|
|
||||||
else if (hasCategory)
|
|
||||||
filter = i => i.Category.ToLower() == cat.ToLower();
|
|
||||||
else if (hasLocation)
|
|
||||||
filter = i => i.Location != null && i.Location.ToLower() == loc.ToLower();
|
|
||||||
|
|
||||||
// Build orderBy function
|
// Build orderBy function
|
||||||
Func<IQueryable<InventoryItem>, IOrderedQueryable<InventoryItem>> orderBy = gridRequest.SortColumn switch
|
Func<IQueryable<InventoryItem>, IOrderedQueryable<InventoryItem>> orderBy = gridRequest.SortColumn switch
|
||||||
@@ -179,6 +151,14 @@ public class InventoryController : Controller
|
|||||||
var allItems = (await _unitOfWork.InventoryItems.FindAsync(i => i.CompanyId == companyId)).ToList();
|
var allItems = (await _unitOfWork.InventoryItems.FindAsync(i => i.CompanyId == companyId)).ToList();
|
||||||
ViewBag.Categories = allItems.Select(i => i.Category).Where(c => c != null).Distinct().OrderBy(c => c).ToList();
|
ViewBag.Categories = allItems.Select(i => i.Category).Where(c => c != null).Distinct().OrderBy(c => c).ToList();
|
||||||
ViewBag.Locations = allItems.Select(i => i.Location).Where(l => !string.IsNullOrWhiteSpace(l)).Distinct().OrderBy(l => l).ToList();
|
ViewBag.Locations = allItems.Select(i => i.Location).Where(l => !string.IsNullOrWhiteSpace(l)).Distinct().OrderBy(l => l).ToList();
|
||||||
|
ViewBag.ColorFamilies = allItems
|
||||||
|
.Where(i => !string.IsNullOrEmpty(i.ColorFamilies))
|
||||||
|
.SelectMany(i => i.ColorFamilies!.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
.Select(f => f.Trim())
|
||||||
|
.Where(f => f.Length > 0)
|
||||||
|
.Distinct()
|
||||||
|
.OrderBy(f => f)
|
||||||
|
.ToList();
|
||||||
ViewBag.StatsLowStockCount = allItems.Count(i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint);
|
ViewBag.StatsLowStockCount = allItems.Count(i => i.IsActive && i.QuantityOnHand <= i.ReorderPoint);
|
||||||
ViewBag.StatsActiveCount = allItems.Count(i => i.IsActive);
|
ViewBag.StatsActiveCount = allItems.Count(i => i.IsActive);
|
||||||
ViewBag.StatsTotalValue = allItems.Sum(i => (decimal?)i.QuantityOnHand * i.UnitCost) ?? 0m;
|
ViewBag.StatsTotalValue = allItems.Sum(i => (decimal?)i.QuantityOnHand * i.UnitCost) ?? 0m;
|
||||||
@@ -187,6 +167,7 @@ public class InventoryController : Controller
|
|||||||
ViewBag.SearchTerm = searchTerm;
|
ViewBag.SearchTerm = searchTerm;
|
||||||
ViewBag.Category = category;
|
ViewBag.Category = category;
|
||||||
ViewBag.Location = location;
|
ViewBag.Location = location;
|
||||||
|
ViewBag.ColorFamily = colorFamily;
|
||||||
ViewBag.LowStockOnly = lowStockOnly;
|
ViewBag.LowStockOnly = lowStockOnly;
|
||||||
ViewBag.SortColumn = gridRequest.SortColumn;
|
ViewBag.SortColumn = gridRequest.SortColumn;
|
||||||
ViewBag.SortDirection = gridRequest.SortDirection;
|
ViewBag.SortDirection = gridRequest.SortDirection;
|
||||||
|
|||||||
@@ -215,8 +215,23 @@ public class VendorsController : Controller
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentUser = await _userManager.GetUserAsync(User);
|
var currentUser = await _userManager.GetUserAsync(User);
|
||||||
|
var companyId = currentUser!.CompanyId;
|
||||||
|
|
||||||
|
var duplicate = await _unitOfWork.Vendors.FirstOrDefaultAsync(
|
||||||
|
v => v.CompanyId == companyId && v.CompanyName.ToLower() == dto.CompanyName.ToLower());
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
var msg = $"A vendor named '{dto.CompanyName}' already exists.";
|
||||||
|
if (inline)
|
||||||
|
return Json(new { success = false, errors = new[] { msg } });
|
||||||
|
ModelState.AddModelError(nameof(dto.CompanyName), msg);
|
||||||
|
await PopulateExpenseAccountsAsync();
|
||||||
|
await PopulateVendorCategoriesAsync(dto.CategoryIds);
|
||||||
|
return View(dto);
|
||||||
|
}
|
||||||
|
|
||||||
var vendor = _mapper.Map<Vendor>(dto);
|
var vendor = _mapper.Map<Vendor>(dto);
|
||||||
vendor.CompanyId = currentUser!.CompanyId;
|
vendor.CompanyId = companyId;
|
||||||
|
|
||||||
if (dto.CategoryIds.Any())
|
if (dto.CategoryIds.Any())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@model PowderCoating.Application.DTOs.Accounting.AccountLedgerDto
|
@model PowderCoating.Application.DTOs.Accounting.AccountLedgerDto
|
||||||
@using PowderCoating.Core.Enums
|
@using PowderCoating.Core.Enums
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Ledger — {Model.AccountNumber} {Model.Name}";
|
ViewData["Title"] = $"Ledger - {Model.AccountNumber} {Model.Name}";
|
||||||
ViewData["PageIcon"] = "bi-journal-text";
|
ViewData["PageIcon"] = "bi-journal-text";
|
||||||
ViewData["PageHelpTitle"] = "Account Ledger";
|
ViewData["PageHelpTitle"] = "Account Ledger";
|
||||||
ViewData["PageHelpContent"] = "A chronological list of every transaction posted to this account. Click any Reference to open the source record. Debit increases asset and expense accounts; credit increases liability, equity, and revenue accounts. Use the date range or quick buttons (This Month, YTD, etc.) to narrow the view.";
|
ViewData["PageHelpContent"] = "A chronological list of every transaction posted to this account. Click any Reference to open the source record. Debit increases asset and expense accounts; credit increases liability, equity, and revenue accounts. Use the date range or quick buttons (This Month, YTD, etc.) to narrow the view.";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model PowderCoating.Core.Entities.BankReconciliation
|
@model PowderCoating.Core.Entities.BankReconciliation
|
||||||
@using PowderCoating.Web.Controllers
|
@using PowderCoating.Web.Controllers
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Reconciliation Report – {Model.Account?.Name}";
|
ViewData["Title"] = $"Reconciliation Report - {Model.Account?.Name}";
|
||||||
var clearedDeposits = ViewBag.ClearedDeposits as IEnumerable<PowderCoating.Core.Entities.Payment> ?? Enumerable.Empty<PowderCoating.Core.Entities.Payment>();
|
var clearedDeposits = ViewBag.ClearedDeposits as IEnumerable<PowderCoating.Core.Entities.Payment> ?? Enumerable.Empty<PowderCoating.Core.Entities.Payment>();
|
||||||
var clearedPayments = ViewBag.ClearedPayments as List<ReconciliationItem> ?? new();
|
var clearedPayments = ViewBag.ClearedPayments as List<ReconciliationItem> ?? new();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@using PowderCoating.Web.Controllers
|
@using PowderCoating.Web.Controllers
|
||||||
@model BudgetCreateVm
|
@model BudgetCreateVm
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Edit Budget — {Model.Name}";
|
ViewData["Title"] = $"Edit Budget - {Model.Name}";
|
||||||
ViewData["PageIcon"] = "bi-pencil";
|
ViewData["PageIcon"] = "bi-pencil";
|
||||||
var months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
var months = new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model PowderCoating.Application.DTOs.Notification.NotificationTemplateDto
|
@model PowderCoating.Application.DTOs.Notification.NotificationTemplateDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Edit Template — {Model.DisplayName}";
|
ViewData["Title"] = $"Edit Template - {Model.DisplayName}";
|
||||||
ViewData["PageIcon"] = "bi-envelope-gear";
|
ViewData["PageIcon"] = "bi-envelope-gear";
|
||||||
var placeholders = ViewBag.Placeholders as List<(string Placeholder, string Description)>
|
var placeholders = ViewBag.Placeholders as List<(string Placeholder, string Description)>
|
||||||
?? new List<(string, string)>();
|
?? new List<(string, string)>();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model PowderCoating.Application.DTOs.Accounting.CustomerStatementDto
|
@model PowderCoating.Application.DTOs.Accounting.CustomerStatementDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Statement – {Model.CustomerName}";
|
ViewData["Title"] = $"Statement - {Model.CustomerName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-start mb-4 flex-wrap gap-2">
|
<div class="d-flex justify-content-between align-items-start mb-4 flex-wrap gap-2">
|
||||||
|
|||||||
@@ -124,8 +124,9 @@
|
|||||||
@{
|
@{
|
||||||
var lowStockOnly = (bool)(ViewBag.LowStockOnly ?? false);
|
var lowStockOnly = (bool)(ViewBag.LowStockOnly ?? false);
|
||||||
var activeLocation = ViewBag.Location as string;
|
var activeLocation = ViewBag.Location as string;
|
||||||
|
var activeColorFamily = ViewBag.ColorFamily as string;
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(ViewBag.SearchTerm) || !string.IsNullOrEmpty(ViewBag.Category) || !string.IsNullOrEmpty(activeLocation) || lowStockOnly)
|
@if (!string.IsNullOrEmpty(ViewBag.SearchTerm) || !string.IsNullOrEmpty(ViewBag.Category) || !string.IsNullOrEmpty(activeLocation) || !string.IsNullOrEmpty(activeColorFamily) || lowStockOnly)
|
||||||
{
|
{
|
||||||
<div class="alert @(lowStockOnly ? "alert-warning" : "alert-info") alert-permanent d-flex justify-content-between align-items-center flex-wrap gap-2">
|
<div class="alert @(lowStockOnly ? "alert-warning" : "alert-info") alert-permanent d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||||
<div>
|
<div>
|
||||||
@@ -149,6 +150,10 @@
|
|||||||
{
|
{
|
||||||
<span> in bin "<strong>@activeLocation</strong>"</span>
|
<span> in bin "<strong>@activeLocation</strong>"</span>
|
||||||
}
|
}
|
||||||
|
@if (!string.IsNullOrEmpty(activeColorFamily))
|
||||||
|
{
|
||||||
|
<span> in color family "<strong>@activeColorFamily</strong>"</span>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex gap-2 flex-wrap">
|
<div class="d-flex gap-2 flex-wrap">
|
||||||
@@ -182,6 +187,16 @@
|
|||||||
<option value="@cat" selected="@(cat == ViewBag.Category)">@cat</option>
|
<option value="@cat" selected="@(cat == ViewBag.Category)">@cat</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
|
@if (((IEnumerable<string>)ViewBag.ColorFamilies).Any())
|
||||||
|
{
|
||||||
|
<select name="colorFamily" class="form-select" style="max-width: 160px; min-width: 120px;" onchange="this.form.submit()">
|
||||||
|
<option value="">All Colors</option>
|
||||||
|
@foreach (var family in ViewBag.ColorFamilies)
|
||||||
|
{
|
||||||
|
<option value="@family" selected="@(family == activeColorFamily)">@family</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
@if (((IEnumerable<string?>)ViewBag.Locations).Any())
|
@if (((IEnumerable<string?>)ViewBag.Locations).Any())
|
||||||
{
|
{
|
||||||
<select name="location" class="form-select" style="max-width: 180px; min-width: 130px;" onchange="this.form.submit()">
|
<select name="location" class="form-select" style="max-width: 180px; min-width: 130px;" onchange="this.form.submit()">
|
||||||
@@ -215,7 +230,7 @@
|
|||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
@if (!Model.Items.Any())
|
@if (!Model.Items.Any())
|
||||||
{
|
{
|
||||||
var isInventoryFiltered = !string.IsNullOrEmpty(ViewBag.SearchTerm as string) || !string.IsNullOrEmpty(ViewBag.Category as string) || lowStockOnly;
|
var isInventoryFiltered = !string.IsNullOrEmpty(ViewBag.SearchTerm as string) || !string.IsNullOrEmpty(ViewBag.Category as string) || !string.IsNullOrEmpty(activeColorFamily) || lowStockOnly;
|
||||||
<div class="text-center py-5">
|
<div class="text-center py-5">
|
||||||
<i class="bi bi-inbox" style="font-size: 4rem; color: #d1d5db;"></i>
|
<i class="bi bi-inbox" style="font-size: 4rem; color: #d1d5db;"></i>
|
||||||
<h5 class="mt-3 text-muted">No inventory items found</h5>
|
<h5 class="mt-3 text-muted">No inventory items found</h5>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model PowderCoating.Application.DTOs.Inventory.InventoryItemDto
|
@model PowderCoating.Application.DTOs.Inventory.InventoryItemDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Label — {Model.Name}";
|
ViewData["Title"] = $"Label - {Model.Name}";
|
||||||
Layout = null; // standalone print page
|
Layout = null; // standalone print page
|
||||||
}
|
}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -95,6 +95,12 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.label-location {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
.label-scan-hint {
|
.label-scan-hint {
|
||||||
font-size: 9px;
|
font-size: 9px;
|
||||||
color: #888;
|
color: #888;
|
||||||
@@ -158,6 +164,11 @@
|
|||||||
<div class="label-sku" style="color:#777">@Model.Manufacturer</div>
|
<div class="label-sku" style="color:#777">@Model.Manufacturer</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (!string.IsNullOrEmpty(Model.Location))
|
||||||
|
{
|
||||||
|
<div class="label-location">Location: @Model.Location</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="label-scan-hint">
|
<div class="label-scan-hint">
|
||||||
Scan to log usage • Powder Coating Logix
|
Scan to log usage • Powder Coating Logix
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
@using PowderCoating.Application.DTOs.Inventory
|
@using PowderCoating.Application.DTOs.Inventory
|
||||||
@using PowderCoating.Web.Controllers
|
@using PowderCoating.Web.Controllers
|
||||||
@{
|
@{
|
||||||
var item = ViewBag.ItemDto as InventoryItemDto;
|
var item = ViewBag.ItemDto as InventoryItemDto;
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
var otherJobs = ViewBag.OtherJobs as List<ScanJobOption> ?? new();
|
var otherJobs = ViewBag.OtherJobs as List<ScanJobOption> ?? new();
|
||||||
var preselectedJobId = ViewBag.PreselectedJobId as int?;
|
var preselectedJobId = ViewBag.PreselectedJobId as int?;
|
||||||
var scanError = ViewBag.ScanError as string;
|
var scanError = ViewBag.ScanError as string;
|
||||||
ViewData["Title"] = $"Log Usage — {item?.Name}";
|
ViewData["Title"] = $"Log Usage - {item?.Name}";
|
||||||
Layout = null; // mobile-first standalone page
|
Layout = null; // mobile-first standalone page
|
||||||
}
|
}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@model PowderCoating.Application.DTOs.Job.JobEditItemsViewModel
|
@model PowderCoating.Application.DTOs.Job.JobEditItemsViewModel
|
||||||
@using PowderCoating.Core.Entities
|
@using PowderCoating.Core.Entities
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Edit Items — {Model.JobNumber}";
|
ViewData["Title"] = $"Edit Items - {Model.JobNumber}";
|
||||||
ViewData["PageIcon"] = "bi-list-check";
|
ViewData["PageIcon"] = "bi-list-check";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@model (PowderCoating.Application.DTOs.Job.JobDto Job, PowderCoating.Application.DTOs.Job.IntakeJobDto Form)
|
@model (PowderCoating.Application.DTOs.Job.JobDto Job, PowderCoating.Application.DTOs.Job.IntakeJobDto Form)
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Part Intake — {Model.Job.JobNumber}";
|
ViewData["Title"] = $"Part Intake - {Model.Job.JobNumber}";
|
||||||
ViewData["PageIcon"] = "bi-box-seam";
|
ViewData["PageIcon"] = "bi-box-seam";
|
||||||
var job = Model.Job;
|
var job = Model.Job;
|
||||||
var form = Model.Form;
|
var form = Model.Form;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@using PowderCoating.Application.DTOs.PurchaseOrder
|
@using PowderCoating.Application.DTOs.PurchaseOrder
|
||||||
@model ReceivePurchaseOrderDto
|
@model ReceivePurchaseOrderDto
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Receive Goods — {ViewBag.PoNumber}";
|
ViewData["Title"] = $"Receive Goods - {ViewBag.PoNumber}";
|
||||||
int poId = (int)ViewBag.PoId;
|
int poId = (int)ViewBag.PoId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep1Dto
|
@model WizardStep1Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Company Profile";
|
ViewData["Title"] = "Setup Wizard - Company Profile";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 1;
|
int step = ViewBag.Step as int? ?? 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep9Dto
|
@model WizardStep9Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Team Members";
|
ViewData["Title"] = "Setup Wizard - Team Members";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 10;
|
int step = ViewBag.Step as int? ?? 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep6Dto
|
@model WizardStep6Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Chart of Accounts";
|
ViewData["Title"] = "Setup Wizard - Chart of Accounts";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 11;
|
int step = ViewBag.Step as int? ?? 11;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep10Dto
|
@model WizardStep10Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Vendors & Suppliers";
|
ViewData["Title"] = "Setup Wizard - Vendors & Suppliers";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 12;
|
int step = ViewBag.Step as int? ?? 12;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep8Dto
|
@model WizardStep8Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Inventory / Powder Colors";
|
ViewData["Title"] = "Setup Wizard - Inventory / Powder Colors";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 13;
|
int step = ViewBag.Step as int? ?? 13;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardOvensStepDto
|
@model WizardOvensStepDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Equipment & Ovens";
|
ViewData["Title"] = "Setup Wizard - Equipment & Ovens";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 14;
|
int step = ViewBag.Step as int? ?? 14;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardPricingTiersStepDto
|
@model WizardPricingTiersStepDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Pricing Tiers";
|
ViewData["Title"] = "Setup Wizard - Pricing Tiers";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 15;
|
int step = ViewBag.Step as int? ?? 15;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardCatalogStepDto
|
@model WizardCatalogStepDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Service Catalog";
|
ViewData["Title"] = "Setup Wizard - Service Catalog";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 16;
|
int step = ViewBag.Step as int? ?? 16;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep7Dto
|
@model WizardStep7Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Notifications";
|
ViewData["Title"] = "Setup Wizard - Notifications";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 17;
|
int step = ViewBag.Step as int? ?? 17;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep9Dto
|
@model WizardStep9Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Team Members";
|
ViewData["Title"] = "Setup Wizard - Team Members";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 18;
|
int step = ViewBag.Step as int? ?? 18;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep2QbDto
|
@model WizardStep2QbDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — QuickBooks Migration";
|
ViewData["Title"] = "Setup Wizard - QuickBooks Migration";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 2;
|
int step = ViewBag.Step as int? ?? 2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@using PowderCoating.Core.Enums
|
@using PowderCoating.Core.Enums
|
||||||
@model WizardStep2Dto
|
@model WizardStep2Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Operating Costs";
|
ViewData["Title"] = "Setup Wizard - Operating Costs";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 3;
|
int step = ViewBag.Step as int? ?? 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardOvensStepDto
|
@model WizardOvensStepDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Shop Equipment";
|
ViewData["Title"] = "Setup Wizard - Shop Equipment";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 4;
|
int step = ViewBag.Step as int? ?? 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep3Dto
|
@model WizardStep3Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Document Numbering";
|
ViewData["Title"] = "Setup Wizard - Document Numbering";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 5;
|
int step = ViewBag.Step as int? ?? 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep5Dto
|
@model WizardStep5Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Job Settings";
|
ViewData["Title"] = "Setup Wizard - Job Settings";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 6;
|
int step = ViewBag.Step as int? ?? 6;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep4Dto
|
@model WizardStep4Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Payment Terms";
|
ViewData["Title"] = "Setup Wizard - Payment Terms";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 7;
|
int step = ViewBag.Step as int? ?? 7;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardPricingTiersStepDto
|
@model WizardPricingTiersStepDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Pricing Tiers";
|
ViewData["Title"] = "Setup Wizard - Pricing Tiers";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 8;
|
int step = ViewBag.Step as int? ?? 8;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Application.DTOs.Wizard
|
@using PowderCoating.Application.DTOs.Wizard
|
||||||
@model WizardStep7Dto
|
@model WizardStep7Dto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Setup Wizard — Notifications";
|
ViewData["Title"] = "Setup Wizard - Notifications";
|
||||||
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
var progress = ViewBag.Progress as WizardProgressDto ?? new WizardProgressDto();
|
||||||
int step = ViewBag.Step as int? ?? 5;
|
int step = ViewBag.Step as int? ?? 5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" data-bs-theme="light">
|
<html lang="en" data-bs-theme="light">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|||||||
@@ -83,4 +83,12 @@
|
|||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script>
|
||||||
|
function changePageSize(size) {
|
||||||
|
var url = new URL(window.location.href);
|
||||||
|
url.searchParams.set('pageSize', size);
|
||||||
|
url.searchParams.set('pageNumber', '1');
|
||||||
|
window.location.href = url.toString();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@using PowderCoating.Core.Entities
|
@using PowderCoating.Core.Entities
|
||||||
@model StripeWebhookEvent
|
@model StripeWebhookEvent
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Webhook Event – {Model.EventId}";
|
ViewData["Title"] = $"Webhook Event - {Model.EventId}";
|
||||||
var statusClass = Model.Status switch
|
var statusClass = Model.Status switch
|
||||||
{
|
{
|
||||||
StripeWebhookEventStatus.Processed => "success",
|
StripeWebhookEventStatus.Processed => "success",
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
@using PowderCoating.Core.Enums
|
@using PowderCoating.Core.Enums
|
||||||
@model Company
|
@model Company
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Manage – {Model.CompanyName}";
|
ViewData["Title"] = $"Manage - {Model.CompanyName}";
|
||||||
var planConfigs = (dynamic)ViewBag.PlanConfigs;
|
var planConfigs = (dynamic)ViewBag.PlanConfigs;
|
||||||
|
|
||||||
string PlanName(int plan)
|
string PlanName(int plan)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@model PowderCoating.Application.DTOs.Accounting.VendorStatementDto
|
@model PowderCoating.Application.DTOs.Accounting.VendorStatementDto
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = $"Statement – {Model.VendorName}";
|
ViewData["Title"] = $"Statement - {Model.VendorName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-start mb-4 flex-wrap gap-2">
|
<div class="d-flex justify-content-between align-items-start mb-4 flex-wrap gap-2">
|
||||||
|
|||||||
@@ -88,6 +88,20 @@
|
|||||||
border-bottom: 3px solid var(--bs-primary);
|
border-bottom: 3px solid var(--bs-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Dark mode fix for main settings tabs: UA button styling bleeds through
|
||||||
|
without an explicit background-color, producing white buttons with faint text. */
|
||||||
|
[data-bs-theme="dark"] #settingsTabs .nav-link {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] #settingsTabs .nav-link:hover:not(.active) {
|
||||||
|
background-color: var(--bs-tertiary-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-bs-theme="dark"] #settingsTabs .nav-link.active {
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── PDF Templates inner tabs (card-header-tabs) ────────────────────────── */
|
/* ── PDF Templates inner tabs (card-header-tabs) ────────────────────────── */
|
||||||
#pdfTemplateTabs .nav-link {
|
#pdfTemplateTabs .nav-link {
|
||||||
color: var(--bs-secondary-color);
|
color: var(--bs-secondary-color);
|
||||||
|
|||||||
Reference in New Issue
Block a user