Session data.

This commit is contained in:
Andy Howard
2025-01-22 08:01:51 +00:00
parent 61ecd59794
commit f375e0d175
121 changed files with 3743 additions and 2126 deletions
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Consoles;
using Sarand.BusinessMgr.Net.Core.Web.Control.Consoles;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
@@ -16,10 +17,18 @@ using Sarand.BusinessMgr.Web.Portal.Consoles;
using Sarand.BusinessMgr.Web.Portal.Helpers;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.CodeTypes;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Diary;
using Sarand.Net.Standard.Base.Interfaces;
using Sarand.Net.Standard.Base.IO;
using Sarand.Net.Standard.Base.ItemData;
using Sarand.Net.Standard.Base.ItemDocs;
using Sarand.Net.Standard.Base.ItemOptions;
using Sarand.Net.Standard.Base.ReferenceData;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.UpdateLog;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Dbas.Base;
using System;
@@ -82,7 +91,7 @@ namespace Sarand.BusinessMgr.Web.Portal.App
try
{
properties = new PropertySet();
SbmGlobals.System = (SbmGlobals_Web.System = (System_Web = new SbmSystem_Web(properties)));
SbmGlobals.System = (SbmGlobals_Web.System = (System_Web = new SbmSystem_Portal(properties)));
Configuration = configuration;
}
catch (Exception exc)
@@ -159,12 +168,48 @@ namespace Sarand.BusinessMgr.Web.Portal.App
public override SbmEmailConfig EmailConfig { get { return emailConfigs.Values.ToList().getConfigForSession(AppConfig); } }
//-------------------------------------------------------------------
// Create Consoles.
public override SaReferenceDataConsole CreateReferenceDataConsole(ISbmUserOrganisationContext userContext)
// Create consoles.
public SbmSessionConsole CreateSessionConsole(ISbmUserOrganisationContext userContext)
{
return SbmSessionConsole.CreateConsole(userContext);
}
public SaDiaryConsole CreateDiaryConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaSecurityConsole CreateSecurityConsole(ISbmUserOrganisationContext userContext)
{
return new SbmSecurityConsole_Web(userContext);
}
public SaCodeTypeConsole CreateCodeTypeConsole(ISbmUserOrganisationContext userContext)
{
return new SbmCodeTypeConsole_Web(userContext);
}
public SaItemDataConsole CreateItemDataConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaItemDocConsole CreateItemDocConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaItemOptionConsole CreateItemOptionConsole(ISbmUserOrganisationContext userContext)
{
return new SbmItemOptionConsole_Web(userContext);
}
public SaInterfaceConsole CreateInterfaceConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaUpdateLogConsole CreateUpdateLogConsole(ISbmUserOrganisationContext userContext)
{
return new SbmUpdateLogConsole_Web(userContext);
}
public SaReferenceDataConsole CreateReferenceDataConsole(ISbmUserOrganisationContext userContext)
{
return new SbmReferenceDataConsole_Portal(userContext);
}
public override SbmEmailConsole CreateEmailConsole(ISbmUserOrganisationContext userContext)
public SbmEmailConsole CreateEmailConsole(ISbmUserOrganisationContext userContext)
{
return new SbmEmailConsole_Portal(EmailConfig);
}
@@ -18,33 +18,46 @@ using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm.Config;
using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm.Config.Database;
using Sarand.BusinessMgr.Net.Standard.Base.Core;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
namespace Sarand.BusinessMgr.Web.Portal.App
{
//=======================================================================
public class SbmSessionData_Portal : SbmSessionData_Web, ISbmUserOrganisationContext
public class SbmSessionData_Portal : SbmSessionData_Web, ISbmSessionData_Core
{
//-------------------------------------------------------------------
// Construction.
[JsonConstructor]
private SbmSessionData_Portal(long sessionIdx, int itemIdx, SbmSessionContext sessionContext) :
base(sessionIdx, itemIdx, sessionContext)
private SbmSessionData_Portal(long sessionIdx, SbmSessionContext sessionContext) :
base(sessionIdx, sessionContext)
{
securityProfile = new SbmSecurityProfile(this, false);
securityProfile = new SbmSecurityProfile(false);
Organisation = new OrganisationData_Portal(null, null);
User = new UserData_Portal(sessionContext, null, null);
}
/// <summary>
/// SessionData construction.
/// <para>SessionContext and UserAccount must be supplied.</para>
/// <para>Organisation is optional.</para>
/// Session Data construction for non-session data, eg. background tasks.
/// <para>.</para>
/// </summary>
public SbmSessionData_Portal(SbmSessionContext sessionContext, String repositoryContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation) :
public SbmSessionData_Portal(SbmSessionContext sessionContext) :
base(0, sessionContext)
{
securityProfile = new SbmSecurityProfile(false);
Organisation = new OrganisationData_Portal(null, null);
User = new UserData_Portal(sessionContext, null, null);
}
/// <summary>
/// Session Data construction.
/// <para>- Session Context must be supplied.</para>
/// <para>- Other parameters are optional and can be added later via Refresh().</para>
/// </summary>
public SbmSessionData_Portal(SbmSessionContext sessionContext, String repositoryContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation) :
base(sessionContext)
{
RepositoryContext = repositoryContext;
securityProfile = new SbmSecurityProfile(this, false);
securityProfile = new SbmSecurityProfile(false);
Organisation = new OrganisationData_Portal(associationOrganisation, affiliateOrganisation);
User = new UserData_Portal(sessionContext, securityItemUser, affiliateUser, supervisedOrganisations);
User = new UserData_Portal(sessionContext, securityItemUser, affiliateUser);
}
//-------------------------------------------------------------------
@@ -136,24 +149,10 @@ namespace Sarand.BusinessMgr.Web.Portal.App
{
[JsonConstructor]
private UserData_Portal() { }
public UserData_Portal(SbmSessionContext sessionContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations) :
public UserData_Portal(SbmSessionContext sessionContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser) :
base(sessionContext)
{
if (securityItemUser != null)
{
SecurityItemId = securityItemUser.Id;
}
if (affiliateUser != null)
{
AffiliateId = affiliateUser.Id;
Refresh(securityItemUser, affiliateUser, supervisedOrganisations);
if (sessionContext.Application == Sbm.Application.WebControl)
KeepLoggedIn = affiliateUser.KeepLoggedIn_Control;
else if (sessionContext.Application == Sbm.Application.WebPortal)
KeepLoggedIn = affiliateUser.KeepLoggedIn_Portal;
else Debugger.Break();
}
this.supervisedOrganisations = supervisedOrganisations ?? new List<SysIdString>();
Refresh(securityItemUser, affiliateUser);
}
public UserData_Portal(UserData userData) :
base(userData)
@@ -163,31 +162,36 @@ namespace Sarand.BusinessMgr.Web.Portal.App
{
SecurityItemId = userData_Portal.SecurityItemId;
AffiliateId = userData_Portal.AffiliateId;
supervisedOrganisations = userData_Portal.supervisedOrganisations;
}
}
// Properties.
public SysId SecurityItemId { get; protected set; }
public SysId AffiliateId { get; protected set; }
public bool KeepLoggedIn { get; private set; }
/// <summary>User managed associations - Id and display name.</summary>
public List<SysIdString> SupervisedOrganisations { get { return new List<SysIdString>(supervisedOrganisations); } }
protected List<SysIdString> supervisedOrganisations { get; } = new List<SysIdString>();
// Utilities.
public bool Refresh(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations)
public bool Refresh(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser)
{
base.Refresh();
// Check that user matches the session.
if (!SysId.IsValid(SecurityItemId) || !SysId.IsValid(securityItemUser?.Id ?? null) || !SecurityItemId.Equals(securityItemUser.Id)) return false;
if (!SysId.IsValid(AffiliateId) || !SysId.IsValid(affiliateUser?.Id ?? null) || !AffiliateId.Equals(affiliateUser.Id)) return false;
if (!SysId.IsValid(securityItemUser?.Id) || (SysId.IsValid(SecurityItemId) && !SecurityItemId.Equals(securityItemUser.Id)))
{
SaLogger.Warn($"{SysUtil.Fn} Invalid - User Security Item doesn't match session. Expected Id: {SecurityItemId}. Found: {securityItemUser?.Id}.");
return false;
}
if (!SysId.IsValid(affiliateUser?.Id) || (SysId.IsValid(AffiliateId) && !AffiliateId.Equals(affiliateUser.Id)))
{
SaLogger.Warn($"{SysUtil.Fn} Invalid - User Affiliate doesn't match session. Expected Id: {AffiliateId}. Found: {affiliateUser?.Id}.");
return false;
}
// Refresh properties.
EmailAddress = securityItemUser.EmailAddress;
Title = affiliateUser.Title;
FirstName = affiliateUser.FirstName;
LastName = affiliateUser.LastName;
DisplayName = affiliateUser.GetDisplayName();
this.supervisedOrganisations.Clear();
this.supervisedOrganisations.AddRange(supervisedOrganisations);
AffiliateId = affiliateUser?.Id ?? new SysId();
SecurityItemId = securityItemUser?.Id ?? new SysId();
EmailAddress = securityItemUser?.EmailAddress ?? "";
Title = affiliateUser?.Title ?? "";
FirstName = affiliateUser?.FirstName ?? "";
LastName = affiliateUser?.LastName ?? "";
DisplayName = affiliateUser?.GetDisplayName() ?? "";
KeepLoggedIn = affiliateUser?.KeepLoggedIn_Portal ?? false;
return true;
}
}
@@ -195,13 +199,14 @@ namespace Sarand.BusinessMgr.Web.Portal.App
/// <summary>Portal User details.</summary>
public UserData_Portal User { get; private set; }
//-------------------------------------------------------------------
/// <summary>
/// Update the user's contact details against the session.
/// Update the User and Organisation details against the Session Data.
/// <para>- User identity must match that already against the session.</para>
/// </summary>
public bool RefreshUser(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation)
public bool Refresh(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation)
{
if (User != null && User.Refresh(securityItemUser, affiliateUser, supervisedOrganisations))
if (User != null && User.Refresh(securityItemUser, affiliateUser))
{
Organisation = new OrganisationData_Portal(associationOrganisation, affiliateOrganisation);
return true;
@@ -211,7 +216,7 @@ namespace Sarand.BusinessMgr.Web.Portal.App
//-------------------------------------------------------------------
/// <summary>
/// User Profile.
/// User Profile - persistent session properties relating to default population of views, forms etc.
/// <para>- Filter settings.</para>
/// </summary>
public class UserProfileData
@@ -0,0 +1,82 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Consoles;
using Sarand.BusinessMgr.Net.Core.Web.Control.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Core;
using Sarand.BusinessMgr.Web.Portal.Consoles;
using Sarand.Net.Standard.Base.CodeTypes;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Diary;
using Sarand.Net.Standard.Base.Interfaces;
using Sarand.Net.Standard.Base.ItemData;
using Sarand.Net.Standard.Base.ItemDocs;
using Sarand.Net.Standard.Base.ItemOptions;
using Sarand.Net.Standard.Base.ReferenceData;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.UpdateLog;
using static Sarand.BusinessMgr.Net.Core.Web.App.SbmAppConfig;
namespace Sarand.BusinessMgr.Web.Portal.App
{
public class SbmSystem_Portal:SbmSystem_Web
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public SbmSystem_Portal(PropertySet properties) : base(properties)
{
}
//-------------------------------------------------------------------
// Create consoles.
public override SbmSessionConsole CreateSessionConsole(ISbmUserOrganisationContext userContext)
{
return SbmSessionConsole.CreateConsole(userContext);
}
public override SaDiaryConsole CreateDiaryConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public override SaSecurityConsole CreateSecurityConsole(ISbmUserOrganisationContext userContext)
{
return new SbmSecurityConsole_Web(userContext);
}
public override SaCodeTypeConsole CreateCodeTypeConsole(ISbmUserOrganisationContext userContext)
{
return new SbmCodeTypeConsole_Web(userContext);
}
public override SaItemDataConsole CreateItemDataConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public override SaItemDocConsole CreateItemDocConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public override SaItemOptionConsole CreateItemOptionConsole(ISbmUserOrganisationContext userContext)
{
return new SbmItemOptionConsole_Web(userContext);
}
public override SaInterfaceConsole CreateInterfaceConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public override SaUpdateLogConsole CreateUpdateLogConsole(ISbmUserOrganisationContext userContext)
{
return new SbmUpdateLogConsole_Web(userContext);
}
public override SaReferenceDataConsole CreateReferenceDataConsole(ISbmUserOrganisationContext userContext)
{
return new SbmReferenceDataConsole_Portal(userContext);
}
public override SbmEmailConsole CreateEmailConsole(ISbmUserOrganisationContext userContext, SbmEmailConfig emailConfig)
{
return new SbmEmailConsole_Portal(emailConfig);
}
//-------------------------------------------------------------------
}
}
@@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Web.Portal.Models.Assets;
using Sarand.BusinessMgr.Web.Portal.Models.Commodities;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -14,19 +14,26 @@ using System.Collections.Generic;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
{
//=======================================================================
// Portal Asset Category Controller - Ajax actions.
//=======================================================================
partial class AssetCategoryController
{
//-------------------------------------------------------------------
// Definitions.
// AssetCategory data.
// Item data.
private class AssetCategoryListData : AjaxResponse_Data.ItemData_Base
{
public String TypeDesc { get; set; }
public String Code { get; set; }
public String DescBrief { get; set; }
public String Caption { get; set; }
public long? AssetCount { get; set; }
// Fields.
public class FieldData
{
// Item property values keyed to match field name.
public Dictionary<string, string> Value { get; } = new Dictionary<string, string>();
}
public FieldData Field { get; } = new FieldData();
}
private class AssetCategoryItemData : AssetCategoryListData
{
@@ -35,33 +42,111 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
private void PopulateAssetCategoryResponseListData(SbmModel_Portal model, AssetCategoryListData data, SbmAssetCategory assetCategory)
{
data.Id = SysId.ToString(assetCategory.Id);
data.TypeDesc = Internals.AssetTypeCodes.GetDescForType(assetCategory.AssetType);
// Prominent properties for selecting and editing.
data.Code = assetCategory.Code;
data.DescBrief = assetCategory.DescBrief;
data.StatusCode = assetCategory.StatusCode;
data.StatusDesc = assetCategory.StatusDesc;
data.Caption = assetCategory.DescBrief;
// Asset count.
long assetCount = Internals.AssetMgr.GetAssetCountForAssetCategory(assetCategory.Id);
if (assetCount > 0) data.AssetCount = assetCount;
}
private void PopulateAssetCategoryResponseItemData(SbmModel_Portal model, AssetCategoryItemData data, SbmAssetCategory assetCategory)
{
PopulateAssetCategoryResponseListData(model, data, assetCategory);
// Asset type - populate for list ('Type' property populated with desc) and form (Type Code & Desc).
data.TypeCode = Internals.AssetTypeCodes.GetCodeForType(assetCategory.AssetType);
data.Notes = assetCategory.Notes;
data.TypeDesc = Internals.AssetTypeCodes.GetDescForType(assetCategory.AssetType);
data.Field.Value.Add($"{Model_AssetCategory.ItemField.Type}", Internals.AssetTypeCodes.GetDescForType(assetCategory.AssetType));
// Asset Category properties.
data.Field.Value.Add($"{Model_AssetCategory.ItemField.Code}", assetCategory.Code);
data.Field.Value.Add($"{Model_AssetCategory.ItemField.Caption}", assetCategory.DescBrief);
// Common properties.
data.StatusCode = assetCategory.StatusCode;
data.StatusDesc = assetCategory.StatusDesc;
data.Field.Value.Add($"{Model_AssetCategory.ItemField.Status}", assetCategory.StatusDesc);
// Cleanse field values.
data.Field.Value.RemoveAll(item => StringUtil.IsBlank(item.Value));
// Populate item list values that might be cleared during update after removing blank values to ensure that blank values are published.
data.Field.Value.Add($"{Model_AssetCategory.ItemField.Notes}", assetCategory.Notes);
data.Field.Value.Add($"{Model_AssetCategory.ItemField.UpdatedOn}", Localiser.FormatDate(assetCategory.UpdateStamp.On));
}
//-------------------------------------------------------------------
// Get AssetCategory List ajax request.
// Asset Category configuration.
//-------------------------------------------------------------------
private class AjaxResponse_AssetCategoryList : AjaxResponse_Data
private class AjaxResponse_AssetCategoryConfig : AjaxResponse_Data
{
// Construction.
public AjaxResponse_AssetCategoryList(SbmModel_Portal model) : base(model) { }
// AssetCategory list.
public List<AssetCategoryListData> AssetCategories { get; } = new List<AssetCategoryListData>();
public AjaxResponse_AssetCategoryConfig(SbmModel_Portal model) : base(model) { }
// Configuration.
public Model_AssetCategory.ListConfigData Config { get; } = new Model_AssetCategory.ListConfigData();
public Model_AssetCategory.ItemConfigData ConfigItemNew { get; } = new Model_AssetCategory.ItemConfigData();
// Reference data.
public List<CodeDesc> AssetTypes { get; } = new List<CodeDesc>();
public List<CodeDesc> IncomeTypes { get; } = new List<CodeDesc>();
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
public List<CodeDesc> StatusesCreate { get; } = new List<CodeDesc>();
public String StatusCodeDefault { get; set; }
}
// Ajax request.
[HttpPost]
[Route("Assets/AssetCategory/Ajax/Config")]
[Route("Assets/AssetCategory/Ajax/GetConfig")]
public IActionResult Ajax_AssetCategoryConfig(Model_AssetCategory model)
{
AjaxResponse_AssetCategoryConfig responseData = new AjaxResponse_AssetCategoryConfig(model);
String messageTitle = Localiser["caption.asset.categories"];
// Validate session and referrer.
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
RefreshModel(model);
// Populate configuration data.
PopulateAssetCategoryConfig(model, responseData);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
private void PopulateAssetCategoryConfig(Model_AssetCategory model, AjaxResponse_AssetCategoryConfig responseData)
{
// Configuration.
model.PopulateListConfig(responseData.Config);
model.PopulateItemConfig(responseData.ConfigItemNew, null, Sbm.AssetType.Unknown);
// Reference data - select lists.
foreach (TypeCodeDesc assetType in GetCodesOfType(Sbm.SystemCode.AssetType))
responseData.AssetTypes.Add(assetType.Code, assetType.Desc);
foreach (TypeCodeDesc incomeType in GetCodesOfType(Sbm.SystemCode.AssetIncomeType))
responseData.IncomeTypes.Add(incomeType.Code, incomeType.Desc);
// Reference data - statuses.
foreach (SaStatus status in SbmAssetCategory.ValidStatuses)
{
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
if (status != SaStatus.Deleted)
responseData.StatusesCreate.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
}
responseData.StatusCodeDefault = SacsSystem.GetStatusCode(SbmAssetCategory.DefaultStatus);
}
//-------------------------------------------------------------------
// Asset Category List.
//-------------------------------------------------------------------
private class AjaxResponse_AssetCategoryList : AjaxResponse_AssetCategoryConfig
{
// Construction.
public AjaxResponse_AssetCategoryList(SbmModel_Portal model) : base(model) { }
// View mode.
public class ModeData
{
public bool? Search { get; set; }
public bool? Maintain { get; set; }
}
public ModeData Mode { get; set; }
// AssetCategory list.
public List<AssetCategoryListData> AssetCategories { get; } = new List<AssetCategoryListData>();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Assets/AssetCategory/Ajax/GetList")]
@@ -77,19 +162,21 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Reference data - statuses.
foreach (SaStatus status in SbmAssetCategory.ValidStatuses)
{
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
if (status != SaStatus.Deleted)
responseData.StatusesCreate.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
}
responseData.StatusCodeDefault = SacsSystem.GetStatusCode(SbmAssetCategory.DefaultStatus);
// Populate configuration data.
PopulateAssetCategoryConfig(model, responseData);
// View mode.
responseData.Mode = new AjaxResponse_AssetCategoryList.ModeData();
Model_AssetCategory.ViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_AssetCategory.ViewMode.Maintain)
responseData.Mode.Maintain = true;
else
responseData.Mode.Search = true;
// Item filter.
SbmAssetCategory.Params prmAssetCategory = new SbmAssetCategory.Params();
prmAssetCategory.Search = model.Filter.Search;
prmAssetCategory.StatusCat = model.Filter.GetStatusCat();
prmAssetCategory.StatusCat = model.GetFilterStatusCat();
model.Paging.ItemTotal = (ulong)AssetMgr.GetAssetCategoryCount(prmAssetCategory);
model.PopulatePagingTo(prmAssetCategory.ResultsPaging);
@@ -99,11 +186,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
ColumnDfn colCode = AssetMgr.GetAssetCategoryColumnDfn(SbmAssetCategory.Column.Code);
ColumnDfn colDescBrief = AssetMgr.GetAssetCategoryColumnDfn(SbmAssetCategory.Column.DescBrief);
ColumnDfn colAssetCount = AssetMgr.GetAssetCategoryColumnDfn(SbmAssetCategory.Column.AssetCount);
ColumnDfn colNotes = AssetMgr.GetAssetCategoryColumnDfn(SbmAssetCategory.Column.Notes);
ColumnDfn colStatus = AssetMgr.GetAssetCategoryColumnDfn(SbmAssetCategory.Column.Status);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId, colType, colCode, colDescBrief,
colAssetCount, colStatus
colAssetCount, colNotes, colStatus
};
// Query items.
@@ -116,15 +204,21 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
AssetCategoryListData assetCategoryData = new AssetCategoryListData()
{
Id = values.GetLong(colId.DataName).ToString(),
TypeDesc = Localiser.GetAssetTypeCaption(assetType),
Code = values.GetString(colCode.DataName),
DescBrief = values.GetString(colDescBrief.DataName),
Caption = values.GetString(colDescBrief.DataName),
TypeDesc = Localiser.GetAssetTypeCaption(assetType),
StatusCode = values.GetString(colStatus.DataName),
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
};
assetCategoryData.Field.Value.Add($"{Model_AssetCategory.ItemField.Type}", Internals.AssetTypeCodes.GetDescForType(assetType));
assetCategoryData.Field.Value.Add($"{Model_AssetCategory.ItemField.Code}", assetCategoryData.Code);
assetCategoryData.Field.Value.Add($"{Model_AssetCategory.ItemField.Caption}", assetCategoryData.Caption);
assetCategoryData.Field.Value.Add($"{Model_AssetCategory.ItemField.Notes}", AssetMgr.GetAssetCategoryDataValue(colNotes, values).ToString());
assetCategoryData.Field.Value.Add($"{Model_AssetCategory.ItemField.Status}", SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)));
long assetCount = values.GetLong(colAssetCount.DataName);
if (assetCount > 0)
assetCategoryData.AssetCount = assetCount;
// Cleanse item values.
assetCategoryData.Field.Value.RemoveAll(item => StringUtil.IsBlank(item.Value));
responseData.AssetCategories.Add(assetCategoryData);
}
}
@@ -144,7 +238,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
{
// Construction.
public AjaxResponse_AssetCategory(SbmModel_Portal model) : base(model) { }
// AssetCategory details.
// Configuration.
public Model_AssetCategory.ItemConfigData Config { get; } = new Model_AssetCategory.ItemConfigData();
// Asset Category details.
public AssetCategoryItemData assetCategory { get; } = new AssetCategoryItemData();
}
//-------------------------------------------------------------------
@@ -180,6 +276,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
}
// Construct response.
model.PopulateItemConfig(responseData.Config, assetCategory);
PopulateAssetCategoryResponseItemData(model, responseData.assetCategory, assetCategory);
responseData.Success = true;
}
@@ -243,15 +340,16 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
assetCategory = AssetMgr.CreateAssetCategory(model.AssetCategory.AssetType);
disposables.Add(assetCategory);
}
// Populate item properties.
if (model.AssetCategory.Code != null)
assetCategory.Code = model.AssetCategory.Code;
if (model.AssetCategory.DescBrief != null)
assetCategory.DescBrief = model.AssetCategory.DescBrief;
if (model.AssetCategory.Caption != null)
assetCategory.DescBrief = model.AssetCategory.Caption;
if (model.AssetCategory.StatusCode != null)
assetCategory.Status = model.AssetCategory.GetStatus();
assetCategory.Status = model.GetAssetCategoryStatus();
if (model.AssetCategory.Notes != null)
assetCategory.Notes = model.AssetCategory.Notes;
@@ -274,6 +372,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
}
// Construct response.
model.PopulateItemConfig(responseData.Config, assetCategory);
PopulateAssetCategoryResponseItemData(model, responseData.assetCategory, assetCategory);
responseData.Success = true;
}
@@ -26,7 +26,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
//-------------------------------------------------------------------
[Route("Assets/AssetCategory")]
public IActionResult Index()
public IActionResult Index(Model_AssetCategory model)
{
if (!ValidUserSession)
AutoLoginUser();
@@ -38,8 +38,11 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
return RedirectToAction("", "Security");
}
// AssetCategory page.
Model_AssetCategory model = new Model_AssetCategory(Localiser);
// Asset Category page.
RefreshModel(model);
model.PopulateListConfig();
model.Paging.PageNo = SessionData_Portal.Profile.Commodity.Filter.PageNo;
model.Paging.PageLength = SessionData_Portal.Profile.Commodity.Filter.PageLength;
return View("Views/Assets/AssetCategory/Index.cshtml", model);
}
@@ -108,7 +108,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
public AjaxResponse_CommodityConfig(SbmModel_Portal model) : base(model) { }
// Configuration.
public Model_Commodity.ListConfigData Config { get; } = new Model_Commodity.ListConfigData();
public Model_Commodity.ItemConfigData ConfigCmd { get; } = new Model_Commodity.ItemConfigData();
public Model_Commodity.ItemConfigData ConfigItemNew { get; } = new Model_Commodity.ItemConfigData();
// Reference data.
public List<CodeDesc> CommodityTypes { get; } = new List<CodeDesc>();
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
@@ -139,7 +139,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
{
// Configuration.
model.PopulateListConfig(responseData.Config);
model.PopulateItemConfig(responseData.ConfigCmd, null, Sbm.CommodityType.Unknown);
model.PopulateItemConfig(responseData.ConfigItemNew, null, Sbm.CommodityType.Unknown);
// Reference data - commodity types.
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
@@ -189,12 +189,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
// View mode.
responseData.Mode = new AjaxResponse_CommodityList.ModeData();
Model_Commodity.CommodityViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Commodity.CommodityViewMode.Maintain)
Model_Commodity.ViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Commodity.ViewMode.Maintain)
responseData.Mode.Maintain = true;
else if (viewMode == Model_Commodity.CommodityViewMode.StockControl)
else if (viewMode == Model_Commodity.ViewMode.StockControl)
responseData.Mode.StockControl = true;
else if (viewMode == Model_Commodity.CommodityViewMode.StockTake)
else if (viewMode == Model_Commodity.ViewMode.StockTake)
responseData.Mode.StockTake = true;
else
responseData.Mode.Search = true;
@@ -303,26 +303,29 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
if (!ValidReferer) return Forbid();
RefreshModel(model);
// Identify item.
SysId commodityId = SysId.ToSysId(model.Commodity.Id);
if (!SysId.IsValid(commodityId))
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SbmCommodity commodity = CommodityMgr.GetCommodityById(commodityId);
if (commodity == null)
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposables = new DisposableCollection<SacsHierarchyItem>())
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve commodity for Id: '{model.Commodity.Id}'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
// Identify item.
SysId commodityId = SysId.ToSysId(model.Commodity.Id);
if (!SysId.IsValid(commodityId))
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SbmCommodity commodity = CommodityMgr.GetCommodityById(commodityId);
disposables.Add(commodity);
if (commodity == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve commodity for Id: '{model.Commodity.Id}'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Construct response.
model.PopulateItemConfig(responseData.Config, commodity);
PopulateCommodityResponseItemData(commodity, responseData.commodity);
responseData.Success = true;
}
// Construct response.
model.PopulateItemConfig(responseData.Config, commodity);
PopulateCommodityResponseItemData(commodity, responseData.commodity);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
@@ -361,63 +364,65 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve existing item.
SbmCommodity commodity = CommodityMgr.GetCommodityById(commodityId);
if (commodity == null && SysId.IsValid(commodityId))
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposables = new DisposableCollection<SacsHierarchyItem>())
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve commodity for Id: '{model.Commodity.Id}'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Create new item if required.
if (commodity == null)
{
commodity = CommodityMgr.CreateCommodity(model.GetCommodityType(), model.Commodity.Code);
// Retrieve existing item.
SbmCommodity commodity = CommodityMgr.GetCommodityById(commodityId);
disposables.Add(commodity);
if (commodity == null && SysId.IsValid(commodityId))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve commodity for Id: '{model.Commodity.Id}'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Create new item if required.
if (commodity == null)
{
commodity = CommodityMgr.CreateCommodity(model.GetCommodityType(), model.Commodity.Code);
disposables.Add(commodity);
}
// Populate item properties.
if (model.Commodity.Type != null)
commodity.CommodityType = model.GetCommodityType();
if (model.Commodity.Code != null)
commodity.Code = model.Commodity.Code;
}
if (model.Commodity.DescBrief != null)
commodity.DescBrief = model.Commodity.DescBrief;
// Common properties.
if (model.Commodity.Notes != null)
commodity.Notes = model.Commodity.Notes;
if (model.Commodity.StatusCode != null)
commodity.Status = model.GetCommodityStatus();
// Populate item properties.
if (model.Commodity.Type != null)
commodity.CommodityType = model.GetCommodityType();
if (model.Commodity.Code != null)
commodity.Code = model.Commodity.Code;
if (model.Commodity.DescBrief != null)
commodity.DescBrief = model.Commodity.DescBrief;
// Common properties.
if (model.Commodity.Notes != null)
commodity.Notes = model.Commodity.Notes;
if (model.Commodity.StatusCode != null)
commodity.Status = model.GetCommodityStatus();
// Store item.
if (!SysId.IsValid(commodity.Id))
{
if (!CommodityMgr.InsertCommodity(commodity, DbUpdateInfo))
// Store item.
if (!SysId.IsValid(commodity.Id))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to insert commodity: {CommodityMgr.ErrorStateMessage}");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
if (!CommodityMgr.InsertCommodity(commodity, DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to insert commodity: {CommodityMgr.ErrorStateMessage}");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
responseData.SetNotification(messageTitle, Localiser["msg.item.created"]);
}
responseData.SetNotification(messageTitle, Localiser["msg.item.created"]);
}
else
{
if (!CommodityMgr.UpdateCommodity(commodity, DbUpdateInfo))
else
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update commodity [Id:{SysId.ToLong(commodity.Id)}]: {CommodityMgr.ErrorStateMessage}");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
if (!CommodityMgr.UpdateCommodity(commodity, DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update commodity [Id:{SysId.ToLong(commodity.Id)}]: {CommodityMgr.ErrorStateMessage}");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
responseData.SetNotification(messageTitle, Localiser["msg.item.updated"]);
}
responseData.SetNotification(messageTitle, Localiser["msg.item.updated"]);
UpdateAssociatedData(commodity);
// Construct response.
model.PopulateItemConfig(responseData.Config, commodity);
PopulateCommodityResponseItemData(commodity, responseData.commodity);
responseData.Success = true;
}
UpdateAssociatedData(commodity);
// Construct response.
model.PopulateItemConfig(responseData.Config, commodity);
PopulateCommodityResponseItemData(commodity, responseData.commodity);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
@@ -199,12 +199,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
// View mode.
responseData.Mode = new AjaxResponse_AssociationList.ModeData();
Model_Association.AssociationViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Association.AssociationViewMode.Maintain)
Model_Association.ViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Association.ViewMode.Maintain)
responseData.Mode.Maintain = true;
else if (viewMode == Model_Association.AssociationViewMode.Relationships)
else if (viewMode == Model_Association.ViewMode.Relationships)
responseData.Mode.Relationships = true;
else if (viewMode == Model_Association.AssociationViewMode.PriceSet)
else if (viewMode == Model_Association.ViewMode.PriceSet)
responseData.Mode.PriceSet = true;
else
responseData.Mode.Search = true;
@@ -205,8 +205,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
// View mode.
responseData.Mode = new AjaxResponse_ContactList.ModeData();
Model_Contact.ContactViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Contact.ContactViewMode.Maintain)
Model_Contact.ViewMode viewMode = model.GetFilterMode();
if (viewMode == Model_Contact.ViewMode.Maintain)
responseData.Mode.Maintain = true;
else
responseData.Mode.Search = true;
@@ -215,7 +215,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
SbmAffiliate.Params prmAffiliate = new SbmAffiliate.Params();
prmAffiliate.Search = model.Filter.Search;
prmAffiliate.AffiliateType = model.GetFilterContactType();
if (prmAffiliate.AffiliateType == Sbm.AffiliateType.Any && viewMode == Model_Contact.ContactViewMode.Search)
if (prmAffiliate.AffiliateType == Sbm.AffiliateType.Any && viewMode == Model_Contact.ViewMode.Search)
prmAffiliate.AffiliateType = Sbm.AffiliateType.AnyContact;
prmAffiliate.StatusCat = SbmAffiliate.StatusCat.NotDeleted;
prmAffiliate.SortColumns.Add(AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Name));
@@ -28,6 +28,16 @@ using DocumentFormat.OpenXml.EMMA;
using DocumentFormat.OpenXml.Wordprocessing;
using Sarand.BusinessMgr.Net.Core.Web.Models;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.Net.Standard.Base.CodeTypes;
using Sarand.Net.Standard.Base.Diary;
using Sarand.Net.Standard.Base.Email;
using Sarand.Net.Standard.Base.Interfaces;
using Sarand.Net.Standard.Base.ItemData;
using Sarand.Net.Standard.Base.ItemDocs;
using Sarand.Net.Standard.Base.ItemOptions;
using Sarand.Net.Standard.Base.ReferenceData;
using Sarand.Net.Standard.Base.UpdateLog;
namespace Sarand.BusinessMgr.Web.Portal.Controllers
{
@@ -38,6 +48,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
{
//-------------------------------------------------------------------
// Data members.
private SbmInternals internals;
private SbmSysParamCache sysParamCache = null;
//-------------------------------------------------------------------
@@ -49,12 +60,44 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
{
if (disposing)
{
if (sysParamCache != null) sysParamCache.Dispose();
sysParamCache = null;
if (internals != null) internals.Dispose(); internals = null;
if (sysParamCache != null) sysParamCache.Dispose(); sysParamCache = null;
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
public SbmInternals Internals { get { if (internals == null && UserContext_Core != null) { internals = new SbmInternals(UserContext_Core); } return internals; } }
// Managers.
public SbmAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
public SbmAssetMgr AssetMgr { get { return Internals.AssetMgr; } }
public SbmCommodityMgr CommodityMgr { get { return Internals.CommodityMgr; } }
public SbmPriceMgr PriceMgr { get { return Internals.PriceMgr; } }
public SbmTransactionMgr TransactionMgr { get { return Internals.TransactionMgr; } }
public SbmStockMgr StockMgr { get { return Internals.StockMgr; } }
public SbmProcessMgr ProcessMgr { get { return Internals.ProcessMgr; } }
public SbmDataItemMgr DataItemMgr { get { return Internals.DataItemMgr; } }
// Consoles.
public SbmSessionConsole SessionConsole { get { return Internals.SessionConsole; } }
public SaDiaryConsole DiaryConsole { get { return Internals.DiaryConsole; } }
public SaSecurityConsole SecurityConsole { get { return Internals.SecurityConsole; } }
public SaCodeTypeConsole CodeTypeConsole { get { return Internals.CodeTypeConsole; } }
public SaReferenceDataConsole ReferenceDataConsole { get { return Internals.ReferenceDataConsole; } }
public SaUpdateLogConsole UpdateLogConsole { get { return Internals.UpdateLogConsole; } }
public SaInterfaceConsole InterfaceConsole { get { return Internals.InterfaceConsole; } }
public SaItemDocConsole ItemDocConsole { get { return Internals.ItemDocConsole; } }
public SaItemOptionConsole ItemOptionConsole { get { return Internals.ItemOptionConsole; } }
public SaItemDataConsole ItemDataConsole { get { return Internals.ItemDataConsole; } }
// Configurations.
public SbmStockControlConfig StockControlConfig { get { return Internals.StockControlConfig; } }
public SbmRequirementCostingConfig RequirementCostingConfig { get { return Internals.RequirementCostingConfig; } }
// System codes.
public List<TypeCodeDesc> GetCodesOfType(Sbm.SystemCode systemCode) { return Internals.GetSystemCodes(systemCode); }
// Email.
public SaEmailConfig EmailConfig { get { return Internals.EmailConfig; } }
public SbmEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
//-------------------------------------------------------------------
// Session data.
@@ -84,24 +127,26 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
/// <para>- Open user session - store details against Sesion Data.</para>
/// <para>- Set 'Keep logged in' cookie if required.</para>
/// </summary>
protected bool SignUserIn(SbmInternals internalsForUser, String repositoryContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation, bool keepLoggedIn, ref String errorMessage)
protected bool SignUserIn(SbmSessionData_Portal sessionDataForUser, SbmInternals internalsForUser, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation, bool keepLoggedIn, ref String errorMessage)
{
string errorPrefix = $"Unable to sign account in";
string errorSuffix = $"Context: {sessionDataForUser.RepositoryContext}. Email: {sessionDataForUser.UserEmailAddress}.";
// Validate Security Item and Affiliate, just in case - should have been done before arriving here!
if (securityItemUser == null)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - null security item.");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - null security item. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (affiliateUser == null)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - null affiliate.");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - null affiliate. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (!affiliateUser.IsStatusCurrent)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - affiliate is not active. Email: {securityItemUser.EmailAddress}");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - affiliate is not active. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
@@ -109,54 +154,64 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
// Organisation.
if (associationOrganisation == null)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - null organisation association.");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - null organisation association. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (associationOrganisation.AssociationType != Sbm.AssociationType.Internal)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - organisation association is not type 'Internal'.");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - organisation association is not type 'Internal'. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (affiliateOrganisation == null)
{
SaLogger.Error($"{SysUtil.Fn} Unable to sign account in - null organisation affiliate.");
SaLogger.Error($"{SysUtil.Fn} {errorPrefix} - null organisation affiliate. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// Verify Organisation is supervised by User.
if (!internalsForUser.AccountMgr.IsAffiliateSupervisedBy(affiliateOrganisation.Id, affiliateUser.Id))
{
SaLogger.Warn($"{SysUtil.Fn} {errorPrefix} - Organisation is not supervised by user. {errorSuffix}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// Configure security profile.
sessionDataForUser.SecurityProfile_Core.RefreshProfile(internalsForUser.SessionConsole, internalsForUser.SecurityConsole, securityItemUser.Id, internalsForUser.SecurityConsole.GetRegisteredRights());
// 'Keep logged in' can be switched off by the application configuration.
keepLoggedIn = App.AppConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
using (DisposableCollection<SacsDisposable> disposables = new DisposableCollection<SacsDisposable>())
// Log user in.
securityItemUser.LastLogin = DateTime.Now;
securityItemUser.InvalidLoginCount = 0;
securityItemUser.LastInvalidLoginAt = DateTime.MinValue;
if (!internalsForUser.SecurityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
{
// Log user in.
securityItemUser.LastLogin = DateTime.Now;
securityItemUser.InvalidLoginCount = 0;
securityItemUser.LastInvalidLoginAt = DateTime.MinValue;
if (!internalsForUser.SecurityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update security item for {securityItemUser.EmailAddress}: {internalsForUser.SecurityConsole.ErrorStateMessage}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
SaLogger.Warn($"{SysUtil.Fn} Failed to update security item for {securityItemUser.EmailAddress}: {internalsForUser.SecurityConsole.ErrorStateMessage}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// Update affiliate.
affiliateUser.KeepLoggedIn_Portal = keepLoggedIn;
if (!internalsForUser.AccountMgr.UpdateAffiliate(affiliateUser, DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update affiliate for {securityItemUser.EmailAddress}: {internalsForUser.AccountMgr.ErrorStateMessage}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
SaLogger.Info($"{SysUtil.Fn} User session opened for {securityItemUser.EmailAddress}", true);
// Update affiliate.
affiliateUser.KeepLoggedIn_Portal = keepLoggedIn;
if (!internalsForUser.AccountMgr.UpdateAffiliate(affiliateUser, DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update affiliate for {securityItemUser.EmailAddress}: {internalsForUser.AccountMgr.ErrorStateMessage}");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
SaLogger.Info($"{SysUtil.Fn} User session opened for {securityItemUser.EmailAddress}", true);
// Create session.
OpenUserSession(internalsForUser.SessionContext, repositoryContext, securityItemUser, affiliateUser, supervisedOrganisations, associationOrganisation, affiliateOrganisation);
// Configure security profile.
SessionData_Portal.SecurityProfile_Core.RefreshProfile(SessionConsole, internalsForUser.SecurityConsole, securityItemUser.Id, internalsForUser.SecurityConsole.GetRegisteredRights());
// Create session.
if (!OpenUserSession(sessionDataForUser))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to open user session. Repository context: {sessionDataForUser.RepositoryContext}. Email: {securityItemUser.EmailAddress}.");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// Send the 'Keep Logged In' cookie if requested.
@@ -168,7 +223,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
//-------------------------------------------------------------------
/// <summary>Populate the user's profile contact details to the session.</summary>
protected bool RefreshSessionProfileContact(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation)
protected bool RefreshSessionData(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation)
{
SbmSessionData_Portal sessionData = SessionData_Portal;
SysId affiliateIdUser = sessionData?.User?.AffiliateId ?? null;
@@ -177,24 +232,30 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
if (!affiliateIdUser.Equals(affiliateUser.Id)) return false;
if (!SysId.IsValid(affiliateOrganisation?.Id ?? null)) return false;
sessionData.RefreshUser(securityItemUser, affiliateUser, supervisedOrganisations, associationOrganisation, affiliateOrganisation);
sessionData.Refresh(securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation);
return true;
}
//-------------------------------------------------------------------
/// <summary>Start a new user session on sign-in.</summary>
protected bool OpenUserSession(SbmSessionContext sessionContext, String repositoryContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, List<SysIdString> supervisedOrganisations, SbmAssociation associationOrganisation, SbmAffiliate affiliateOrganisation)
protected bool OpenUserSession(SbmSessionData_Portal sessionDataForUser)
{
// Validate user properties.
if (!SysId.IsValid(affiliateUser.Id)) return false;
if (StringUtil.IsEmpty(securityItemUser.EmailAddress)) return false;
if (!SysId.IsValid(sessionDataForUser.UserAffiliateId))
{
return false;
}
if (StringUtil.IsBlank(sessionDataForUser.UserEmailAddress))
{
return false;
}
// Close previous session.
CloseUserSession();
// Open session.
return SetSessionData(new SbmSessionData_Portal(sessionContext, repositoryContext, securityItemUser, affiliateUser, supervisedOrganisations, associationOrganisation, affiliateOrganisation));
return SetSessionData(sessionDataForUser);
}
protected void CloseUserSession()
{
@@ -267,8 +328,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
if (sessionContext != null)
{
// Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SbmInternals internalsForUser = new SbmInternals(userContext))
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContext, keepLoggedInParams.RepositoryContext, null, null, null, null);
using (SbmInternals internalsForUser = new SbmInternals(sessionDataForUser))
{
using (SaSecurityItem securityItemUser = internalsForUser.SecurityConsole.GetUserByEmail(keepLoggedInParams.EmailAddress))
using (SbmAffiliate affiliateUser = internalsForUser.AccountMgr.GetAffiliateById(keepLoggedInParams.AffiliateIdUser))
@@ -281,10 +342,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
{
if (affiliateUser.IsStatusCurrent)
{
List<SysIdString> supervisedOrganisations = internalsForUser.AccountMgr.GetAffiliatesSupervisedBy(affiliateUser.Id);
// Bring the Session Data up to date with the session properties.
sessionDataForUser.Refresh(securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation);
String errorMessage = "";
if (SignUserIn(internalsForUser, keepLoggedInParams.RepositoryContext, securityItemUser, affiliateUser, supervisedOrganisations, associationOrganisation, affiliateOrganisation, true, ref errorMessage))
if (SignUserIn(sessionDataForUser, internalsForUser, securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation, true, ref errorMessage))
{
// User auto-login successful.
SaLogger.Info(logPrefix + " 'Keep Logged In' cookie found." + logSuffix);
return true;
}
@@ -93,24 +93,24 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{
if (sessionContext == null) return false;
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContext, model.RepositoryContext, null, null, null, null);
ISacsDatabase busMgrDatabase = App.GetBusMgrDatabase(sessionContext);
if (busMgrDatabase == null) return false;
using (DisposableCollection<IDisposable> disposables = new DisposableCollection<IDisposable>())
{
SbmInternals internalsForUser = new SbmInternals(userContext);
SbmInternals internalsForUser = new SbmInternals(sessionDataForUser);
disposables.Add(internalsForUser);
// User's security item.
SaSecurityItem securityItemUser = GetSecurityItemForSignin(userContext, internalsForUser.SecurityConsole, model);
SaSecurityItem securityItemUser = GetSecurityItemForSignin(sessionDataForUser, internalsForUser.SecurityConsole, model);
disposables.Add(securityItemUser);
if (securityItemUser == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}.");
return false;
}
if (!internalsForUser.SecurityConsole.PasswordMatches(securityItemUser, model.Password, userContext.DbUpdateInfo))
if (!internalsForUser.SecurityConsole.PasswordMatches(securityItemUser, model.Password, sessionDataForUser.DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Supplied password doesn't match Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}.");
return false;
@@ -125,17 +125,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
return false;
}
// User's supervised organisations.
List<SysIdString> supervisedOrganisations = internalsForUser.AccountMgr.GetAffiliatesSupervisedBy(affiliateUser.Id);
if (supervisedOrganisations.IsEmpty())
{
SaLogger.Warn($"{SysUtil.Fn} User has no supervised organisations. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}.");
return false;
}
userContext.RefreshUser(securityItemUser, affiliateUser, supervisedOrganisations);
// User's organisation association.
SbmAssociation associationOrganisation = GetOrganisationAssociationForSignIn(internalsForUser.AccountMgr, model, userContext);
SbmAssociation associationOrganisation = GetOrganisationAssociationForSignIn(internalsForUser.AccountMgr, model, sessionDataForUser);
disposables.Add(associationOrganisation);
if (associationOrganisation == null)
{
@@ -152,15 +143,18 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
return false;
}
// Populate User properties to the Session Data.
sessionDataForUser.Refresh(securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation);
// Initialise user session.
if (SignUserIn(internalsForUser, model.RepositoryContext, securityItemUser, affiliateUser, supervisedOrganisations, associationOrganisation, affiliateOrganisation, model.KeepMeSignedIn, ref errorMessage))
if (SignUserIn(sessionDataForUser, internalsForUser, securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation, model.KeepMeSignedIn, ref errorMessage))
return true;
}
return false;
}
//-------------------------------------------------------------------
private SaSecurityItem GetSecurityItemForSignin(SbmUserContext_Web userContext, SaSecurityConsole securityConsoleForUser, Model_Security model)
private SaSecurityItem GetSecurityItemForSignin(ISbmUserContext userContext, SaSecurityConsole securityConsoleForUser, Model_Security model)
{
// Retrieve security item by email address.
SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(model.EmailAddress);
@@ -216,13 +210,14 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
/// <summary>
/// Identify the organisation for the user to login to - either last selected (via SysParam) or first in list.
/// </summary>
private SbmAssociation GetOrganisationAssociationForSignIn(SbmAccountMgr accountMgrForUser, Model_Security model, SbmUserContext userContext)
private SbmAssociation GetOrganisationAssociationForSignIn(SbmAccountMgr accountMgrForUser, Model_Security model, ISbmUserOrganisationContext userContext)
{
// Previously selected organisation is stored in user params (SysParam table).
SbmSysParamCache sysParamCache = new SbmSysParamCache(userContext, userContext.UserAffiliateId);
SysId affiliateIdOrganisation = SysId.ToSysId(sysParamCache.GetUserParamValue(SbmSysParamCache.ParamName_SelectedCompany));
SbmAssociation associationOrganisation = null;
foreach (SysIdString supervisedOrganisation in userContext.SupervisedOrganisations)
List<SysIdString> supervisedOrganisations = accountMgrForUser.GetAffiliatesSupervisedBy(userContext.UserAffiliateId);
foreach (SysIdString supervisedOrganisation in supervisedOrganisations)
{
SbmAssociation associationOrganisationCandidate = accountMgrForUser.GetAssociationByOwnerTypeTarget(supervisedOrganisation.Id, Sbm.AssociationType.Internal, supervisedOrganisation.Id);
if (associationOrganisationCandidate == null)
@@ -374,10 +369,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
// Validate referrer.
if (!ValidReferer) return Forbid();
// If user is logged in, session Consoles and Managers can be used.
// If 'Request Password' parameters are specified, Consoles and Managers must be associated with the specific database for the user.
SbmSessionContext sessionContextForUser = null;
SbmUserContext_Web userContextForUser = null;
// If user is logged in, session Internals can be used.
// If 'Request Password' parameters are specified, Internals must be associated with the specific context for the user.
SbmInternals internalsForUser = null;
// If 'Request Password' encrypted params (from email link) are present,
// Session is not required and password can be set directly against the user.
@@ -389,29 +383,27 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (storePasswordParams.IsValid())
{
// Instance Repository configured on Control database identified by Context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(storePasswordParams.RepositoryContext);
if (sessionContext != null)
SbmSessionContext sessionContextForUser = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(storePasswordParams.RepositoryContext);
if (sessionContextForUser != null)
{
// Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SbmInternals internalsForUser = new SbmInternals(userContext))
// Consoles and Managers must be associated with the specific context for the User storing the password.
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContextForUser, storePasswordParams.RepositoryContext, null, null, null, null);
internalsForUser = new SbmInternals(sessionDataForUser);
// Retrieve user details and validate email address.
securityItemUser = internalsForUser.SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, storePasswordParams.SecurityItemId);
affiliateUser = internalsForUser.AccountMgr.GetAffiliateById(storePasswordParams.AffiliateId);
if (storePasswordParams.IsValid(securityItemUser, affiliateUser))
{
// Retrieve user details and validate email address.
securityItemUser = internalsForUser.SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, storePasswordParams.SecurityItemId);
affiliateUser = internalsForUser.AccountMgr.GetAffiliateById(storePasswordParams.AffiliateId);
if (storePasswordParams.IsValid(securityItemUser, affiliateUser))
{
sessionContextForUser = sessionContext;
userContextForUser = userContext;
validRequestPasswordParams = true;
validSessionRequired = false;
}
else
{
SaLogger.Warn($"{SysUtil.Fn} 'Request Password' parameters supplied but invalid. Email: {storePasswordParams.EmailAddress}. SecurityItemId: {SysId.ToString(storePasswordParams.SecurityItemId)}. AffiliateId: {SysId.ToString(storePasswordParams.AffiliateId)}.");
if (securityItemUser != null) securityItemUser.Dispose(); securityItemUser = null;
if (affiliateUser != null) affiliateUser.Dispose(); affiliateUser = null;
}
sessionDataForUser.Refresh(securityItemUser, affiliateUser, null, null);
validRequestPasswordParams = true;
validSessionRequired = false;
}
else
{
SaLogger.Warn($"{SysUtil.Fn} 'Request Password' parameters supplied but invalid. Email: {storePasswordParams.EmailAddress}. SecurityItemId: {SysId.ToString(storePasswordParams.SecurityItemId)}. AffiliateId: {SysId.ToString(storePasswordParams.AffiliateId)}.");
if (securityItemUser != null) securityItemUser.Dispose(); securityItemUser = null;
if (affiliateUser != null) affiliateUser.Dispose(); affiliateUser = null;
if (internalsForUser != null) internalsForUser.Dispose(); internalsForUser = null;
}
}
}
@@ -420,20 +412,24 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (validSessionRequired && (securityItemUser == null || affiliateUser == null) && !ValidUserSession)
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
// User specific Consoles and Managers if User Context specified.
using (SaSecurityConsole securityConsoleForUser = userContextForUser != null ? App.CreateSecurityConsole(userContextForUser) : null)
using (SbmAccountMgr accountMgrForUser = userContextForUser != null ? App.System.CreateAccountMgr(userContextForUser) : null)
// User specific Internals if Request Password params supplied, otherwise use Session Internals for current User Session.
SbmInternals internalsForStorePassword = internalsForUser ?? Internals;
using (DisposableCollection<SacsDisposable> disposables = new DisposableCollection<SacsDisposable>())
{
SaSecurityConsole securityConsole = (securityConsoleForUser ?? SecurityConsole);
SbmAccountMgr accountMgr = (accountMgrForUser ?? AccountMgr);
disposables.Add(internalsForUser);
disposables.Add(securityItemUser);
disposables.Add(affiliateUser);
// Retrieve user details if not previously populated.
if (securityItemUser == null && SessionData_Portal != null)
securityItemUser = (securityConsole.GetSecurityItemById(SaSecurity.ItemType.User, SessionData_Portal.User.SecurityItemId));
securityItemUser = internalsForStorePassword.SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, SessionData_Portal.User.SecurityItemId);
disposables.Add(securityItemUser);
if (securityItemUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve security item details."));
if (affiliateUser == null && SessionData_Portal != null)
affiliateUser = accountMgr.GetAffiliateById(SessionData_Portal.User.AffiliateId);
affiliateUser = internalsForStorePassword.AccountMgr.GetAffiliateById(SessionData_Portal.User.AffiliateId);
disposables.Add(affiliateUser);
if (affiliateUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve affiliate details."));
@@ -447,7 +443,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
// Store password.
// NB Do not use Microsoft.AspNetCore.Identity.PasswordHasher.HashPassword() while legacy (C++) desktop application still in use.
securityConsole.SetPassword(securityItemUser, model.Password);
internalsForStorePassword.SecurityConsole.SetPassword(securityItemUser, model.Password);
securityItemUser.PasswordChangedAt = DateTime.Now;
// Remove new password from history if present.
for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++)
@@ -465,21 +461,14 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
securityItemUser.PasswordHistory.Add(oldPasswordHashed);
while (securityItemUser.PasswordHistory.Count > 10)
securityItemUser.PasswordHistory.RemoveAt(securityItemUser.PasswordHistory.Count - 1);
if (!securityConsole.UpdateSecurityItem(securityItemUser, userContextForUser?.DbUpdateInfo ?? DbUpdateInfo))
if (!internalsForStorePassword.SecurityConsole.UpdateSecurityItem(securityItemUser, internalsForStorePassword.DbUpdateInfo))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to change password for {securityItemUser.EmailAddress}: {securityConsole.ErrorStateMessage}");
SaLogger.Warn($"{SysUtil.Fn} Failed to change password for {securityItemUser.EmailAddress}: {internalsForStorePassword.SecurityConsole.ErrorStateMessage}");
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
}
SaLogger.Info($"{SysUtil.Fn} Password changed for {securityItemUser.EmailAddress}.", true);
}
// Cleanup. NB The Security Item and/or Affiliate aren't disposed when the method
// returns above but these objects shouldn't be carrying any disposable resources.
if (securityItemUser != null) securityItemUser.Dispose(); securityItemUser = null;
if (affiliateUser != null) affiliateUser.Dispose(); affiliateUser = null;
sessionContextForUser = null;
userContextForUser = null;
// Construct response.
responseData.Success = true;
if (validRequestPasswordParams)
@@ -517,10 +506,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext);
if (sessionContext != null)
{
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContext, model.RepositoryContext, null, null, null, null);
// Get user security item and affiliate.
using (SbmInternals internalsForUser = new SbmInternals(userContext))
using (SbmInternals internalsForUser = new SbmInternals(sessionDataForUser))
using (SaSecurityItem securityItemUser = internalsForUser.SecurityConsole.GetUserByEmail(model.EmailAddress))
{
if (securityItemUser != null)
@@ -529,16 +518,17 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{
if (affiliateUser != null)
{
sessionDataForUser.Refresh(securityItemUser, affiliateUser, null, null);
if (affiliateUser.Status == SaStatus.Current || affiliateUser.IsStatusActive)
{
SbmEmailConsole emailConsole = App.CreateEmailConsole(userContext);
SbmEmailConsole emailConsole = internalsForUser.EmailConsole;
// Send password request email.
SaEmailData emailData = new SaEmailData();
emailData.Config = App.EmailConfig;
emailData.AddressesTo.Add(model.EmailAddress);
emailData.Subject = Localiser["security.caption.request.password"];
PopulateRequestPasswordEmailBody(emailConsole, userContext, emailData, securityItemUser, affiliateUser);
PopulateRequestPasswordEmailBody(emailConsole, sessionDataForUser, emailData, securityItemUser, affiliateUser);
if (emailConsole.SendEmail(emailData))
SaLogger.Info($"{SysUtil.Fn} Password request email sent to {model.EmailAddress}.", true);
else SaLogger.Warn($"{SysUtil.Fn} Failed to send password request email to {model.EmailAddress}.");
@@ -17,6 +17,7 @@ using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Sarand.BusinessMgr.Web.Portal.Helpers;
using Sarand.BusinessMgr.Web.Portal.App;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{
@@ -81,12 +82,13 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (sessionContext != null)
{
// Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SbmInternals internalsForUser = new SbmInternals(userContext))
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContext, changePasswordParams.RepositoryContext, null, null, null, null);
using (SbmInternals internalsForUser = new SbmInternals(sessionDataForUser))
{
using (SaSecurityItem securityItemUser = internalsForUser.SecurityConsole.GetUserByEmail(changePasswordParams.EmailAddress))
using (SbmAffiliate affiliateUser = internalsForUser.AccountMgr.GetAffiliateById(changePasswordParams.AffiliateId))
{
sessionDataForUser.Refresh(securityItemUser, affiliateUser, null, null);
if (securityItemUser != null && affiliateUser != null)
{
if (securityItemUser.Id.Equals(changePasswordParams.SecurityItemId) && affiliateUser.UserId.Equals(securityItemUser.Id))
@@ -96,7 +96,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Transactions
public AjaxResponse_TransactionConfig(SbmModel_Portal model) : base(model) { }
// Configuration.
public Model_Transaction.ListConfigData Config { get; } = new Model_Transaction.ListConfigData();
public Model_Transaction.ItemConfigData ConfigCmd { get; } = new Model_Transaction.ItemConfigData();
public Model_Transaction.ItemConfigData ConfigItemNew { get; } = new Model_Transaction.ItemConfigData();
// Reference data.
public List<CodeDesc> TransactionTypes { get; } = new List<CodeDesc>();
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
@@ -127,7 +127,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Transactions
{
// Configuration.
model.PopulateListConfig(responseData.Config);
model.PopulateItemConfig(responseData.ConfigCmd, null, Sbm.TransactionType.Unknown);
model.PopulateItemConfig(responseData.ConfigItemNew, null, Sbm.TransactionType.Unknown);
// Reference data - transaction types.
foreach (TypeCodeDesc transactionType in GetCodesOfType(Sbm.SystemCode.TransactionType))
@@ -3,7 +3,7 @@ using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Web.Portal.Models.Assets;
using Sarand.BusinessMgr.Web.Portal.Models.Vehicles;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -13,7 +13,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Vehicles
{
//=======================================================================
partial class VehicleClassController
@@ -71,9 +71,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Assets/VehicleClass/Ajax/GetList")]
[Route("Assets/VehicleClass/Ajax/GetVehicleClasses")]
[Route("Assets/VehicleClass/Ajax/GetVehicleClassList")]
[Route("Vehicles/VehicleClass/Ajax/GetList")]
[Route("Vehicles/VehicleClass/Ajax/GetVehicleClasses")]
[Route("Vehicles/VehicleClass/Ajax/GetVehicleClassList")]
public IActionResult Ajax_GetVehicleClassList(Model_VehicleClass model)
{
String messageTitle = Localiser["caption.vehicle.classes"];
@@ -96,7 +96,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
// Item filter.
SbmVehicleClass.Params prmVehicleClass = new SbmVehicleClass.Params();
prmVehicleClass.Search = model.Filter.Search;
prmVehicleClass.StatusCat = model.Filter.GetStatusCat();
prmVehicleClass.StatusCat = model.GetFilterStatusCat();
model.Paging.ItemTotal = (ulong)AssetMgr.GetVehicleClassCount(prmVehicleClass);
model.PopulatePagingTo(prmVehicleClass.ResultsPaging);
@@ -157,8 +157,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Assets/VehicleClass/Ajax/GetItem")]
[Route("Assets/VehicleClass/Ajax/GetVehicleClass")]
[Route("Vehicles/VehicleClass/Ajax/GetItem")]
[Route("Vehicles/VehicleClass/Ajax/GetVehicleClass")]
public IActionResult Ajax_GetVehicleClass(Model_VehicleClass model)
{
String messageTitle = Localiser["caption.vehicle.class"];
@@ -198,8 +198,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
// Store VehicleClass ajax request.
//-------------------------------------------------------------------
[HttpPost]
[Route("Assets/VehicleClass/Ajax/StoreItem")]
[Route("Assets/VehicleClass/Ajax/StoreVehicleClass")]
[Route("Vehicles/VehicleClass/Ajax/StoreItem")]
[Route("Vehicles/VehicleClass/Ajax/StoreVehicleClass")]
public IActionResult Ajax_StoreVehicleClass(Model_VehicleClass model)
{
String messageTitle = Localiser["caption.vehicle.class"];
@@ -2,14 +2,14 @@
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Web.Portal.Models.Assets;
using Sarand.BusinessMgr.Web.Portal.Models.Vehicles;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Vehicles
{
//======================================================================
public partial class VehicleClassController : SbmController_Portal
@@ -25,7 +25,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
}
//-------------------------------------------------------------------
[Route("Assets/VehicleClass")]
[Route("Vehicles/VehicleClass")]
public IActionResult Index()
{
if (!ValidUserSession)
@@ -40,7 +40,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
// VehicleClass page.
Model_VehicleClass model = new Model_VehicleClass(Localiser);
return View("Views/Assets/VehicleClass/Index.cshtml", model);
return View("Views/Vehicles/VehicleClass/Index.cshtml", model);
}
//-------------------------------------------------------------------
@@ -15,7 +15,7 @@ using System;
namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
{
//=======================================================================
public class Model_Asset : SbmModel_Portal
public partial class Model_Asset : SbmModel_Portal
{
//-------------------------------------------------------------------
// Construction.
@@ -0,0 +1,258 @@
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm;
namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
{
//=======================================================================
// Asset Category model - Configuration.
//=======================================================================
partial class Model_AssetCategory
{
//-------------------------------------------------------------------
/// <summary>Prefix for field names.</summary>
public const String FieldNamePrefix = "AssetCat";
/// <summary>Item fields.</summary>
public enum ItemField
{
// AssetCategory properties.
Id,
// Identity.
Type,
Code,
Caption,
// Defaults.
IncomeType,
// Purchase.
TaxCodePurchase,
PaymentTerms,
// Sale.
TaxCodeSale,
TaxCodeProfit,
// Associated properties.
AssetCount,
// Common.
Notes,
Status,
CreatedOn,
UpdatedOn,
Actions,
}
/// <summary>
/// Identifier used by form fields to show control specific messages generated by model validation etc.
/// <para>- Both page and model should use this method to consistently generate the field name.</para>
/// </summary>
public static String GetFieldName(ItemField field)
{
return $"{FieldNamePrefix}{field}";
}
// List configuration.
public class ListConfigData
{
// Actions.
public class ActionData
{
public class AllowData
{
public bool? Create { get; set; }
public bool? Update { get; set; }
}
public AllowData Allow { get; } = new AllowData();
}
public ActionData Action { get; } = new ActionData();
// List columns.
public class ColumnData
{
// Column name prefix.
public String Prefix { get; } = Model_AssetCategory.FieldNamePrefix;
// Hide column.
public HashSet<string> Hide { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Column labels.
public Dictionary<String, String> Label { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
}
public ColumnData Column { get; } = new ColumnData();
}
public ListConfigData ListConfig { get; private set; }
//-------------------------------------------------------------------
/// <summary>
/// Populate AssetCategory list configuration data - only required on initial page construction.
/// </summary>
public void PopulateListConfig()
{
ListConfig = new ListConfigData();
PopulateListConfig(ListConfig);
}
public void PopulateListConfig(ListConfigData config)
{
ViewMode pageMode = GetFilterMode();
bool modeIsSearch = pageMode == ViewMode.Search;
bool modeIsMaintain = pageMode == ViewMode.Maintain;
bool userCanCreateAssetCategories = SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(Sbm.ItemType.AssetCategory);
bool userCanUpdateAssetCategories = SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(Sbm.ItemType.AssetCategory);
// Actions.
if (userCanCreateAssetCategories)
config.Action.Allow.Create = true;
if (userCanUpdateAssetCategories)
config.Action.Allow.Update = true;
// List columns.
if (GetFilterAssetType() <= 0)
config.Column.Hide.Add($"{ItemField.Type}");
// Asset Category Assets.
if (!modeIsMaintain || !SessionConsole.AllowOption(Sbm.ConfigOption.Assets))
config.Column.Hide.Add($"{ItemField.AssetCount}");
// Actions.
if (!modeIsMaintain)
config.Column.Hide.Add($"{ItemField.Actions}");
}
//-------------------------------------------------------------------
// Item configuration.
//-------------------------------------------------------------------
// Legacy AssetCategory dialog tabs and panels.
// Dialog:
// - Asset type, code, caption.
// Tab 1 'Properties':
// Defaults - Income type.
// Purchase - Purcahse tax code, payment terms.
// Sale - Sell tax code, profit tax code.
// Notes.
// Tab 2 'Processes'.
//-------------------------------------------------------------------
public class ItemConfigData
{
// Update dialog title.
public String Title { get; set; }
// Pre-select AssetCategory type.
public class TypeData
{
public TypeData(string code, String desc)
{
Code = code;
Desc = desc;
}
public String Code { get; set; }
public String Desc { get; set; }
}
public TypeData Type { get; set; }
// Field name prefix.
public String Prefix { get; } = Model_AssetCategory.FieldNamePrefix;
// Control flags.
public bool? ManagedByAccounts { get; set; }
public bool? LocalPricing { get; set; }
// Allowed actions.
public class AllowData
{
public bool? UpdateCode { get; set; }
}
public AllowData Allow { get; } = new AllowData();
// Item fields.
public class FieldData
{
// Field name prefix.
public String Prefix { get; } = Model_AssetCategory.FieldNamePrefix;
// Hide field.
public HashSet<string> Hide { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Read-only field.
public HashSet<string> Readonly { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Field labels.
public Dictionary<String, String> Label { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
}
public FieldData Field { get; } = new FieldData();
}
/// <summary>
/// Populate item configuration for existing vehicle.
/// </summary>
public void PopulateItemConfig(ItemConfigData config, SbmAssetCategory assetCategory)
{
PopulateItemConfig(config, assetCategory.GetItemId(), assetCategory.AssetType);
}
/// <summary>
/// Populate item configuration for new or existing vehicle.
/// </summary>
public void PopulateItemConfig(ItemConfigData config, ItemId assetCategoryId, Sbm.AssetType assetType)
{
// Session configuration.
bool userCanCreateAssetCategories = SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(Sbm.ItemType.AssetCategory);
bool userCanUpdateAssetCategories = SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(Sbm.ItemType.AssetCategory);
// Update dialog title.
config.Title = Localiser["caption.vehicle.update"];
//---------------------------------------------------------------
// Identity.
// Asset type.
// ToDo - Asset type readonly if any associated assets.
if (!userCanUpdateAssetCategories || (ItemId.IsValid(assetCategoryId) && AssetMgr.AssetCategoryHasAssets(assetCategoryId.Id)))
config.Field.Readonly.Add($"{ItemField.Type}");
// Code.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.Code}");
// Caption.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.Caption}");
//---------------------------------------------------------------
// Defaults.
// Income type.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.IncomeType}");
//---------------------------------------------------------------
// Purchase.
// Tax code - purchase.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.TaxCodePurchase}");
// Payment terms.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.PaymentTerms}");
//---------------------------------------------------------------
// Sale.
// Tax code - sell.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.TaxCodeSale}");
// Tax code - profit.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.TaxCodeProfit}");
//---------------------------------------------------------------
// Common properties.
// Status.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.Status}");
// Notes.
if (!userCanUpdateAssetCategories)
config.Field.Readonly.Add($"{ItemField.Notes}");
//---------------------------------------------------------------
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -1,4 +1,5 @@
using DocumentFormat.OpenXml.Spreadsheet;
using Microsoft.AspNetCore.Http;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
@@ -15,8 +16,15 @@ using System;
namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
{
//=======================================================================
public class Model_AssetCategory : SbmModel_Portal
public partial class Model_AssetCategory : SbmModel_Portal
{
//-------------------------------------------------------------------
// Definitions.
public enum ViewMode
{
Search, Maintain
}
//-------------------------------------------------------------------
// Construction.
public Model_AssetCategory(SbmLocaliser localiser) :
@@ -28,14 +36,24 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
// Filter properties.
public class FilterData
{
public String Mode { get; set; }
public String AssetType { get; set; }
public String Search { get; set; }
public String StatusCat { get; set; }
public SbmAssetCategory.StatusCat GetStatusCat()
{
return EnumUtil.ParseEnum(StatusCat, SbmAssetCategory.StatusCat.NotDeleted);
}
}
public FilterData Filter { get; } = new FilterData();
public ViewMode GetFilterMode()
{
return EnumUtil.ParseEnum(Filter.Mode, ViewMode.Search);
}
public Sbm.AssetType GetFilterAssetType()
{
return EnumUtil.ParseEnum(Filter.AssetType, Sbm.AssetType.Unknown);
}
public SbmAssetCategory.StatusCat GetFilterStatusCat()
{
return EnumUtil.ParseEnum(Filter.StatusCat, SbmAssetCategory.StatusCat.NotDeleted);
}
//-------------------------------------------------------------------
// Item properties.
@@ -46,12 +64,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
public String TypeCode { get; set; }
public Sbm.AssetType AssetType { get; set; }
public String Code { get; set; }
public String DescBrief { get; set; }
public String Caption { get; set; }
public String Notes { get; set; }
public String StatusCode { get; set; }
public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); }
}
public AssetCategoryData AssetCategory { get; } = new AssetCategoryData();
public SaStatus GetAssetCategoryStatus() { return SacsSystem.GetStatusForCode(AssetCategory.StatusCode); }
//-------------------------------------------------------------------
// Validation.
@@ -66,7 +84,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
// AssetCategory type.
if (AssetCategory.TypeCode != null)
{
String controlName = "AssetCategoryType";
String controlName = @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Type);
AssetCategory.AssetType = (Sbm.AssetType)Internals.AssetTypeCodes.GetTypeForCode(AssetCategory.TypeCode);
responseData.SetControlValue(controlName, AssetCategory.TypeCode);
if (StringUtil.IsBlank(AssetCategory.TypeCode))
@@ -78,7 +96,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
// AssetCategory Code.
if (AssetCategory.Code != null)
{
String controlName = "AssetCategoryCode";
String controlName = @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Code);
AssetCategory.Code = AssetCategory.Code.ToUpper();
responseData.SetControlValue(controlName, AssetCategory.Code);
if (StringUtil.IsBlank(AssetCategory.Code))
@@ -87,21 +105,21 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Code)]);
}
// AssetCategory DescBrief.
if (AssetCategory.DescBrief != null)
// AssetCategory Caption.
if (AssetCategory.Caption != null)
{
String controlName = "AssetCategoryDescription";
responseData.SetControlValue(controlName, AssetCategory.DescBrief);
if (StringUtil.IsBlank(AssetCategory.DescBrief))
String controlName = @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Caption);
responseData.SetControlValue(controlName, AssetCategory.Caption);
if (StringUtil.IsBlank(AssetCategory.Caption))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(AssetCategory.DescBrief) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_DescBrief))
else if (StringUtil.GetLength(AssetCategory.Caption) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_DescBrief))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_DescBrief)]);
}
// Notes.
if (AssetCategory.Notes != null)
{
String controlName = "AssetCategoryNotes";
String controlName = @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Notes);
responseData.SetControlValue(controlName, AssetCategory.Notes);
if (StringUtil.GetLength(AssetCategory.Notes) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Notes))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Notes)]);
@@ -110,10 +128,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
// AssetCategory status.
if (AssetCategory.StatusCode != null)
{
String controlName = "AssetCategoryStatus";
String controlName = @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Status);
if (StringUtil.IsBlank(AssetCategory.StatusCode))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SbmAssetCategory.ValidStatuses.Contains(AssetCategory.GetStatus()))
else if (!SbmAssetCategory.ValidStatuses.Contains(GetAssetCategoryStatus()))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
@@ -1,130 +0,0 @@
using DocumentFormat.OpenXml.Spreadsheet;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using System;
namespace Sarand.BusinessMgr.Web.Portal.Models.Assets
{
//=======================================================================
public class Model_VehicleClass : SbmModel_Portal
{
//-------------------------------------------------------------------
// Construction.
public Model_VehicleClass(SbmLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Filter properties.
public class FilterData
{
public string Search { get; set; }
public string StatusCat { get; set; }
public SbmVehicleClass.StatusCat GetStatusCat()
{
return EnumUtil.ParseEnum(StatusCat, SbmVehicleClass.StatusCat.NotDeleted);
}
}
public FilterData Filter { get; } = new FilterData();
//-------------------------------------------------------------------
// Item properties.
public class VehicleClassData
{
public string Exists { get; set; }
public string Id { get; set; }
public string MakeCode { get; set; }
public string Model { get; set; }
public string Derivative { get; set; }
public string DescBrief { get; set; }
public string VehicleTypeCode { get; set; }
public Sbm.VehicleType VehicleType { get; set; } = Sbm.VehicleType.Unknown;
public string VehicleCategoryCode { get; set; }
public string FuelTypeCode { get; set; }
public Sbm.VehicleFuelType FuelType { get; set; } = Sbm.VehicleFuelType.Unknown;
public string OdometerUnitsCode { get; set; }
public Sbm.VehicleOdometerUnits OdometerUnits { get; set; } = Sbm.VehicleOdometerUnits.Unknown;
public string Notes { get; set; }
public string StatusCode { get; set; }
public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); }
}
public VehicleClassData VehicleClass { get; } = new VehicleClassData();
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// VehicleClass.
public bool ValidateVehicleClassData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposables = new DisposableCollection<SacsHierarchyItem>())
{
// Make.
if (VehicleClass.MakeCode != null)
{
string controlName = "VehicleClassMake";
responseData.SetControlValue(controlName, VehicleClass.MakeCode);
if (VehicleClass.MakeCode.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
}
// Model.
if (VehicleClass.Model != null)
{
string controlName = "VehicleClassModel";
VehicleClass.Model = VehicleClass.Model.ToUpper();
responseData.SetControlValue(controlName, VehicleClass.Model);
if (VehicleClass.Model.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(VehicleClass.Model) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Model))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Model)]);
}
// VehicleClass DescBrief.
if (VehicleClass.DescBrief != null)
{
string controlName = "VehicleClassDescription";
responseData.SetControlValue(controlName, VehicleClass.DescBrief);
if (VehicleClass.DescBrief.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(VehicleClass.DescBrief) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_DescBrief))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_DescBrief)]);
}
// Notes.
if (VehicleClass.Notes != null)
{
string controlName = "VehicleClassNotes";
responseData.SetControlValue(controlName, VehicleClass.Notes);
if (StringUtil.GetLength(VehicleClass.Notes) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Notes))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Notes)]);
}
// VehicleClass status.
if (VehicleClass.StatusCode != null)
{
string controlName = "VehicleClassStatus";
if (VehicleClass.StatusCode.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SbmVehicleClass.ValidStatuses.Contains(VehicleClass.GetStatus()))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -219,11 +219,11 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
public void PopulateListConfig(ListConfigData config)
{
// View properties.
CommodityViewMode viewMode = GetFilterMode();
bool modeIsMaintain = viewMode == CommodityViewMode.Maintain;
bool modeIsSearch = viewMode == CommodityViewMode.Search;
bool modeIsStockControl = viewMode == CommodityViewMode.StockControl;
bool modeIsStockTake = viewMode == CommodityViewMode.StockTake;
ViewMode viewMode = GetFilterMode();
bool modeIsMaintain = viewMode == ViewMode.Maintain;
bool modeIsSearch = viewMode == ViewMode.Search;
bool modeIsStockControl = viewMode == ViewMode.StockControl;
bool modeIsStockTake = viewMode == ViewMode.StockTake;
Sbm.CommodityType commodityType = GetFilterCommodityType();
@@ -260,7 +260,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
config.Column.Hide.Add($"{ItemField.SalesPrice}");
// Pack qty.
if (modeIsStockControl || SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_PackQtySale))
if (modeIsStockControl || SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_PackQtySale))
config.Column.Label.Add($"{ItemField.PackQtySale}", Localiser["label.pack.quantity"]);
else
config.Column.Hide.Add($"{ItemField.PackQtySale}");
@@ -288,7 +288,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
// Specification.
// Weight.
if (modeIsStockControl || SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_Weight))
if (modeIsStockControl || SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_Weight))
config.Column.Label.Add($"{ItemField.Weight}", Localiser["label.weight"]);
else
config.Column.Hide.Add($"{ItemField.Weight}");
@@ -297,7 +297,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
// Defaults.
// Catalog Reference.
if (modeIsStockControl || SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_CatalogRef))
if (modeIsStockControl || SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_CatalogRef))
config.Column.Label.Add($"{ItemField.CatalogRef}", SessionConsole.GetAttributeCaption(SbmDbDfn.ColumnIdx.Commodity_CatalogRef, Localiser["label.catalog.ref"]));
else
config.Column.Hide.Add($"{ItemField.CatalogRef}");
@@ -306,19 +306,19 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
// Stock.
// Stock - allocated.
if ((modeIsStockControl || SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockAllocated)) && SessionConsole.DisplayAttribute(SbmDbDfn.ColumnIdx.Commodity_QtyAllocated))
if ((modeIsStockControl || SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockAllocated)) && SessionConsole.DisplayAttribute(SbmDbDfn.ColumnIdx.Commodity_QtyAllocated))
config.Column.Label.Add($"{ItemField.QtyAllocated}", SessionConsole.GetAttributeCaption(SbmDbDfn.ColumnIdx.Commodity_QtyAllocated, Localiser["label.allocated"]));
else
config.Column.Hide.Add($"{ItemField.QtyAllocated}");
// Stock - available.
if (!modeIsStockControl && SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockAvailable))
if (!modeIsStockControl && SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockAvailable))
config.Column.Label.Add($"{ItemField.StockAvailable}", Localiser["label.available"]);
else
config.Column.Hide.Add($"{ItemField.StockAvailable}");
// Current Level.
if (modeIsStockControl || SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockLevelSales))
if (modeIsStockControl || SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Commodity_StockLevelSales))
config.Column.Label.Add($"{ItemField.CurrentLevel}", Localiser["label.current.level"]);
else
config.Column.Hide.Add($"{ItemField.CurrentLevel}");
@@ -28,7 +28,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
{
//-------------------------------------------------------------------
// Definitions.
public enum CommodityViewMode
public enum ViewMode
{
Search, Maintain, StockControl, StockTake
}
@@ -49,9 +49,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
public String Search { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public CommodityViewMode GetFilterMode()
public ViewMode GetFilterMode()
{
return EnumUtil.ParseEnum(Filter.Mode, CommodityViewMode.Search);
return EnumUtil.ParseEnum(Filter.Mode, ViewMode.Search);
}
public Sbm.CommodityType GetFilterCommodityType()
{
@@ -134,9 +134,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
}
public void PopulateListConfig(ListConfigData config)
{
AssociationViewMode pageMode = GetFilterMode();
bool modeIsRelationships = pageMode == AssociationViewMode.Relationships;
bool modeIsMaintain = pageMode == AssociationViewMode.Maintain;
ViewMode pageMode = GetFilterMode();
bool modeIsRelationships = pageMode == ViewMode.Relationships;
bool modeIsMaintain = pageMode == ViewMode.Maintain;
Sbm.AssociationType associationType = GetFilterAssociationType();
bool typeIsCustomer = associationType == Sbm.AssociationType.Customer;
bool typeIsSupplier = associationType == Sbm.AssociationType.Supplier;
@@ -177,15 +177,15 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
config.Column.Hide.Add($"{ItemField.Address}");
// Customer financials.
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Open))
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Open))
config.Column.Hide.Add($"{ItemField.TransSalesValueOpen}");
if (!modeIsMaintain || !typeIsCustomer || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_LastSaleRaised))
if (!modeIsMaintain || !typeIsCustomer || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_LastSaleRaised))
config.Column.Hide.Add($"{ItemField.TransLastSaleRaised}");
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_AnnualSalesTarget))
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_AnnualSalesTarget))
config.Column.Hide.Add($"{ItemField.AnnualSalesTarget}");
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Cytd))
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Cytd))
config.Column.Hide.Add($"{ItemField.TransSalesValueCytd}");
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Lcy))
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Trans_SalesValue_Lcy))
config.Column.Hide.Add($"{ItemField.TransSalesValueLcy}");
// Customer commodities.
if (!modeIsMaintain || !typeIsCustomer || !CommodityMgr.CanManageCommodityCustomers())
@@ -196,7 +196,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
if (!modeIsMaintain || !typeIsCustomer || !UserCanViewFinancials() || !SessionConsole.AllowOption(Sbm.ConfigOption.CustomerPriceSet) && PriceMgr.PriceDatabaseIsValid)
config.Column.Hide.Add($"{ItemField.PriceSet}");
// Association group.
if (!modeIsMaintain || !typeIsCustomer || !SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Group))
if (!modeIsMaintain || !typeIsCustomer || !SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Association_Group))
config.Column.Hide.Add($"{ItemField.Group}");
// Customer codes.
if (!modeIsMaintain || !typeIsCustomer || !CodeTypeConsole.CodeTypeHasCodes(Internals.GetCodeTypeCode(Sbm.ApplCodeType.AccountManager)))
@@ -331,7 +331,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
config.Type = new ItemConfigData.TypeData(associationTypes.GetCodeForType(Sbm.AssociationType.Member), Localiser.GetAssociationTypeCaption(Sbm.AssociationType.Member));
// Allow actions.
if (SessionData_Portal.GetOwnerOption_AllowOption(Sbm.OrgOption_AllowOption.UpdateAssociationCode))
if (SessionConsole.GetOwnerOption_AllowOption(Sbm.OrgOption_AllowOption.UpdateAssociationCode))
config.Allow.UpdateCode = true;
// Item Fields.
@@ -27,7 +27,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
{
//-------------------------------------------------------------------
// Definitions.
public enum AssociationViewMode
public enum ViewMode
{
Search, Maintain, Relationships, PriceSet,
}
@@ -39,9 +39,6 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
{
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// Filter.
public class FilterData
@@ -53,9 +50,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
public string Search { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public AssociationViewMode GetFilterMode()
public ViewMode GetFilterMode()
{
return EnumUtil.ParseEnum(Filter.Mode, AssociationViewMode.Search);
return EnumUtil.ParseEnum(Filter.Mode, ViewMode.Search);
}
public Sbm.AssociationType GetFilterAssociationType()
{
@@ -114,9 +114,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
public void PopulateListConfig(ListConfigData config)
{
ContactViewMode viewMode = GetFilterMode();
bool modeIsMaintain= viewMode == ContactViewMode.Maintain;
bool modeIsSearch = viewMode == ContactViewMode.Search;
ViewMode viewMode = GetFilterMode();
bool modeIsMaintain= viewMode == ViewMode.Maintain;
bool modeIsSearch = viewMode == ViewMode.Search;
Sbm.AffiliateType affiliateType = GetFilterContactType();
bool contactGroupsOnly = affiliateType == Sbm.AffiliateType.ContactGroup;
@@ -27,7 +27,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
{
//-------------------------------------------------------------------
// Definitions.
public enum ContactViewMode
public enum ViewMode
{
Search, Maintain,
}
@@ -49,9 +49,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
public String Email { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public ContactViewMode GetFilterMode()
public ViewMode GetFilterMode()
{
return EnumUtil.ParseEnum(Filter.Mode, ContactViewMode.Search);
return EnumUtil.ParseEnum(Filter.Mode, ViewMode.Search);
}
public Sbm.AffiliateType GetFilterContactType()
{
@@ -106,6 +106,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
Menu.Items.Add(referenceItem);
}
//-------------------------------------------------------------------
// View reference data.
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// View reference data - Contacts.
@@ -113,7 +117,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
/// List of Affiliate Types for filter dropdown.
/// <para>- Contact model cannot define this as contact list/dialog may be included in other views with their own model, eg. Association page.</para>
/// </summary>
public IEnumerable<SelectListItem> GetAffiliateTypeCodesForFilterSelect()
public IEnumerable<SelectListItem> GetAffiliateTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> affiliateTypes = GetCodesOfType(Sbm.SystemCode.AffiliateType);
if (!affiliateTypes.Any(item => item.Type == (int)Sbm.AffiliateType.AnyOrganisation))
@@ -125,7 +129,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
/// List of Association Types for filter dropdown.
/// <para>- Association model cannot define this as association list/dialog may be included in other views with their own model, eg. Commodity page.</para>
/// </summary>
public IEnumerable<SelectListItem> GetAssociationTypeCodesForFilterSelect()
public IEnumerable<SelectListItem> GetAssociationTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> associationTypes = GetCodesOfType(Sbm.SystemCode.AssociationType);
associationTypes.RemoveAll(item => item.Type == (short)Sbm.AssociationType.Internal);
@@ -137,13 +141,72 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
return new SelectList(associationTypes, "Code", "Desc");
}
//-------------------------------------------------------------------
// View reference data - Commodities.
/// <summary>
/// List of Commodity Types for filter dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetCommodityTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
commodityTypes.Add(Sbm.CommodityType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
}
/// <summary>
/// List of Commodity Types for form dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetCommodityTypeCodesForDropdown()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
}
/// <summary>
/// List of Asset Types for filter dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetAssetTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> assetTypes = new List<TypeCodeDesc>();
assetTypes.Add(Sbm.AssetType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc assetType in GetCodesOfType(Sbm.SystemCode.AssetType))
{
assetTypes.Add(assetType);
}
return new SelectList(assetTypes, "Code", "Desc");
}
/// <summary>
/// List of Asset Types for form dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetAssetTypeCodesForDropdown()
{
List<TypeCodeDesc> assetTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc assetType in GetCodesOfType(Sbm.SystemCode.AssetType))
{
assetTypes.Add(assetType);
}
return new SelectList(assetTypes, "Code", "Desc");
}
//-------------------------------------------------------------------
// View reference data - Transactions.
/// <summary>
/// List of Transaction Types for filter dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetTransactionTypeCodesForFilterSelect()
public IEnumerable<SelectListItem> GetTransactionTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> transactionTypes = new List<TypeCodeDesc>();
transactionTypes.Add(Sbm.TransactionType.Any, "", Localiser["label.any"]);
@@ -171,44 +234,11 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
return new SelectList(transactionTypes, "Code", "Desc");
}
//-------------------------------------------------------------------
// View reference data - Commodities.
/// <summary>
/// List of Commodity Types for filter dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetCommodityTypeCodesForFilterSelect()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
commodityTypes.Add(Sbm.CommodityType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
}
/// <summary>
/// List of Commodity Types for form dropdown.
/// </summary>
public IEnumerable<SelectListItem> GetCommodityTypeCodesForDropdown()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
}
// ToDo - Organisation Option - Show Column:
// case Sbm.SystemCode.OrgOption_ShowColumn:
// if (code.Type == (int) Sbm.OrgOption_ShowColumn.Transaction_ContactArea)
// Desc = "Transaction: " + sessionConsole.GetAttributeCaption(SbmDbDfn.ColumnIdx.Association_ContactAreaCode, "Contact area");
//-------------------------------------------------------------------
}
//=======================================================================
@@ -394,7 +394,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Transactions
// Contact Area.
if (CodeTypeConsole.CodeTypeHasCodes(Internals.GetCodeTypeCode(Sbm.ApplCodeType.ContactArea)) &&
SessionData_Portal.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Transaction_ContactArea) &&
SessionConsole.GetOwnerOption_ShowColumn(Sbm.OrgOption_ShowColumn.Transaction_ContactArea) &&
(modeIsDeliveryPlanning || isSalesOrder))
{
config.Column.Label.Add($"{ItemField.ContactArea}", SessionConsole.GetAttributeCaption(SbmDbDfn.ColumnIdx.Transaction_ContactAreaCode, Localiser["label.contact.area"]));
@@ -0,0 +1,305 @@
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
namespace Sarand.BusinessMgr.Web.Portal.Models.Vehicles
{
//=======================================================================
// Vehicle model - Configuration.
//=======================================================================
partial class Model_Vehicle
{
//-------------------------------------------------------------------
/// <summary>Prefix for field names.</summary>
public const String FieldNamePrefix = "Vehicle";
/// <summary>Item fields.</summary>
public enum ItemField
{
// Vehicle properties.
Id,
// Identity.
Registration,
Vin,
// Model.
Make,
Model,
Class,
// Defaults.
CapCode,
KeyNumber,
KeyLocation,
Weight,
// Spec.
BuildOn,
PurchaseOdo,
RegisterOn,
FirstRegisterOn,
EngineNumber,
RegistrationPrevious,
LatestOdo,
LatestOdoOn,
// Associated properties.
AssetCount,
// Common.
Notes,
Status,
CreatedOn,
UpdatedOn,
Actions,
}
/// <summary>
/// Identifier used by form fields to show control specific messages generated by model validation etc.
/// <para>- Both page and model should use this method to consistently generate the field name.</para>
/// </summary>
public static String GetFieldName(ItemField field)
{
return $"{FieldNamePrefix}{field}";
}
// List configuration.
public class ListConfigData
{
// Actions.
public class ActionData
{
public class AllowData
{
public bool? Create { get; set; }
public bool? Update { get; set; }
}
public AllowData Allow { get; } = new AllowData();
}
public ActionData Action { get; } = new ActionData();
// List columns.
public class ColumnData
{
// Column name prefix.
public String Prefix { get; } = Model_Vehicle.FieldNamePrefix;
// Hide column.
public HashSet<string> Hide { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Column labels.
public Dictionary<String, String> Label { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
}
public ColumnData Column { get; } = new ColumnData();
}
public ListConfigData ListConfig { get; private set; }
//-------------------------------------------------------------------
/// <summary>
/// Populate Vehicle list configuration data - only required on initial page construction.
/// </summary>
public void PopulateListConfig()
{
ListConfig = new ListConfigData();
PopulateListConfig(ListConfig);
}
public void PopulateListConfig(ListConfigData config)
{
ViewMode pageMode = GetFilterMode();
bool modeIsSearch = pageMode == ViewMode.Search;
bool modeIsMaintain = pageMode == ViewMode.Maintain;
bool userCanCreateVehicles = SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(Sbm.ItemType.Vehicle);
bool userCanUpdateVehicles = SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(Sbm.ItemType.Vehicle);
// Actions.
if (userCanCreateVehicles)
config.Action.Allow.Create = true;
if (userCanUpdateVehicles)
config.Action.Allow.Update = true;
// List columns.
if (SysId.IsValid(SysId.ToSysId(Filter.VehicleClassId)))
config.Column.Hide.Add($"{ItemField.Class}");
// Vehicle Assets.
if (!modeIsMaintain || !SessionConsole.AllowOption(Sbm.ConfigOption.Assets))
config.Column.Hide.Add($"{ItemField.AssetCount}");
// Actions.
if (!modeIsMaintain)
config.Column.Hide.Add($"{ItemField.Actions}");
}
//-------------------------------------------------------------------
// Item configuration.
//-------------------------------------------------------------------
// Legacy Vehicle dialog tabs and panels.
// Tab 1 'Properties':
// Model
// Defaults
// Spec
// HPI
// Service
// Notes
// Tab 2 'Features':
// Features
//-------------------------------------------------------------------
public class ItemConfigData
{
// Update dialog title.
public String Title { get; set; }
// Pre-select Vehicle type.
public class TypeData
{
public TypeData(string code, String desc)
{
Code = code;
Desc = desc;
}
public String Code { get; set; }
public String Desc { get; set; }
}
public TypeData Type { get; set; }
// Field name prefix.
public String Prefix { get; } = Model_Vehicle.FieldNamePrefix;
// Control flags.
public bool? ManagedByAccounts { get; set; }
public bool? LocalPricing { get; set; }
// Allowed actions.
public class AllowData
{
public bool? UpdateCode { get; set; }
}
public AllowData Allow { get; } = new AllowData();
// Item fields.
public class FieldData
{
// Field name prefix.
public String Prefix { get; } = Model_Vehicle.FieldNamePrefix;
// Hide field.
public HashSet<string> Hide { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Read-only field.
public HashSet<string> Readonly { get; } = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
// Field labels.
public Dictionary<String, String> Label { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
}
public FieldData Field { get; } = new FieldData();
}
/// <summary>
/// Populate item configuration for existing vehicle.
/// </summary>
public void PopulateItemConfig(ItemConfigData config, SbmVehicle vehicle)
{
PopulateItemConfig(config, vehicle.GetItemId());
}
/// <summary>
/// Populate item configuration for new or existing vehicle.
/// </summary>
public void PopulateItemConfig(ItemConfigData config, ItemId vehicleItemId)
{
// Session configuration.
bool userCanCreateVehicles = SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(Sbm.ItemType.Vehicle);
bool userCanUpdateVehicles = SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(Sbm.ItemType.Vehicle);
// Update dialog title.
config.Title = Localiser["caption.vehicle.update"];
//---------------------------------------------------------------
// Identity.
// Registration.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Registration}");
// VIN.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Vin}");
//---------------------------------------------------------------
// Model.
// Make.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Make}");
// Model.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Model}");
// Class.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Class}");
//---------------------------------------------------------------
// Defaults.
// CAP code.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.CapCode}");
// Key Number.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.KeyNumber}");
// Key Location.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.KeyLocation}");
// Weight.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Weight}");
//---------------------------------------------------------------
// Spec.
// Build On.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.BuildOn}");
// Purchase Odomoeter.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.PurchaseOdo}");
// Register On.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.RegisterOn}");
// First Register On.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.FirstRegisterOn}");
// Engine Number.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.EngineNumber}");
// Previous Registration.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.RegistrationPrevious}");
// Latest Odomoeter.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.LatestOdo}");
// Latest Odomoeter.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.LatestOdoOn}");
//---------------------------------------------------------------
// Service.
//---------------------------------------------------------------
// Common properties.
// Status.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Status}");
// Notes.
if (!userCanUpdateVehicles)
config.Field.Readonly.Add($"{ItemField.Notes}");
//---------------------------------------------------------------
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,144 @@
using DocumentFormat.OpenXml.Spreadsheet;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using System;
namespace Sarand.BusinessMgr.Web.Portal.Models.Vehicles
{
//=======================================================================
public partial class Model_Vehicle : SbmModel_Portal
{
//-------------------------------------------------------------------
// Definitions.
public enum ViewMode
{
Search, Maintain
}
//-------------------------------------------------------------------
// Construction.
public Model_Vehicle(SbmLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Filter properties.
public class FilterData
{
public String Mode { get; set; }
public String VehicleClassId { get; set; }
public String Search { get; set; }
public String StatusCat { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public ViewMode GetFilterMode()
{
return EnumUtil.ParseEnum(Filter.Mode, ViewMode.Search);
}
public SbmVehicle.StatusCat GetFilterStatusCat()
{
return EnumUtil.ParseEnum(Filter.StatusCat, SbmVehicle.StatusCat.NotDeleted);
}
//-------------------------------------------------------------------
// Item properties.
public class VehicleData
{
public String Exists { get; set; }
public String Id { get; set; }
public String ClassId { get; set; }
public String Registration { get; set; }
public String Vin { get; set; }
public String CapCode { get; set; }
public String KeyNumber { get; set; }
public String KeyLocation { get; set; }
public String EngineNumber { get; set; }
public String EngineCapacity { get; set; }
public String Seats { get; set; }
public String Weight { get; set; }
public String ManufactureYear { get; set; }
public String Notes { get; set; }
public String StatusCode { get; set; }
public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); }
}
public VehicleData Vehicle { get; } = new VehicleData();
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// Vehicle.
public bool ValidateVehicleData(SbmController_Base.AjaxResponse_Data responseData)
{
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposables = new DisposableCollection<SacsHierarchyItem>())
{
// Vehicle Class.
if (Vehicle.ClassId != null)
{
String controlName = "VehicleClass";
if (StringUtil.IsBlank(Vehicle.ClassId))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!AssetMgr.VehicleClassExistsById(SysId.ToSysId(Vehicle.ClassId)))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
// Registration.
if (Vehicle.Registration != null)
{
String controlName = "VehicleRegistration";
Vehicle.Registration = Vehicle.Registration.ToUpper();
responseData.SetControlValue(controlName, Vehicle.Registration);
if (StringUtil.IsBlank(Vehicle.Registration))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(Vehicle.Registration) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_RegNumber))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_RegNumber)]);
}
// Vin.
if (Vehicle.Vin != null)
{
String controlName = "VehicleVin";
Vehicle.Vin = Vehicle.Vin.ToUpper();
responseData.SetControlValue(controlName, Vehicle.Vin);
if (StringUtil.GetLength(Vehicle.Vin) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_VIN))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_VIN)]);
}
// Notes.
if (Vehicle.Notes != null)
{
String controlName = "VehicleNotes";
responseData.SetControlValue(controlName, Vehicle.Notes);
if (StringUtil.GetLength(Vehicle.Notes) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_Notes))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicle_Notes)]);
}
// Vehicle status.
if (Vehicle.StatusCode != null)
{
String controlName = "VehicleStatus";
if (StringUtil.IsBlank(Vehicle.StatusCode))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SbmVehicle.ValidStatuses.Contains(Vehicle.GetStatus()))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,135 @@
using DocumentFormat.OpenXml.Spreadsheet;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using System;
namespace Sarand.BusinessMgr.Web.Portal.Models.Vehicles
{
//=======================================================================
public partial class Model_VehicleClass : SbmModel_Portal
{
//-------------------------------------------------------------------
// Construction.
public Model_VehicleClass(SbmLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Filter properties.
public class FilterData
{
public string VehicleType { get; set; }
public string Search { get; set; }
public string StatusCat { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public Sbm.VehicleType GetFilterVehicleType()
{
return (Sbm.VehicleType)Internals.VehicleTypeCodes.GetTypeForCode(Filter.VehicleType);
}
public SbmVehicleClass.StatusCat GetFilterStatusCat()
{
return EnumUtil.ParseEnum(Filter.StatusCat, SbmVehicleClass.StatusCat.NotDeleted);
}
//-------------------------------------------------------------------
// Item properties.
public class VehicleClassData
{
public string Exists { get; set; }
public string Id { get; set; }
public string MakeCode { get; set; }
public string Model { get; set; }
public string Derivative { get; set; }
public string DescBrief { get; set; }
public string VehicleTypeCode { get; set; }
public Sbm.VehicleType VehicleType { get; set; } = Sbm.VehicleType.Unknown;
public string VehicleCategoryCode { get; set; }
public string FuelTypeCode { get; set; }
public Sbm.VehicleFuelType FuelType { get; set; } = Sbm.VehicleFuelType.Unknown;
public string OdometerUnitsCode { get; set; }
public Sbm.VehicleOdometerUnits OdometerUnits { get; set; } = Sbm.VehicleOdometerUnits.Unknown;
public string Notes { get; set; }
public string StatusCode { get; set; }
public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); }
}
public VehicleClassData VehicleClass { get; } = new VehicleClassData();
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// VehicleClass.
public bool ValidateVehicleClassData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposables = new DisposableCollection<SacsHierarchyItem>())
{
// Make.
if (VehicleClass.MakeCode != null)
{
string controlName = "VehicleClassMake";
responseData.SetControlValue(controlName, VehicleClass.MakeCode);
if (VehicleClass.MakeCode.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
}
// Model.
if (VehicleClass.Model != null)
{
string controlName = "VehicleClassModel";
VehicleClass.Model = VehicleClass.Model.ToUpper();
responseData.SetControlValue(controlName, VehicleClass.Model);
if (VehicleClass.Model.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(VehicleClass.Model) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Model))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Model)]);
}
// VehicleClass DescBrief.
if (VehicleClass.DescBrief != null)
{
string controlName = "VehicleClassDescription";
responseData.SetControlValue(controlName, VehicleClass.DescBrief);
if (VehicleClass.DescBrief.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(VehicleClass.DescBrief) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_DescBrief))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_DescBrief)]);
}
// Notes.
if (VehicleClass.Notes != null)
{
string controlName = "VehicleClassNotes";
responseData.SetControlValue(controlName, VehicleClass.Notes);
if (StringUtil.GetLength(VehicleClass.Notes) > GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Notes))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.SaVehicleClass_Notes)]);
}
// VehicleClass status.
if (VehicleClass.StatusCode != null)
{
string controlName = "VehicleClassStatus";
if (VehicleClass.StatusCode.IsBlank())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SbmVehicleClass.ValidStatuses.Contains(VehicleClass.GetStatus()))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -52,7 +52,6 @@
<ItemGroup>
<Folder Include="Views\Assets\Asset\" />
<Folder Include="Views\Assets\Vehicle\" />
<Folder Include="Views\Transaction\" />
</ItemGroup>
@@ -2,207 +2,8 @@
@model Model_AssetCategory
@inject SbmLocaliser Localiser
@{
/* Asset Category view. */
ViewData["Title"] = "Asset Categories";
Model.AdditionalFiles_JS.Add("js/sbm-asset-cat.js");
}
<div class="sbm-panel AssetCategories fullheight">
<script type="text/javascript">
sbm.dlg.title.createItem = '@(Localiser.GetJavascriptText("caption.asset.category.create"))';
sbm.dlg.title.updateItem = '@(Localiser.GetJavascriptText("caption.asset.category.update"))';
</script>
<div class="sbm-panel-data sbm-flex">
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategoryFilter", @class = "sbm-form", @onSubmit = "return false;" }))
{
@* Header - Page caption, paging controls, actions. *@
<div class="sbm-panel-header">
<div class="row">
<div class="fixed">
<partial name="~/Views/Common/ResultsPaging.cshtml" />
</div>
<div class="col center"><div class="sbm-panel-caption">@Localiser["caption.asset.categories"]</div></div>
<div class="fixed">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
</div>
@* Filter Panel *@
<div class="sbm-panel-filter">
<div class="row pb4">
<div class="col-sm-5 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-sm-7">
@Html.TextBoxFor(model => model.Filter.Search, new { @id = "", @class = "FilterSearch", @maxlength = "32" })
</div>
</div>
</div>
}
@* Item list *@
<div class="sbm-panel-item-table sbm-flex">
<table class="sbm-item-list">
<thead>
<tr>
<th class="pl-2">@Localiser["label.type"]</th>
<th class="">@Localiser["label.code"]</th>
<th class="">@Localiser["label.description"]</th>
<th class="center">@Localiser["label.status"]</th>
<th class="right" style="width:2%;"></th>
</tr>
<tr><td colspan="6"><div class="sbm-panel-messages"></div></td></tr>
</thead>
<tbody></tbody>
</table>
</div>
@* Element templates *@
<div class="sbm-panel-item-template">
@* Filter Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu AssetCategoryFilter">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
@* AssetCategory row template - table is ignored. *@
<table class="">
<tr class="sbm-row-item AssetCategory">
<td><div class="AssetCategoryType pl-1"></div></td>
<td><div class="AssetCategoryCode"></div></td>
<td><div class="AssetCategoryDescription"></div></td>
<td><div class="AssetCategoryStatusDesc center"></div></td>
<td>
<div class="right">
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</td>
</tr>
</table>
@* Item Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu AssetCategory">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
</div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategoryId", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.AssetCategory.Id, new { @id = "", @class = "AssetCategoryId" })
}
<div id="dlgAssetCategory" class="sbm-dialog">
<div class="spacer2"></div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategory", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.AssetCategory.Exists, new { @id = "", @class = "AssetCategoryExists" })
@Html.HiddenFor(model => model.AssetCategory.Id, new { @id = "", @class = "AssetCategoryId" })
@* Type *@
<div class="sbm-form-control AssetCategoryType">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryType"><span>@Localiser["label.type"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.DropDownListFor(model => model.AssetCategory.TypeCode, Model.GetAssetTypeCodesForSelect(), Localiser["label.select"], new { @id = "ifAssetCategoryType", @class = "AssetCategoryType sbm-select" })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Contact Code *@
<div class="sbm-form-control AssetCategoryCode">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryCode"><span>@Localiser["label.code"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBoxFor(model => model.AssetCategory.Code, new { @id = "ifAssetCategoryCode", @class = "AssetCategoryCode sbm-input upper", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Code) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Description *@
<div class="sbm-form-control AssetCategoryDescription">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryDescription"><span>@Localiser["label.description"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBoxFor(model => model.AssetCategory.DescBrief, new { @id = "ifAssetCategoryDescription", @class = "AssetCategoryDescription sbm-input", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_DescBrief) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Status *@
<div class="sbm-form-control AssetCategoryStatus">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="cbAssetCategoryStatus"><span>@Localiser["label.status"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
<select id="cbAssetCategoryStatus" class="sbm-select AssetCategoryStatus" name="AssetCategory.StatusCode"></select>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Notes *@
<div class="sbm-form-control AssetCategoryNotes">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryNotes"><span>@Localiser["label.notes"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
@Html.TextAreaFor(model => model.AssetCategory.Notes, new { @id = "ifAssetCategoryNotes", @class = "AssetCategoryNotes sbm-textarea", @rows = 3, @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Notes) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
}
<div class="spacer2"></div>
</div>
</div>
</div>
<partial name="Panel-AssetCategoryMaintain.cshtml" />
@@ -0,0 +1,108 @@
@* View is decoupled from Asset Category model as it may be included in other views, eg. Assets. *@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Asset Category - Dialog panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Assets/AssetCategory/Panel-AssetCategoryDialog")) return;
}
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategoryId", @onSubmit = "return false;" }))
{
@Html.Hidden("AssetCategory.Id", "", new { @id = "", @class = "AssetCategoryId" })
}
<div id="dlgAssetCategory" class="sbm-dialog">
<div class="spacer2"></div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategory", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("AssetCategory.Exists", "", new { @id = "", @class = "AssetCategoryExists sbm-input" })
@Html.Hidden("AssetCategory.Id", "", new { @id = "", @class = "AssetCategoryId sbm-input" })
@* Type *@
<div class="sbm-form-control @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Type)">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryType"><span>@Localiser["label.type"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.DropDownList("AssetCategory.TypeCode", Model.GetAssetTypeCodesForDropdown(), Localiser["label.select"], new { @id = "ifAssetCategoryType", @class = "AssetCategoryType sbm-select sbm-auto-val" })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Contact Code *@
<div class="sbm-form-control @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Code)">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryCode"><span>@Localiser["label.code"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBox("AssetCategory.Code", "", new { @id = "ifAssetCategoryCode", @class = "AssetCategoryCode sbm-input sbm-auto-val upper", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Code) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Caption *@
<div class="sbm-form-control @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Caption)">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryCaption"><span>@Localiser["label.description"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBox("AssetCategory.Caption", "", new { @id = "ifAssetCategoryCaption", @class = "AssetCategoryDescription sbm-input sbm-auto-val", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_DescBrief) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Status *@
<div class="sbm-form-control @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Status)">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="cbAssetCategoryStatus"><span>@Localiser["label.status"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
<select id="cbAssetCategoryStatus" class="sbm-select AssetCategoryStatus sbm-auto-val" name="AssetCategory.StatusCode"></select>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Notes *@
<div class="sbm-form-control @Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Notes)">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetCategoryNotes"><span>@Localiser["label.notes"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
@Html.TextArea("AssetCategory.Notes", "", new { @id = "ifAssetCategoryNotes", @class = "AssetCategoryNotes sbm-textarea sbm-auto-val", @rows = 3, @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAssetCategory_Notes) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
}
<div class="spacer2"></div>
</div>
@@ -0,0 +1,62 @@
@* View is decoupled from Asset Category model as it may be included in other views, eg. Assets. *@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Asset Category - List panel */
/* NB Can potentially appear more than once on a page. */
}
@* Item list *@
<div class="sbm-panel-item-table sbm-flex">
<table class="sbm-item-list">
<thead>
<tr>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Type) width25pc pl-1">@Localiser["label.type"]</th>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Code) width10pc">@Localiser["label.code"]</th>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Caption) width25pc">@Localiser["label.description"]</th>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Notes) width25pc d-none d-md-table-cell">@Localiser["label.notes"]</th>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Status) width10pc center">@Localiser["label.status"]</th>
<th class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Actions) width5pc"></th>
</tr>
<tr><td colspan="6"><div class="sbm-panel-messages"></div></td></tr>
</thead>
<tbody></tbody>
</table>
</div>
@* Element templates *@
<div class="sbm-panel-item-template">
@* Filter Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu AssetCategoryFilter">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
@* AssetCategory row template - table is ignored. *@
<table class="">
<tr class="sbm-row-item AssetCategory">
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Type) pl-1"></td>
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Code)"></td>
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Caption)"></td>
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Notes) d-none d-md-table-cell"></td>
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Status) center"></td>
<td class="@Model_AssetCategory.GetFieldName(Model_AssetCategory.ItemField.Actions)">
<div class="right">
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</td>
</tr>
</table>
@* Item Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu AssetCategory">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
</div>
@@ -0,0 +1,61 @@
@* View is decoupled from Asset Category model as it may be included in other views, eg. Assets. *@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Asset Category - Maintain panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Assets/AssetCategory/Panel-AssetCategoryMaintain")) return;
Model.AdditionalFiles_JS.Add("js/sbm-asset-cat.js");
}
<div class="sbm-panel AssetCategories fullheight">
<script type="text/javascript">
sbm.dlg.title.createItem = '@(Localiser.GetJavascriptText("caption.asset.category.create"))';
sbm.dlg.title.updateItem = '@(Localiser.GetJavascriptText("caption.asset.category.update"))';
</script>
<div class="sbm-panel-data sbm-flex">
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetCategoryFilter", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_AssetCategory.ViewMode.Maintain, new { @id = "" })
@* Header - Page caption, paging controls, actions. *@
<div class="sbm-panel-header">
<div class="row">
<div class="fixed">
<partial name="~/Views/Common/ResultsPaging.cshtml" />
</div>
<div class="col center"><div class="sbm-panel-caption">@Localiser["caption.asset.categories"]</div></div>
<div class="fixed">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
</div>
@* Filter Panel *@
<div class="sbm-panel-filter">
<div class="row pb4">
<div class="col-sm-5 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-sm-7">
@Html.TextBox("Filter.Search", "", new { @id = "", @class = "FilterSearch", @maxlength = "32" })
</div>
</div>
</div>
}
<partial name="Panel-AssetCategoryList.cshtml" />
</div>
</div>
<partial name="Panel-AssetCategoryDialog.cshtml" />
@@ -0,0 +1,43 @@
@* View is decoupled from Asset Category model as it may be included in other views, eg. Assets. *@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Asset Category - Select panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Assets/AssetCategory/Panel-AssetCategorySelect")) return;
Model.AdditionalFiles_JS.Add("js/sbm-asset-cat.js");
}
<script type="text/javascript">
</script>
<div id="dlgAssetCategorySelect" class="sbm-dialog sbm-flex sbm-no-padding" title="@Localiser["caption.contact.select"]">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmAssetCategoryFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_AssetCategory.ViewMode.Search, new { @id = "" })
@* Filter Panel *@
<div class="sbm-panel-filter">
<div class="row">
<div class="col-sm-4 row pb4">
@* AssetCategory type *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-8 col-sm-8">
@Html.DropDownList("Filter.AssetCategoryType", Model.GetAssetTypeCodesForFilterDropdown(), Localiser["label.any"], new { @id = "", @class = "FilterAssetCategoryType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@* AssetCategory filter - name etc. *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-8 col-sm-8">
@Html.TextBox("Filter.Search", "", new { @id = "", @class = "FilterSearch sbm-input", @maxlength = "32" })
</div>
</div>
</div>
</div>
}
<partial name="Panel-AssetCategoryList.cshtml" />
</div>
@@ -20,7 +20,7 @@
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmAssociationFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Association.AssociationViewMode.Maintain, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Association.ViewMode.Maintain, new { @id = "" })
@* Header - Page caption, paging controls, actions. *@
<div class="sbm-panel-header">
@@ -48,7 +48,7 @@
@* Association Category *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-7 col-sm-8">
@Html.DropDownList("Filter.AssociationType", Model.GetAssociationTypeCodesForFilterSelect(), @Localiser["label.any"], new { @id = "", @class = "FilterAssociationType sbm-select" })
@Html.DropDownList("Filter.AssociationType", Model.GetAssociationTypeCodesForFilterDropdown(), @Localiser["label.any"], new { @id = "", @class = "FilterAssociationType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -15,7 +15,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmAssociationFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Association.AssociationViewMode.Search, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Association.ViewMode.Search, new { @id = "" })
@Html.Hidden("Filter.OwnerId", "", new { @id = "", @class = "FilterOwnerId" })
@Html.Hidden("Filter.TargetId", "", new { @id = "", @class = "FilterTargetId" })
@@ -26,7 +26,7 @@
@* Association type *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-8 col-sm-8">
@Html.DropDownList("Filter.AssociationType", Model.GetAssociationTypeCodesForFilterSelect(), @Localiser["label.any"], new { @id = "", @class = "FilterAssociationType sbm-select" })
@Html.DropDownList("Filter.AssociationType", Model.GetAssociationTypeCodesForFilterDropdown(), @Localiser["label.any"], new { @id = "", @class = "FilterAssociationType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -2,7 +2,7 @@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Commodity dialog panel */
/* Commodity - Dialog panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Commodity/Panel-CommodityDialog")) return;
}
@@ -35,7 +35,7 @@
</div>
<div class="col-sm">
<div class="sbm-control">
@Html.DropDownList("Commodity.Type", Model.GetCommodityTypeCodesForSelect(), Localiser["label.select"], new { @id = "cbCommodityType", @class = "CommodityType sbm-select" })
@Html.DropDownList("Commodity.Type", Model.GetCommodityTypeCodesForDropdown(), Localiser["label.select"], new { @id = "cbCommodityType", @class = "CommodityType sbm-select" })
</div>
<div class="sbm-message"></div>
</div>
@@ -2,7 +2,7 @@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Commodity list panel */
/* Commodity - List panel */
/* NB Can potentially appear more than once on a page. */
}
@@ -2,7 +2,7 @@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Commodity maintain panel */
/* Commodity - Maintain panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Commodity/Panel-CommodityMaintain")) return;
Model.AdditionalFiles_JS.Add("js/sbm-commodity.js");
@@ -18,7 +18,7 @@
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmCommodityFilter", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Commodity.CommodityViewMode.Maintain, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Commodity.ViewMode.Maintain, new { @id = "" })
@* Header - Page caption, paging controls, actions. *@
<div class="sbm-panel-header">
@@ -44,7 +44,7 @@
@* Commodity Category *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-7 col-sm-8">
@Html.DropDownList("Filter.CommodityType", Model.GetCommodityTypeCodesForSelect(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" })
@Html.DropDownList("Filter.CommodityType", Model.GetCommodityTypeCodesForFilterDropdown(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -2,7 +2,7 @@
@model SbmModel_Portal
@inject SbmLocaliser Localiser
@{
/* Commodity select panel */
/* Commodity - Select panel */
// Ensure view is only included once in page.
if (!Model.RegisterView("Views/Commodity/Panel-CommoditySelect")) return;
Model.AdditionalFiles_JS.Add("js/sbm-commodity.js");
@@ -15,7 +15,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmCommodityFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Commodity.CommodityViewMode.Search, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Commodity.ViewMode.Search, new { @id = "" })
@* Filter Panel *@
<div class="sbm-panel-filter">
@@ -24,7 +24,7 @@
@* Commodity type *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-8 col-sm-8">
@Html.DropDownList("Filter.CommodityType", Model.GetAffiliateTypeCodesForFilterSelect(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" })
@Html.DropDownList("Filter.CommodityType", Model.GetCommodityTypeCodesForFilterDropdown(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -21,7 +21,7 @@
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmContactFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Contact.ContactViewMode.Maintain, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Contact.ViewMode.Maintain, new { @id = "" })
@* Header - Page caption, paging controls, actions. *@
<div class="sbm-panel-header">
@@ -47,7 +47,7 @@
@* Contact type *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-7 col-sm-8">
@Html.DropDownList("Filter.ContactType", Model.GetAffiliateTypeCodesForFilterSelect(), Localiser["label.any"], new { @id = "", @class = "FilterContactType sbm-select" })
@Html.DropDownList("Filter.ContactType", Model.GetAffiliateTypeCodesForFilterDropdown(), Localiser["label.any"], new { @id = "", @class = "FilterContactType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -15,7 +15,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "", @class = "frmContactFilter sbm-form", @onSubmit = "return false;" }))
{
@Html.Hidden("Filter.Mode", Model_Contact.ContactViewMode.Search, new { @id = "" })
@Html.Hidden("Filter.Mode", Model_Contact.ViewMode.Search, new { @id = "" })
@* Filter Panel *@
<div class="sbm-panel-filter">
@@ -24,7 +24,7 @@
@* Contact type *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
<div class="col-8 col-sm-8">
@Html.DropDownList("Filter.ContactType", Model.GetAffiliateTypeCodesForFilterSelect(), Localiser["label.any"], new { @id = "", @class = "FilterContactType sbm-select" })
@Html.DropDownList("Filter.ContactType", Model.GetAffiliateTypeCodesForFilterDropdown(), Localiser["label.any"], new { @id = "", @class = "FilterContactType sbm-select" })
</div>
</div>
<div class="col-sm-4 row pb4">
@@ -45,6 +45,7 @@
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" />
</environment>
<link rel="stylesheet" href="~/css/sbm-base.css?@Model.HrefVersion" />
<link rel="stylesheet" href="~/css/sbm-cols.css?@Model.HrefVersion" />
<link rel="stylesheet" href="~/css/sbm-main.css?@Model.HrefVersion" />
<link rel="stylesheet" href="~/css/sbm-form.css?@Model.HrefVersion" />
<link rel="stylesheet" href="~/css/sbm-data.css?@Model.HrefVersion" />
@@ -0,0 +1,215 @@
@* Assets - Asset *@
@model Model_Asset
@inject SbmLocaliser Localiser
@{
ViewData["Title"] = "Assets";
Model.AdditionalFiles_JS.Add("js/sbm-asset.js");
}
<div class="sbm-panel Assets fullheight">
<script type="text/javascript">
sbm.dlg.title.createItem = '@(Localiser.GetJavascriptText("caption.asset.create"))';
sbm.dlg.title.updateItem = '@(Localiser.GetJavascriptText("caption.asset.update"))';
sbm.lbl.selectCategory = '@(Localiser.GetJavascriptText("caption.category.select"))';
</script>
<div class="sbm-panel-data sbm-flex">
@* Filter form - wrap header to include paging controls. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetFilter", @class = "sbm-form", @onSubmit = "return false;" }))
{
<div class="sbm-panel-header">
<div class="row">
<div class="fixed">
<partial name="~/Views/Common/ResultsPaging.cshtml" />
</div>
<div class="col center"><div class="sbm-panel-caption">@Localiser["label.assets"]</div></div>
<div class="fixed">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
</div>
@* Filter Panel *@
<div class="sbm-panel-filter">
<div class="row pb4">
<div class="col-sm-5 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-sm-7">
@Html.TextBoxFor(model => model.Filter.Search, new { @id = "", @class = "FilterSearch", @maxlength = "32" })
</div>
</div>
</div>
}
<div class="sbm-panel-item-table sbm-flex">
<table class="sbm-item-list">
<thead>
<tr>
<th class="pl-2">@Localiser["label.category"]</th>
<th class="">@Localiser["label.serial"]</th>
<th class="">@Localiser["label.description"]</th>
<th class="center">@Localiser["label.status"]</th>
<th class="right" style="width:2%;"></th>
</tr>
<tr><td colspan="6"><div class="sbm-panel-messages"></div></td></tr>
</thead>
<tbody></tbody>
</table>
</div>
@* Element templates *@
<div class="sbm-panel-item-template">
@* Filter Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu AssetFilter">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
@* Asset row template - table is ignored. *@
<table class="">
<tr class="sbm-row-item Asset">
<td><div class="AssetCategory pl-1"></div></td>
<td><div class="AssetSerial"></div></td>
<td><div class="AssetDescription"></div></td>
<td><div class="AssetStatusDesc center"></div></td>
<td>
<div class="right">
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sbm-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span><span class="sbm-ellipsis-dot"></span></a>
<ul class="dropdown-menu dropdown-menu-right sbm-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</td>
</tr>
</table>
@* Item Burger option template - ul is ignored *@
<ul class="sbm-dropdown-menu Asset">
<li class="sbm-dropdown-item sbm-action"><div class="sbm-label">XXX</div></li>
</ul>
</div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssetId", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.Asset.Id, new { @id = "", @class = "AssetId" })
}
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmCategories", @onSubmit = "return false;" }))
{
}
<div id="dlgAsset" class="sbm-dialog">
<div class="spacer2"></div>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAsset", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.Asset.Exists, new { @id = "", @class = "AssetExists" })
@Html.HiddenFor(model => model.Asset.Id, new { @id = "", @class = "AssetId" })
@* Type *@
<div class="sbm-form-control AssetCategory">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for=""><span>@Localiser["label.category"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control row">
<div class="col">
@Html.HiddenFor(model => model.Asset.CategoryId, new { @id = "", @class = "AssetCategoryId" })
<input type="text" class="AssetCategory sbm-input" readonly="readonly" />
</div>
<div class="fixed">
<div class="sbm-action AssetCategorySearch"><img src="~/img/action/search24.png" alt="" title="" /></div>
</div>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Serial Number*@
<div class="sbm-form-control AssetSerialNumber">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetSerialNumber"><span>@Localiser["label.serial"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBoxFor(model => model.Asset.SerialNumber, new { @id = "ifAssetSerialNumber", @class = "AssetSerialNumber sbm-input upper", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAsset_SerialNumber) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Description *@
<div class="sbm-form-control AssetDescription">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetDescription"><span>@Localiser["label.description"]</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
@Html.TextBoxFor(model => model.Asset.DescBrief, new { @id = "ifAssetDescription", @class = "AssetDescription sbm-input", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAsset_DescBrief) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Status *@
<div class="sbm-form-control AssetStatus">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="cbAssetStatus"><span>@Localiser["label.status"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm-9">
<div class="sbm-control">
<select id="cbAssetStatus" class="sbm-select AssetStatus" name="Asset.StatusCode"></select>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
@* Notes *@
<div class="sbm-form-control AssetNotes">
<div class="row">
<div class="col-sm-3">
<div class="sbm-label">
<label for="ifAssetNotes"><span>@Localiser["label.notes"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
@Html.TextAreaFor(model => model.Asset.Notes, new { @id = "ifAssetNotes", @class = "AssetNotes sbm-textarea", @rows = 3, @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.SaAsset_Notes) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
}
<div class="spacer2"></div>
</div>
@* Select Item dialog and script *@
<partial name="~/Views/Common/SelectItem.cshtml" />
</div>
</div>
@@ -4,6 +4,7 @@
@using Sarand.BusinessMgr.Web.Portal.Models.Contacts
@using Sarand.BusinessMgr.Web.Portal.Models.Commodities
@using Sarand.BusinessMgr.Web.Portal.Models.Assets
@using Sarand.BusinessMgr.Web.Portal.Models.Vehicles
@using Sarand.BusinessMgr.Web.Portal.Models.Codes
@using Sarand.Net.Standard.Base.CodeTypes
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@@ -2,25 +2,6 @@
BusMgr Portal - Base stylesheet.
*/
:root
{
--color-OldGold: #d4af37;
--color-MintGreen: #98fb98;
--color-LimeGreen: #32cd32;
--color-KellyGreen: #4cbb17;
--color-OliveGreen: #808000;
--color-ForestGreen: #228b22;
--color-CornflowerBlue: #6495ed;
--color-RoyalBlue: #4169e1;
--color-NavyBlue: #000080;
--color-DarkBlue: #00008B;
--color-Indigo: #4b0082;
--color-Iris: #5d3fd3;
--color-Burgundy: #800020;
--color-BrightPurple: #bf40bf;
--color-DarkPink: #aa336a;
}
body
{
margin: 0;
@@ -0,0 +1,96 @@
/*
BusMgr Portal - Colours stylesheet.
*/
:root
{
--color-primary: #4b0082;
--color-light: #9b71b9;
--color-pale: #ebe2f1;
--color-OldGold: #d4af37;
--color-MintGreen: #98fb98;
--color-LimeGreen: #32cd32;
--color-KellyGreen: #4cbb17;
--color-OliveGreen: #808000;
--color-ForestGreen: #228b22;
--color-CornflowerBlue: #6495ed;
--color-RoyalBlue: #4169e1;
--color-NavyBlue: #000080;
--color-DarkBlue: #00008B;
--color-Indigo: #4b0082;
--color-Iris: #5d3fd3;
--color-Burgundy: #800020;
--color-BrightPurple: #bf40bf;
--color-DarkPink: #aa336a;
}
/* Data panel */
:root
{
--color-panel-data: var(--color-OliveGreen);
}
.Contacts .sbm-panel-data
{
--color-panel-data: var(--color-ForestGreen);
}
.Associations .sbm-panel-data
{
--color-panel-data: var(--color-Iris);
}
.Commodities .sbm-panel-data
{
--color-panel-data: var(--color-Burgundy);
}
.AssetCategories .sbm-panel-data, .Assets .sbm-panel-data
{
--color-panel-data: var(--color-BrightPurple);
}
.VehicleClasses .sbm-panel-data, .Vehicles .sbm-panel-data
{
--color-panel-data: var(--color-Iris);
}
/* Dialogs */
:root
{
--color-dialog: var(--color-OldGold);
}
.ui-dialog.sbm-dark-blue
{
--color-dialog: var(--color-DarkBlue);
}
.ui-dialog.sbm-Contact
{
--color-dialog: var(--color-ForestGreen);
}
.ui-dialog.sbm-Association
{
--color-dialog: var(--color-Iris);
}
.ui-dialog.sbm-Commodity
{
--color-dialog: var(--color-Burgundy);
}
.ui-dialog.sbm-AssetCategory, .ui-dialog.sbm-Asset
{
--color-dialog: var(--color-BrightPurple);
}
.ui-dialog.sbm-VehicleClass, .ui-dialog.sbm-Vehicle
{
--color-dialog: var(--color-Iris);
}
/* The End */
@@ -4,26 +4,6 @@
/* Data panel */
:root
{
--color-panel-data: var(--color-OliveGreen);
}
.Contacts .sbm-panel-data
{
--color-panel-data: var(--color-ForestGreen);
}
.Associations .sbm-panel-data
{
--color-panel-data: var(--color-Iris);
}
.Commodities .sbm-panel-data
{
--color-panel-data: var(--color-Burgundy);
}
.sbm-panel-data
{
margin: 0 auto;
@@ -2,17 +2,6 @@
BusMgr Portal - Main stylesheet.
*/
/* Global variables */
:root
{
/* Colour analysis: https://www.colorhexa.com/ */
/* #4b0082 - Indigo. Ref. https://www.crispedge.com/color/4b0082 */
--color-primary: #4b0082;
--color-light: #9b71b9;
--color-pale: #ebe2f1;
}
/* Document */
html
@@ -332,31 +321,6 @@ a:focus
/* Dialogs */
:root
{
--color-dialog: var(--color-OldGold);
}
.ui-dialog.sbm-dark-blue
{
--color-dialog: var(--color-DarkBlue);
}
.ui-dialog.sbm-Contact
{
--color-dialog: var(--color-ForestGreen);
}
.ui-dialog.sbm-Association
{
--color-dialog: var(--color-Iris);
}
.ui-dialog.sbm-Commodity
{
--color-dialog: var(--color-Burgundy);
}
.sbm-dialog
{
display: none;
@@ -6,99 +6,125 @@
(function (win, doc, undef)
{
"use strict";
let ac = sbm.AssetCat = { data: {}, ajax: {} };
let $pnl = ac.$pnl = {}, $frm = ac.$frm = {}, $dlg = ac.$dlg = {};
let ac = sbm.AssetCats = { env: {} };
//--------------------------------------------------------------
ac.refreshResults = function (delay)
ac.refreshConfig = function (env, delay)
{
env.ajax.refreshConfig = env.ajax.refreshConfig || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/Config', formSel: env.$frm.filter, callbackFn: function (response) { ac.doRefreshConfig(env, response); } };
sbm.doAjaxRequest(env.ajax.refreshConfig, delay || 50);
}
ac.doRefreshConfig = function (env, response)
{
//sbm.debug('doRefreshConfig', env, response);
if (!response.success) return;
// Config.
env.mode = response.mode;
env.config = response.config;
env.configItemNew = response.configItemNew;
env.data.assetTypes = response.assetTypes;
env.data.statuses = response.statuses;
env.data.statusesCreate = response.statusesCreate;
env.data.statusCodeDefault = response.statusCodeDefault;
}
//--------------------------------------------------------------
ac.refreshResults = function (env, delay)
{
if (!ac.awaitingRefreshResponse)
{
$pnl.bgr.invisible();
$pnl.table.find('tbody tr').remove();
$pnl.msgs.hide().empty().append($('<div class="sbm-message">' + sbm.msg.dataQuerying + '</div>')).fadeIn(200);
env.$pnl.bgr.invisible();
env.$pnl.table.find('tbody tr').remove();
env.$pnl.msgs.hide().empty().append($('<div class="sbm-message">' + sbm.msg.dataQuerying + '</div>')).fadeIn(200);
}
ac.ajax.assetCategories = ac.ajax.assetCategories || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/GetAssetCategories', formId: $frm.filter.prop('id'), callbackFn: ac.handleAssetCategories };
sbm.doAjaxRequest(ac.ajax.assetCategories, delay || 50);
env.ajax.assetCategories = env.ajax.assetCategories || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/GetAssetCategories', formSel: env.$frm.filter, callbackFn: function (response) { ac.doRefreshResults(env, response); } };
sbm.doAjaxRequest(env.ajax.assetCategories, delay || 50);
ac.awaitingRefreshResponse = true;
}
ac.handleAssetCategories = function (response)
ac.doRefreshResults = function (env, response)
{
//sbm.debug('handleAssetCategories', response);
//sbm.debug('doRefreshResults', response);
delete ac.awaitingRefreshResponse;
let $table = $('table', $pnl.table).find('tbody tr').remove().end();
$pnl.msgs.hide().empty();
sbm.refreshPaging(response, '#frmAssetCategoryFilter', ac.refreshResults);
env.$pnl.msgs.hide().empty();
let $table = $('table', env.$pnl.table).find('tbody tr').remove().end();
sbm.refreshPaging(response, env.$frm.filter, function () { ac.refreshResults(env); });
if (!response.success) return;
// Reference data.
if (response.statuses) sbm.data.statuses = response.statuses;
if (response.statusesCreate) sbm.data.statusesCreate = response.statusesCreate;
if (response.statusCodeDefault) sbm.data.statusCodeDefault = response.statusCodeDefault;
ac.doRefreshConfig(env, response);
// Menu.
$pnl.bgr.invisible();
$pnl.mnu.empty();
$pnl.mnu.append(ac.getFilterMenuOption(sbm.lbl.refresh, function () { ac.refreshResults(); }, 'sbm-refresh'));
$pnl.mnu.append(ac.getFilterMenuOption(sbm.lbl.create, function () { ac.createItem(); }, 'sbm-add'));
$pnl.bgr.toggleVisibility(!!$('.sbm-dropdown-item', $pnl.mnu).length);
if (env.$pnl.bgr.length)
{
env.$pnl.bgr.invisible();
env.$pnl.mnu.empty();
env.$pnl.mnu.append(ac.getFilterMenuOption(env, sbm.lbl.refresh, function () { ac.refreshResults(env); }, 'sbm-refresh'));
env.$pnl.mnu.append(ac.getFilterMenuOption(env, sbm.lbl.create, function () { ac.createItem(env, env.configItemNew); }, 'sbm-add'));
env.$pnl.bgr.toggleVisibility(!!$('.sbm-dropdown-item', env.$pnl.mnu).length);
}
// Items.
var items = response.assetCategories || [];
if (!items.length)
return $pnl.msgs.append($('<div class="sbm-message">' + sbm.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
$table.append(ac.populateItem(ac.getItemTemplate(), items[itemIdx]));
return env.$pnl.msgs.append($('<div class="sbm-message">' + sbm.msg.dataNoneFound + '</div>')).fadeIn(500);
for (const item of items)
$table.append(env, ac.populateItem(env, ac.getItemTemplate(env), item));
}
ac.populateItem = function ($item, item)
ac.populateItem = function (env, $item, item)
{
//sbm.debug('populateItem', env, $item, item)
if (!item) return $item;
$pnl.msgs.hide().empty();
$item.prop('id', ac.getItemId(item));
$('.AssetCategoryType', $item).text(item.typeDesc);
$('.AssetCategoryCode', $item).text(item.code);
$('.AssetCategoryDescription', $item).text(item.descBrief);
$('.AssetCategoryStatusDesc', $item).text(item.statusDesc).removeStatusClasses().addClass('sbm-status-' + item.statusCode.toLowerCase());
// Actions.
let fnUpd = function () { ac.updateItem($item, item) };
var $bgr = $('.sbm-burger', $item).invisible();
let $mnu = $('ul.sbm-dropdown-menu', $bgr).empty();
if (!item.deleted)
let cfg = env.config;
if (cfg) sbm.populateItemValues(cfg, $item, item.field.value);
let prefix = cfg.column.prefix;
$('.' + prefix + 'Status', $item).text(item.statusDesc).removeStatusClasses().addClass('sbm-status-' + item.statusCode.toLowerCase());
if (!env.mode.search)
{
$mnu.append(ac.getItemMenuOption(sbm.lbl.edit, fnUpd, 'sbm-edit'));
$('.AssetCategoryCode', $item).off('click').on('click', fnUpd).addClass('sbm-action-text');
$item.off('dblclick').on('dblclick', fnUpd);
// Actions.
let fnUpd = function () { ac.updateItem(env, item.id) };
var $bgr = $('.sbm-burger', $item).invisible();
let $mnu = $('ul.sbm-dropdown-menu', $bgr).empty();
if (!item.deleted)
{
$mnu.append(ac.getItemMenuOption(env, sbm.lbl.edit, fnUpd, 'sbm-edit'));
$('.' + prefix + 'Code', $item).off('click').on('click', fnUpd).addClass('sbm-action-text');
$item.off('dblclick').on('dblclick', fnUpd);
}
$bgr.toggleVisibility(!!$('.sbm-dropdown-item', $mnu).length);
}
else
{
$item.off('click').on('click', function () { ac.selectItemRow(env, $item, item); });
$item.off('dblclick').on('dblclick', function () { ac.selectItem(env); });
}
$bgr.toggleVisibility(!!$('.sbm-dropdown-item', $mnu).length);
return $item;
}
ac.getItemId = function (item)
{
return 'Itm_' + (item || {}).id;
return 'Act_' + (item || {}).id;
}
//--------------------------------------------------------------
ac.getFilterDropdownTemplate = function ()
ac.getFilterDropdownTemplate = function (env)
{
return $('.sbm-dropdown-menu.AssetCategoryFilter li.sbm-dropdown-item', $pnl.tmpls).clone();
return $('.sbm-dropdown-menu.AssetCategoryFilter li.sbm-dropdown-item', env.$pnl.tmpls).clone();
}
ac.getItemTemplate = function ()
ac.getItemTemplate = function (env)
{
return $('table tr.sbm-row-item.AssetCategory', $pnl.tmpls).clone();
return $('table tr.sbm-row-item.AssetCategory', env.$pnl.tmpls).clone();
}
ac.getItemDropdownTemplate = function ()
ac.getItemDropdownTemplate = function (env)
{
return $('.sbm-dropdown-menu.AssetCategory li.sbm-dropdown-item', $pnl.tmpls).clone();
return $('.sbm-dropdown-menu.AssetCategory li.sbm-dropdown-item', env.$pnl.tmpls).clone();
}
//--------------------------------------------------------------
ac.getFilterMenuOption = function (lbl, fn, cls)
ac.getFilterMenuOption = function (env, lbl, fn, cls)
{
return ac.getMenuOption(ac.getFilterDropdownTemplate(), lbl, fn, cls);
return ac.getMenuOption(ac.getFilterDropdownTemplate(env), lbl, fn, cls);
}
ac.getItemMenuOption = function (lbl, fn, cls)
ac.getItemMenuOption = function (env, lbl, fn, cls)
{
return ac.getMenuOption(ac.getItemDropdownTemplate(), lbl, fn, cls);
return ac.getMenuOption(ac.getItemDropdownTemplate(env), lbl, fn, cls);
}
ac.getMenuOption = function ($opt, lbl, fn, cls)
{
@@ -106,101 +132,169 @@
}
//--------------------------------------------------------------
ac.createItem = function ()
ac.createItem = function (env, cfg)
{
ac.clearItem();
sbm.populateSelectCodeDesc('#cbAssetCategoryStatus', sbm.data.statusesCreate);
$('#cbAssetCategoryStatus').val(sbm.data.statusCodeDefault).prop('readonly', false);
$dlg.item.dialog('option', 'title', sbm.dlg.title.createItem);
ac.openAssetCategoryDlg();
sbm.debug('createItem', env, cfg);
ac.clearItem(env, cfg);
let $frm = env.$frm.item;
sbm.populateSelectCodeDesc('#cbAssetCategoryStatus', env.data.statusesCreate);
$('#cbAssetCategoryStatus').val(env.data.statusCodeDefault).prop('readonly', false);
ac.openItemDlg(env, cfg, sbm.dlg.title.createItem);
}
ac.openAssetCategoryDlg = function ()
ac.clearItem = function (env, cfg)
{
sbm.openDialog($dlg.item, 600, 600);
sbm.clearItemForm(env.$frm.item);
sbm.populateSelectCodeDesc('#cbAssetCategoryStatus', env.data.statuses);
}
ac.clearItem = function ()
ac.openItemDlg = function (env, cfg, title)
{
let frm = $frm.item;
$('.AssetCategoryExists,.AssetCategoryId,input[type="text"],textarea,select', frm).val('');
sbm.populateSelectCodeDesc('#cbAssetCategoryStatus', sbm.data.statuses);
$('.AssetCategoryType,.AssetCategoryStatus', frm).prop('disabled', false);
sbm.clearControlErrors();
let $dlg = env.$dlg.item;
let $frm = env.$frm.item;
sbm.configureItemControls(cfg, $frm);
var btns = {};
btns[sbm.lbl.ok] = function () { ac.storeItem(env); };
btns[sbm.lbl.cancel] = function () { delete env.prmEdit; $(this).dialog('close'); };
$dlg.dialog('option', 'buttons', btns);
if (title) $dlg.dialog('option', 'title', title);
sbm.openDialog($dlg, 600, 600);
}
//--------------------------------------------------------------
ac.updateItem = function ($item, item)
ac.updateItem = function (env, id)
{
ac.clearItem();
$('.AssetCategoryId', $frm.itemId).val(item.id);
sbm.ajax.updateItem = sbm.ajax.updateItem || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/GetItem', formId: $frm.itemId.prop('id'), callbackFn: ac.onUpdateItem };
sbm.doAjaxRequest(sbm.ajax.updateItem, 50);
let $frm = env.$frm.itemId;
$('.AssetCategoryId', $frm).val(id);
env.ajax.updateItem = env.ajax.updateItem || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/GetItem', formSel: $frm, callbackFn: function (response) { ac.onUpdateItem(env, response); } };
sbm.doAjaxRequest(env.ajax.updateItem, 50);
}
ac.onUpdateItem = function (response)
ac.onUpdateItem = function (env, response)
{
//sbm.debug('onUpdateItem', response);
let frm = $frm.item;
ac.clearItem();
if (!response.success) return;
let cfg = response.config || {};
ac.clearItem(env, cfg);
let item = response.assetCategory;
$('.AssetCategoryExists', frm).val(1);
$('.AssetCategoryId', frm).val(item.id);
$('.AssetCategoryType', frm).val(item.typeCode).prop('disabled', true);
$('.AssetCategoryCode', frm).val(item.code);
$('.AssetCategoryDescription', frm).val(item.descBrief);
$('.AssetCategoryNotes', frm).val(item.notes);
$('.AssetCategoryStatus', frm).val(item.statusCode).prop('disabled', true);
sbm.clearControlErrors();
$dlg.item.dialog('option', 'title', sbm.dlg.title.updateItem);
ac.openAssetCategoryDlg();
let $frm = env.$frm.item;
sbm.populateFormValues(cfg, $frm, item.field.value);
let $ctrls = $('.sbm-input,.sbm-textarea,.sbm-select', $frm);
$ctrls.filter('.AssetCategoryId').val(item.id);
$ctrls.filter('.AssetCategoryExists').val(1);
sbm.selectOrAdd($ctrls.filter('.AssetCategoryType'), item.typeCode, item.typeDesc);
sbm.selectOrAdd($ctrls.filter('.AssetCategoryStatus'), item.statusCode, item.field.value.Status);
ac.openItemDlg(env, cfg, sbm.dlg.title.updateItem);
}
//--------------------------------------------------------------
ac.storeItem = function ()
ac.storeItem = function (env)
{
sbm.ajax.storeItem = sbm.ajax.storeItem || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/StoreItem', formId: 'frmAssetCategory', callbackFn: ac.onStoreItem };
sbm.doAjaxRequest(sbm.ajax.storeItem, 50);
env.ajax.storeItem = env.ajax.storeItem || { url: sbm.url.base + 'Assets/AssetCategory/Ajax/StoreItem', formSel: env.$frm.item, callbackFn: function (response) { ac.onStoreItem(env, response); } };
sbm.doAjaxRequest(env.ajax.storeItem, 50);
}
ac.onStoreItem = function (response)
ac.onStoreItem = function (env, response)
{
//sbm.debug('onStoreItem', response);
sbm.refreshControlValues(response.controlValues);
if (!response.success) return;
$dlg.item.dialog('close');
env.$dlg.item.dialog('close');
var item = response.assetCategory;
var $item = $('#' + ac.getItemId(item), $pnl.table);
if (!$item.length)
if (env.prmEdit)
{
$item = ac.getItemTemplate();
$('table tbody', $pnl.table).prepend($item).show();
ac.onItemEdited(env, item);
}
ac.populateItem($item, item);
else if (env.$pnl.table.length)
{
env.$pnl.msgs.hide().empty();
var $item = $('#' + ac.getItemId(item), env.$pnl.table);
if (!$item.length)
{
$item = ac.getItemTemplate();
$('table tbody', env.$pnl.table).prepend($item).show();
}
}
ac.populateItem(env, $item, item);
}
//--------------------------------------------------------------
/* Params: type, search, fnSuccess. */
sbm.fn.selectAssetCategory = function (prm)
{
//sbm.debug('selectAssetCategory', prm);
let env = ac.env.select;
env.prmSelect = prm;
env.$frm.filter.find('.FilterAssetCategoryType').val('');
env.$frm.filter.find('.FilterSearch').val(prm.search || '');
env.$pnl.table.find('tbody tr').remove();
sbm.openDialog(env.$dlg.select, 1000, 800);
if (env.$pnl.items.length) setTimeout(function () { ac.refreshResults(env); }, 250);
}
ac.selectItemRow = function (env, $item, item)
{
//sbm.debug('selectItemRow', env, $item, item);
env.$pnl.table.find('tr').removeClass('sbm-sel');
$item.addClass('sbm-sel');
env.prmSelect.item = item;
}
ac.selectItem = function (env)
{
//sbm.debug('selectItem', env, env.prmSelect.item);
env.$dlg.select.dialog('close');
env.prmSelect.fnSuccess(env.prmSelect.item);
delete env.prmSelect;
}
/* Params: id, fnSuccess. */
sbm.fn.editAssetCategory = function (prm)
{
//sbm.debug('editAssetCategory', prm);
let env = ac.env.select;
env.prmEdit = prm;
sbm.debug(env, prm);
ac.updateItem(env, prm.id);
}
ac.onItemEdited = function (env, item)
{
//sbm.debug('ac.onItemEdited', env, item);
env.prmEdit.fnSuccess(item);
delete env.prmEdit;
}
//--------------------------------------------------------------
ac.initEnv = function ($pnlItems)
{
let env = { data: {}, ajax: {}, $pnl: {}, $frm: {}, $ctrl: {}, $dlg: {} };
env.$pnl.items = $($pnlItems);
env.$pnl.header = env.$pnl.items.find('.sbm-panel-header');
env.$pnl.bgr = env.$pnl.header.find('.sbm-burger');
env.$pnl.mnu = env.$pnl.bgr.find('ul.sbm-dropdown-menu');
env.$pnl.table = env.$pnl.items.find('.sbm-panel-item-table');
env.$pnl.msgs = env.$pnl.table.find('.sbm-panel-messages');
env.$pnl.tmpls = env.$pnl.items.find('.sbm-panel-item-template');
env.$frm.filter = $('#frmAssetCategoryFilter').on('input', '.FilterSearch', function () { ac.refreshResults(250); });
env.$frm.itemId = $('#frmAssetCategoryId');
var opt = sbm.dlgOpts();
opt.dialogClass += " sbm-AssetCategory";
env.$dlg.item = $('#dlgAssetCategory').dialog(opt);
env.$frm.item = $('#frmAssetCategory').on('input', '.sbm-input, .sbm-textarea', function () { sbm.clearControlError(this); }).on('change', '.sbm-select', function () { sbm.clearControlError(this); });
var opt = sbm.dlgOpts();
opt.dialogClass += " sbm-AssetCategory";
opt.buttons[sbm.lbl.ok] = function () { ac.selectItem(env); };
opt.buttons[sbm.lbl.cancel] = function () { delete env.prmSelect; $(this).dialog('close'); };
env.$dlg.select = $('#dlgAssetCategorySelect').dialog(opt);
return env;
}
//--------------------------------------------------------------
$(function ()
{
$pnl.items = $('.sbm-panel.AssetCategories');
$pnl.header = $('.sbm-panel-header', $pnl.items);
$pnl.bgr = $('.sbm-burger', $pnl.header);
$pnl.mnu = $('ul.sbm-dropdown-menu', $pnl.bgr);
$pnl.filter = $('.sbm-panel-filter', $pnl.items);
$pnl.table = $('.sbm-panel-item-table', $pnl.items);
$pnl.msgs = $('.sbm-panel-messages', $pnl.items);
$pnl.tmpls = $('.sbm-panel-item-template', $pnl.items);
$frm.filter = $('#frmAssetCategoryFilter');
$('.FilterSearch', $frm.filter).on('input', function () { ac.refreshResults(250); });
$frm.itemId = $('#frmAssetCategoryId');
var opt = sbm.dlgOpts();
opt.buttons[sbm.lbl.save] = function () { ac.storeItem(); };
opt.buttons[sbm.lbl.cancel] = function () { $(this).dialog('close'); };
$dlg.item = $('#dlgAssetCategory').dialog(opt);
$frm.item = $('#frmAssetCategory');
$($frm.item).on('input', '.sbm-input, .sbm-textarea', function () { sbm.clearControlError(this); }).on('change', '.sbm-select', function () { sbm.clearControlError(this); });
setTimeout(ac.refreshResults, 250);
ac.env.maint = ac.initEnv('.sbm-panel.AssetCategories');
if (ac.env.maint.$pnl.items.length) setTimeout(function () { ac.refreshResults(ac.env.maint); }, 250);
ac.env.select = ac.initEnv('#dlgAssetCategorySelect');
if (ac.env.select.$pnl.items.length) setTimeout(function () { ac.refreshConfig(ac.env.select); }, 250);
});
//--------------------------------------------------------------
@@ -214,6 +214,7 @@
$frm.itemId = $('#frmAssetId');
$frm.categories = $('#frmCategories');
var opt = sbm.dlgOpts();
opt.dialogClass += " sbm-Asset";
opt.buttons[sbm.lbl.save] = function () { ac.storeItem(); };
opt.buttons[sbm.lbl.cancel] = function () { $(this).dialog('close'); };
$dlg.item = $('#dlgAsset').dialog(opt);
@@ -20,7 +20,7 @@
// Config.
env.mode = response.mode;
env.config = response.config;
env.configCmd = response.configCmd;
env.configItemNew = response.configItemNew;
env.data.commodityTypes = response.commodityTypes;
env.data.statuses = response.statuses;
env.data.defaultStatusCode = response.defaultStatusCode;
@@ -55,7 +55,7 @@
env.$pnl.bgr.invisible();
env.$pnl.mnu.empty();
env.$pnl.mnu.append(co.getFilterMenuOption(env, sbm.lbl.refresh, function () { co.refreshResults(env); }, 'sbm-refresh'));
env.$pnl.mnu.append(co.getFilterMenuOption(env, sbm.lbl.create, function () { co.createItem(env, env.configCmd); }, 'sbm-add'));
env.$pnl.mnu.append(co.getFilterMenuOption(env, sbm.lbl.create, function () { co.createItem(env, env.configItemNew); }, 'sbm-add'));
env.$pnl.bgr.toggleVisibility(!!$('.sbm-dropdown-item', env.$pnl.mnu).length);
}
@@ -63,8 +63,8 @@
var items = response.commodities || [];
if (!items.length)
return env.$pnl.msgs.append($('<div class="sbm-message">' + sbm.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
$table.append(co.populateItem(env, co.getItemTemplate(env), items[itemIdx]));
for (const item of items)
$table.append(co.populateItem(env, co.getItemTemplate(env), item));
}
co.populateItem = function (env, $item, item)
{
@@ -72,10 +72,10 @@
$item.prop('id', co.getItemId(item));
let cfg = env.config;
if (cfg) sbm.populateItemValues(cfg, $item, item.field.value);
let prefix = cfg.column.prefix;
$('.' + prefix + 'Status', $item).text(item.statusDesc).removeStatusClasses().addClass('sbm-status-' + item.statusCode.toLowerCase());
if (!env.mode.search)
{
let prefix = cfg.column.prefix;
$('.' + prefix + 'Status', $item).text(item.statusDesc).removeStatusClasses().addClass('sbm-status-' + item.statusCode.toLowerCase());
// Actions.
var $bgr = $('.sbm-burger', $item).hide();
let $mnu = $('ul.sbm-dropdown-menu', $bgr).empty();
@@ -182,9 +182,7 @@
//--------------------------------------------------------------
co.storeItem = function (env)
{
env.ajax.storeItem = env.ajax.storeItem || {
url: sbm.url.base + 'Commodity/Ajax/StoreItem', formSel: env.$frm.item, callbackFn: function (response) { co.onStoreItem(env, response); }
};
env.ajax.storeItem = env.ajax.storeItem || {url: sbm.url.base + 'Commodity/Ajax/StoreItem', formSel: env.$frm.item, callbackFn: function (response) { co.onStoreItem(env, response); }};
sbm.doAjaxRequest(env.ajax.storeItem, 50);
}
co.onStoreItem = function (env, response)
@@ -256,7 +254,7 @@
}
//--------------------------------------------------------------
co.initCommodityEnv = function ($pnlItems)
co.initEnv = function ($pnlItems)
{
let env = { data: {}, ajax: {}, $pnl: {}, $frm: {}, $ctrl: {}, $dlg: {} };
@@ -288,12 +286,13 @@
//--------------------------------------------------------------
$(function ()
{
co.env.maint = co.initCommodityEnv('.sbm-panel.Commodities');
co.env.maint = co.initEnv('.sbm-panel.Commodities');
if (co.env.maint.$pnl.items.length) setTimeout(function () { co.refreshResults(co.env.maint); }, 250);
co.env.select = co.initCommodityEnv('#dlgCommoditySelect');
co.env.select = co.initEnv('#dlgCommoditySelect');
if (co.env.select.$pnl.items.length) setTimeout(function () { co.refreshConfig(co.env.select); }, 250);
});
//--------------------------------------------------------------
}(window, window.document));
/* The End */