CW Products MMS Model

Error executing template "Designs/Swift/Paragraph/CPQ_Inputs.cshtml"
System.IO.IOException: The process cannot access the file 'E:\DynamicWeb\Solutions\CPQ-Dev-Old\wwwroot\Files\System\Log\Custom\DWCPQ - modelForm\2026-07-31.log' because it is being used by another process.
   at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.StreamWriter.ValidateArgsAndOpenPath(String path, Boolean append, Encoding encoding, Int32 bufferSize)
   at System.IO.StreamWriter..ctor(String path, Boolean append, Encoding encoding)
   at DW_CPQ_API.Helpers.LogHelper.WriteLine(String text, Boolean append)
   at DW_CPQ_API.Helpers.LogHelper.WriteFormattedLog(LogLevel level, String text)
   at DW_CPQ_API.Helpers.LogHelper.Info(String text)
   at DW_CPQ_API.ModelController.LoadFormInput()
   at DW_CPQ_API.ModelController.LoadFormApplyRules()
   at DW_CPQ_API.ModelController.GetModelData()
   at DW_CPQ_API.ModelController..ctor(String modelVersionId, Nullable`1 pageId, NameValueCollection requestVars)
   at DW_CPQ_API.ModelController..ctor(Int32 pageId, NameValueCollection requestVars)
   at CompiledRazorTemplates.Dynamic.RazorEngine_b56c023e858a4a09a4086d5edd325fd5.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using System 4 @using DW_CPQ_API 5 @using System.Text.Json 6 @using System.Linq 7 8 @{ 9 10 var modelController = Dynamicweb.Context.Current.Items["ModelController"] as ModelController; 11 12 if(modelController == null) 13 { 14 modelController = new ModelController(Model.PageID, Dynamicweb.Context.Current.Request.Params); 15 Dynamicweb.Context.Current.Items["ModelController"] = modelController; 16 } 17 18 //when debugmode is "true" set input name in div element as its title attribute for easy identification 19 string debugmode =""; 20 if( Dynamicweb.Context.Current.Request.QueryString.Get("debugmode") != null) 21 { 22 debugmode= Dynamicweb.Context.Current.Request.QueryString.Get("debugmode")!; 23 } 24 var cpq_model = modelController.DocumentResult; 25 26 string sectionTitle = Model.Item?.GetString("CPQ_SectionTitle") ?? ""; 27 string inputGroupName = Model.Item?.GetString("CPQ_InputGroupName") ?? ""; 28 string rowTabName = ""; 29 var currentParagraph = Dynamicweb.Content.Services.Paragraphs.GetParagraph(Model.ID); 30 if (currentParagraph != null && currentParagraph.GridRowId > 0) 31 { 32 var row = Dynamicweb.Content.Services.Grids.GetGridRowById(currentParagraph.GridRowId); 33 if (row != null) 34 { 35 var rowItem = Dynamicweb.Content.Services.Items.GetItem(row.ItemType, row.ItemId); 36 rowTabName = rowItem?["CPQ_TabName"]?.ToString() ?? ""; 37 } 38 } 39 40 string inputGroupPrefixSource = rowTabName; 41 string inputGroupPrefix = new string((inputGroupPrefixSource ?? string.Empty) 42 .Select(ch => char.IsLetterOrDigit(ch) || ch == '_' || ch == '-' ? ch : '_') 43 .ToArray()); 44 if (string.IsNullOrWhiteSpace(inputGroupPrefix)) 45 { 46 inputGroupPrefix = "default"; 47 } 48 49 var cpqPage = Dynamicweb.Content.Services.Pages.GetPage(Model.PageID); 50 string cpqTheme = (cpqPage.Item["CPQ_Theme"] ?? "cpq-bold").ToString(); 51 52 int inputColumns = Convert.ToInt32(Model.Item?.GetValue("CPQ_InputColumns") ?? 1); 53 54 string versionId=modelController.ModelVersionId; 55 56 string normalizedInputGroupName = (inputGroupName ?? string.Empty).Trim(); 57 var allGroups = cpq_model.Groups ?? new List<DW_CPQ_API.Classes.InputGroup>(); 58 59 var selectedRootGroups = allGroups 60 .Where(x => string.Equals((x.Name ?? string.Empty).Trim(), normalizedInputGroupName, StringComparison.OrdinalIgnoreCase) 61 || string.Equals((x.Label ?? string.Empty).Trim(), normalizedInputGroupName, StringComparison.OrdinalIgnoreCase)) 62 .ToList(); 63 64 var selectedRootGroupNames = selectedRootGroups 65 .Select(x => (x.Name ?? string.Empty).Trim()) 66 .Where(x => !string.IsNullOrWhiteSpace(x)) 67 .Distinct(StringComparer.OrdinalIgnoreCase) 68 .ToList(); 69 70 var childGroups = new List<DW_CPQ_API.Classes.InputGroup>(); 71 if (selectedRootGroupNames.Any()) 72 { 73 var pendingParents = new Queue<string>(selectedRootGroupNames); 74 var visitedParents = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 75 76 while (pendingParents.Count > 0) 77 { 78 var parentName = (pendingParents.Dequeue() ?? string.Empty).Trim(); 79 if (string.IsNullOrWhiteSpace(parentName) || !visitedParents.Add(parentName)) 80 { 81 continue; 82 } 83 84 var directChildren = allGroups 85 .Where(x => string.Equals((x.ParentGroup ?? string.Empty).Trim(), parentName, StringComparison.OrdinalIgnoreCase)) 86 .OrderBy(x => x.Seq ?? 0) 87 .ToList(); 88 89 foreach (var child in directChildren) 90 { 91 var childName = (child.Name ?? string.Empty).Trim(); 92 if (string.IsNullOrWhiteSpace(childName)) 93 { 94 continue; 95 } 96 97 if (!childGroups.Any(x => string.Equals((x.Name ?? string.Empty).Trim(), childName, StringComparison.OrdinalIgnoreCase))) 98 { 99 childGroups.Add(child); 100 pendingParents.Enqueue(childName); 101 } 102 } 103 } 104 } 105 106 var filterGroupNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 107 if (string.IsNullOrWhiteSpace(normalizedInputGroupName)) 108 { 109 // Intentionally keep filterGroupNames empty so no inputs are rendered 110 // when CPQ_InputGroupName is not set. 111 } 112 else if (selectedRootGroupNames.Any()) 113 { 114 foreach (var rootName in selectedRootGroupNames) 115 { 116 filterGroupNames.Add(rootName); 117 } 118 119 foreach (var childGroup in childGroups) 120 { 121 var childName = (childGroup.Name ?? string.Empty).Trim(); 122 if (!string.IsNullOrWhiteSpace(childName)) 123 { 124 filterGroupNames.Add(childName); 125 } 126 } 127 } 128 else 129 { 130 filterGroupNames.Add(normalizedInputGroupName); 131 } 132 133 var filteredInputs = cpq_model.Inputs 134 .Where(x => filterGroupNames.Contains((x.GroupName ?? string.Empty).Trim())) 135 .ToList(); 136 137 var groupLabelByName = allGroups 138 .Where(x => !string.IsNullOrWhiteSpace(x.Name)) 139 .GroupBy(x => (x.Name ?? string.Empty).Trim(), StringComparer.OrdinalIgnoreCase) 140 .ToDictionary( 141 x => x.Key, 142 x => x.FirstOrDefault(y => !string.IsNullOrWhiteSpace(y.Label))?.Label ?? x.First().Name ?? x.Key, 143 StringComparer.OrdinalIgnoreCase); 144 145 bool showSubgroupTitles = selectedRootGroupNames.Any() && childGroups.Any(); 146 var renderedSubgroupTitles = new HashSet<string>(StringComparer.OrdinalIgnoreCase); 147 148 string hideSection = ""; 149 int inputCount = filteredInputs.Count(x => x.Visible == null || x.Visible == true); 150 151 if (!string.IsNullOrWhiteSpace(normalizedInputGroupName)) 152 { 153 var inputGrp = selectedRootGroups.FirstOrDefault(); 154 if( inputGrp != null ) 155 { 156 if(inputGrp.Visible == false || inputCount == 0) 157 { 158 hideSection = "style=\"display:none;\""; 159 } 160 else 161 { 162 sectionTitle = inputGrp.Label; 163 } 164 } 165 else 166 { 167 if( inputCount == 0 ) 168 { 169 hideSection = "style=\"display:none;\""; 170 } 171 } 172 } 173 174 } 175 176 <div class="input-section-@inputGroupName" @hideSection> 177 @if( !string.IsNullOrEmpty(sectionTitle) )//&& 178 { 179 <div class="input-section-title">@sectionTitle</div> 180 } 181 @if (!string.IsNullOrWhiteSpace(normalizedInputGroupName)) 182 { 183 <div name="result"></div> 184 <form> 185 186 <div class="container inputs-container input-columns-@inputColumns"> 187 188 @foreach(var inputItem in filteredInputs) 189 { 190 if (showSubgroupTitles && !selectedRootGroupNames.Contains((inputItem.GroupName ?? string.Empty).Trim())) 191 { 192 var subgroupName = (inputItem.GroupName ?? string.Empty).Trim(); 193 if (!string.IsNullOrWhiteSpace(subgroupName) && renderedSubgroupTitles.Add(subgroupName)) 194 { 195 var subgroupTitle = groupLabelByName.ContainsKey(subgroupName) ? groupLabelByName[subgroupName] : subgroupName; 196 <div class="input-section-title mt-3" data-subgroup="@subgroupName.ToLower()">@subgroupTitle</div> 197 } 198 } 199 200 var hidden = ""; 201 if( inputItem.Visible != null && inputItem.Visible == false ) hidden = "display:none;"; 202 203 var normalizedFieldWidth = (inputItem.FieldWidth ?? "").Trim().ToLowerInvariant(); 204 var fieldWidthClass = normalizedFieldWidth == "halfwidth" ? "field-width-half" : "field-width-full"; 205 206 var strRequired = ""; 207 if( inputItem.Required != null && inputItem.Required == true ) strRequired = "add-label-required"; 208 209 bool isRequired = inputItem.Required == true; 210 // bool isInvalid = isRequired && string.IsNullOrEmpty(inputItem.Value); 211 //string validationClass = isInvalid ? "is-invalid" : ""; 212 var inputSettings = inputItem.Settings ?? new List<DW_CPQ_API.Classes.NameValue>(); 213 bool isReadOnly = Convert.ToBoolean(inputSettings.FirstOrDefault(x => x.Name == "readonly")?.Value?.ToString() ?? false); 214 string valuePrefix = inputSettings.FirstOrDefault(x => x.Name.Equals("value-prefix", StringComparison.OrdinalIgnoreCase))?.Value?.ToString() ?? ""; 215 string valueSuffix = inputSettings.FirstOrDefault(x => x.Name.Equals("value-suffix", StringComparison.OrdinalIgnoreCase))?.Value?.ToString() ?? ""; 216 string valueFormat = inputSettings.FirstOrDefault(x => x.Name.Equals("value-format", StringComparison.OrdinalIgnoreCase) || x.Name.Equals("format", StringComparison.OrdinalIgnoreCase))?.Value?.ToString()?.Trim().ToLowerInvariant() ?? ""; 217 string settingsKeywordText = string.Join(" ", inputSettings 218 .Select(x => $"{x.Name} {x.Value}") 219 .Where(x => !string.IsNullOrWhiteSpace(x))) 220 .ToLowerInvariant(); 221 if (string.IsNullOrWhiteSpace(valueFormat)) 222 { 223 if (settingsKeywordText.Contains("currency")) valueFormat = "currency"; 224 else if (settingsKeywordText.Contains("inch")) valueFormat = "inch"; 225 else if (settingsKeywordText.Contains("kg")) valueFormat = "kg"; 226 } 227 if (string.IsNullOrWhiteSpace(valuePrefix) && string.IsNullOrWhiteSpace(valueSuffix)) 228 { 229 if (valueFormat == "currency") valuePrefix = "$"; 230 if (valueFormat == "inch") valueSuffix = "\""; 231 if (valueFormat == "kg") valueSuffix = "kg"; 232 } 233 bool hasValueAffix = !string.IsNullOrWhiteSpace(valuePrefix) || !string.IsNullOrWhiteSpace(valueSuffix); 234 235 string inputOptionColumns = inputSettings.FirstOrDefault(x => x.Name == "option-columns")?.Value?.ToString() ?? "3"; 236 string imageClass = inputSettings.FirstOrDefault(x => x.Name == "option-image-class")?.Value?.ToString() ?? ""; 237 238 bool hideOptionLabel = (inputSettings.FirstOrDefault(x => x.Name == "hide-label")?.Value?.ToString() ?? "").ToLower() == "true"; 239 bool noLabel = (inputSettings.FirstOrDefault(x => x.Name == "no-label")?.Value?.ToString() ?? "").ToLower() == "true"; 240 241 <div class="input-@(inputItem.Type)-container input-container @fieldWidthClass @(inputItem.Type=="radiobox"||inputItem.Type=="radioswatch"||inputItem.Type=="checkboxLarge"?"input-grid":"")" id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" style="@hidden" title="@(debugmode=="true"?inputItem.Name:"")"> 242 243 @{ 244 if( noLabel ) 245 { 246 <div id="@($"{inputGroupPrefix}_label_{inputItem.Name}")" style="display:none;"></div> 247 } 248 else 249 { 250 <div class="input-label @strRequired" id="@($"{inputGroupPrefix}_label_{inputItem.Name}")">@inputItem.Label</div> 251 } 252 } 253 254 <div class="input-control input-control-col-@inputOptionColumns" @(noLabel?"style=\"width:100%\"":"")> 255 256 @if( inputItem.Type == "toggle" ) 257 { 258 259 string isChecked = ""; 260 // if( inputItem.Value != null && (inputItem.Value.ToLower()=="true" || inputItem.Value.ToLower()=="on"|| inputItem.Value.ToLower()=="yes") ) 261 if( inputItem.Value is bool toggleValue && toggleValue) 262 { 263 isChecked = "checked"; 264 } 265 <label class="toggle-switch" > 266 <input type="checkbox" name="@inputItem.Name" id="@($"{inputGroupPrefix}_{inputItem.Name}")" @isChecked onclick="updateModelForm({inputname:this.name,inputvalue:this.checked});" data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())"> 267 <span class="toggle-slider"></span> 268 </label> 269 } 270 @if( inputItem.Type == "radio" ) // Radio Button 271 { 272 bool optionInline = Convert.ToBoolean(inputItem.Settings.FirstOrDefault(x => x.Name == "option-inline")?.Value.ToString() ?? inputItem.Options.Count <= 2); 273 string inlineClass = ""; 274 if( optionInline ) inlineClass = "form-check-inline"; 275 foreach( var option in inputItem.Options ) 276 { 277 string optionDisabled = ""; 278 if( option.Disabled ) optionDisabled = "disabled"; 279 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 280 <div class="form-check @inlineClass @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")"> 281 <input class="form-check-input" type="radio" id="@optionId" name="@inputItem.Name" value="@option.Value" onclick="updateModelForm({inputname:this.name,inputvalue:this.value});" checked="@option.Selected" @optionDisabled data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 282 <label class="form-check-label" onclick="this.parentElement.querySelector('#@optionId').click();">@option.Label</label> 283 @if( !string.IsNullOrEmpty(option.Image) ) 284 { 285 <img src="@option.Image" class="@imageClass" onclick="this.parentElement.querySelector('#@optionId').click();" /> 286 } 287 </div> 288 } 289 } 290 @if( inputItem.Type == "radiobox" ) 291 { 292 foreach (var option in inputItem.Options) 293 { 294 string optionDisabled = ""; 295 if( option.Disabled ) optionDisabled = "option-disabled"; 296 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 297 var selectedText = option.Selected ? "selected" : ""; 298 <div class="@selectedText @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")" 299 onclick="this.querySelector('#@optionId').click();"> 300 <input type="radio" name="@inputItem.Name" id="@optionId" value="@option.Value" style="display:none;" checked="@option.Selected" 301 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});"/> 302 @if( !string.IsNullOrEmpty(option.Image) ) 303 { 304 <img src="@option.Image" class="@imageClass" /> 305 } 306 @if(!hideOptionLabel) 307 { 308 <label onclick="this.parentElement.querySelector('#@optionId').click();">@option.Label</label> 309 } 310 </div> 311 } 312 } 313 @if ( inputItem.Type == "radioswatch" ) 314 { 315 <div class="color-options"> 316 @foreach (var option in inputItem.Options) 317 { 318 string optionDisabled = option.Disabled ? "option-disabled" : ""; 319 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 320 var selectedClass = option.Selected ? "selected" : ""; 321 322 <div class="color-item @selectedClass @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 323 id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")" 324 onclick="this.querySelector('#@optionId').click();"> 325 326 <input type="radio" 327 name="@inputItem.Name" 328 id="@optionId" 329 value="@option.Value" 330 style="display:none;" 331 checked="@option.Selected" 332 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" 333 onclick="updateModelForm({inputname:this.name, inputvalue:this.value});" /> 334 335 <div class="color-circle" 336 style="background:@option.Value;"> 337 </div> 338 339 @if (!hideOptionLabel) 340 { 341 <label>@option.Label</label> 342 } 343 </div> 344 } 345 </div> 346 } 347 @if( inputItem.Type == "checkbox" ) 348 { 349 foreach( var option in inputItem.Options ) 350 { 351 string optionDisabled = ""; 352 if( option.Disabled ) optionDisabled = "option-disabled"; 353 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 354 <div class="@optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")" 355 onclick="if(event.target.closest('label,input')) return; this.querySelector('#@optionId').click();"> 356 @if( !string.IsNullOrEmpty(option.Image) ) 357 { 358 <img src="@option.Image" class="@imageClass" /> 359 } 360 <label class="highlight"> 361 <input type="checkbox" name="@inputItem.Name" id="@optionId" value="@option.Value" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});" checked="@option.Selected" data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 362 <span>@option.Label</span> 363 </label> 364 365 </div> 366 } 367 } 368 @if( inputItem.Type == "checkboxLarge" ) 369 { 370 foreach (var option in inputItem.Options) 371 { 372 string optionDisabled = ""; 373 if( option.Disabled ) optionDisabled = "option-disabled"; 374 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 375 <div class="@optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")" 376 onclick="if(event.target.closest('input')) return; this.querySelector('#@optionId').click();"> 377 <input type="checkbox" name="@inputItem.Name" id="@optionId" value="@option.Value" class="hidden-checkbox" onclick="updateModelForm({inputname:this.name, inputvalue:this.value});" 378 checked="@option.Selected" @optionDisabled data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 379 <img src="@option.Image" class="@imageClass" /> 380 <span class="checkbox-indicator @(option.Selected ? "checked" : "")"> 381 <span class="checkmark @(option.Selected ? "visible" : "")">✔</span> 382 </span> 383 <label> 384 <span>@option.Label</span> 385 </label> 386 </div> 387 } 388 } 389 @if (inputItem.Type == "select"){ 390 @RenderPartial("Components/CPQ/Select.cshtml", new DW_CPQ_API.Classes.CPQInputViewModel{ InputItem = inputItem, InputGroupPrefix = inputGroupPrefix }); 391 } 392 393 @if (inputItem.Type == "text") 394 { 395 if (hasValueAffix) 396 { 397 <div class="input-group cpq-input-with-format"> 398 @if (!string.IsNullOrWhiteSpace(valuePrefix)) 399 { 400 <span class="input-group-text cpq-input-prefix">@valuePrefix</span> 401 } 402 <input class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 403 value="@inputItem.Value" 404 name="@inputItem.Name" 405 type="text" 406 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 407 data-field="@inputItem.Name" 408 placeholder="@inputItem.Placeholder" 409 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 410 @(isReadOnly ? "readonly=\"readonly\"" : "") 411 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 412 @if (!string.IsNullOrWhiteSpace(valueSuffix)) 413 { 414 <span class="input-group-text cpq-input-suffix">@valueSuffix</span> 415 } 416 </div> 417 } 418 else 419 { 420 <input class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 421 value="@inputItem.Value" 422 name="@inputItem.Name" 423 type="text" 424 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 425 data-field="@inputItem.Name" 426 placeholder="@inputItem.Placeholder" 427 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 428 @(isReadOnly ? "readonly=\"readonly\"" : "") 429 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 430 } 431 } 432 433 @if( inputItem.Type == "number" ) 434 { 435 decimal minValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "min")?.Value.ToString() ?? 0); 436 decimal maxValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "max")?.Value.ToString() ?? 0); 437 decimal stepValue = Convert.ToDecimal(inputItem.Settings.FirstOrDefault(x => x.Name == "step")?.Value.ToString() ?? 0); 438 439 string minmaxString = ""; 440 if( minValue != maxValue ) 441 { 442 minmaxString = $"min=\"{minValue}\" max=\"{maxValue}\""; 443 } 444 445 string stepString = ""; 446 if( stepValue > 0 ) 447 { 448 stepString = $"step=\"{stepValue}\""; 449 } 450 451 <!-- need readonly option --> 452 @* <input class="form-control" 453 value="@inputItem.Value" 454 name="@inputItem.Name" 455 type="number" 456 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 457 placeholder="@inputItem.Placeholder" 458 @(isReadOnly ? "readonly=\"readonly\"" : "") 459 @minmaxString @stepString onblur="checkLimits(this)" 460 /> *@ 461 462 @if (hasValueAffix) 463 { 464 <div class="input-group cpq-input-with-format"> 465 @if (!string.IsNullOrWhiteSpace(valuePrefix)) 466 { 467 <span class="input-group-text cpq-input-prefix">@valuePrefix</span> 468 } 469 <input 470 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 471 type="number" 472 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 473 data-field="@inputItem.Name" 474 name="@inputItem.Name" 475 value="@inputItem.Value" 476 onfocus="this.select();" 477 placeholder="@inputItem.Placeholder" 478 readonly="@isReadOnly" 479 disabled="@isReadOnly" 480 @minmaxString @stepString onblur="updateModelForm({inputname:this.name,inputvalue:this.value});" 481 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" 482 /> 483 @if (!string.IsNullOrWhiteSpace(valueSuffix)) 484 { 485 <span class="input-group-text cpq-input-suffix">@valueSuffix</span> 486 } 487 </div> 488 } 489 else 490 { 491 <input 492 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 493 type="number" 494 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 495 data-field="@inputItem.Name" 496 name="@inputItem.Name" 497 value="@inputItem.Value" 498 onfocus="this.select();" 499 placeholder="@inputItem.Placeholder" 500 readonly="@isReadOnly" 501 disabled="@isReadOnly" 502 @minmaxString @stepString onblur="updateModelForm({inputname:this.name,inputvalue:this.value});" 503 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" 504 /> 505 } 506 <div class="invalid-feedback"> 507 Value out of range 508 </div> 509 } 510 511 @if (inputItem.Type == "lookup") 512 { 513 var jsonString = "{}"; 514 if(inputItem.Parameters != null && inputItem.Parameters.Count > 0) 515 { 516 jsonString = JsonSerializer.Serialize(inputItem.Parameters); 517 } 518 519 <div class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"> 520 <div class="position-relative"> 521 <input type="text" 522 id="@($"{inputGroupPrefix}_lookup_{inputItem.Name}")" 523 name="lookup_@inputItem.Name" 524 class="form-control lookup-input cpqlookup" 525 value="@inputItem.ValueText" 526 placeholder="Type to search..." 527 data-params='@jsonString' 528 data-lookupName="@inputItem.Name" 529 data-versionId="@versionId" 530 autocomplete="off" 531 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 532 </div> 533 534 <input type="hidden" 535 value="@inputItem.Value" 536 name="@inputItem.Name" 537 id="@($"{inputGroupPrefix}_{inputItem.Name}")" /> 538 539 <div id="@($"{inputGroupPrefix}_lookupresult_{inputItem.Name}")" class="lookup-results"></div> 540 541 <div class="invalid-feedback"> 542 This field is required. 543 </div> 544 </div> 545 } 546 547 @if (inputItem.Type == "longtext") 548 { 549 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"> 550 <textarea 551 class="form-control @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 552 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 553 data-field="@inputItem.Name" 554 name="@inputItem.Name" 555 placeholder="@inputItem.Placeholder" 556 rows="2" 557 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 558 @(isReadOnly ? "readonly=\"readonly\"" : "") 559 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">@inputItem.Value</textarea> 560 </div> 561 } 562 563 @if (inputItem.Type == "richtext") 564 { 565 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"> 566 <textarea 567 class="form-control rich-editor" 568 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 569 data-field="@inputItem.Name" 570 name="@inputItem.Name" 571 placeholder="@inputItem.Placeholder" 572 rows="1" 573 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 574 @(isReadOnly ? "readonly=\"readonly\"" : "") 575 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())">@inputItem.Value</textarea> 576 </div> 577 } 578 579 @if (inputItem.Type == "button") 580 { 581 <div id="@($"{inputGroupPrefix}_visible_{inputItem.Name}")" class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"> 582 <button 583 type="button" 584 class="btn @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 585 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 586 name="@inputItem.Name" 587 @(isReadOnly ? "disabled" : "") 588 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())"> 589 @inputItem.Value 590 </button> 591 </div> 592 } 593 594 @if (inputItem.Type == "date") 595 { 596 <div class="mb-3 @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)"> 597 <input type="text" 598 class="form-control datepicker @(inputItem.Required == true && string.IsNullOrEmpty(inputItem.Value as string) ? "is-invalid" : "")" 599 name="@inputItem.Name" 600 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 601 value="@inputItem.Value" 602 placeholder="Select date" 603 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 604 @(inputItem.Required == true ? "required" : "") 605 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 606 </div> 607 } 608 609 @if (inputItem.Type == "popup") 610 { 611 <input class="form-control popup-message-field @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 612 value="@inputItem.Value" 613 name="@inputItem.Name" 614 type="text" 615 id="@($"{inputGroupPrefix}_{inputItem.Name}")" 616 onchange="updateModelForm({inputname:this.name,inputvalue:this.value});" 617 placeholder="@inputItem.Placeholder" 618 @(isReadOnly ? "readonly=\"readonly\"" : "") 619 data-required="@(inputItem.Required.GetValueOrDefault().ToString().ToLower())" /> 620 } 621 622 @if( inputItem.Type == "buttonGroup" ) 623 { 624 @foreach (var option in inputItem.Options) 625 { 626 string optionDisabled = option.Disabled ? "option-disabled" : ""; 627 string selectedText = option.Selected ? "selected" : ""; 628 var optionId = $"{inputGroupPrefix}_{inputItem.Name}_{option.Value.Replace(" ", "")}"; 629 var url = option.Value.StartsWith("http") ? option.Value : "https://" + option.Value; 630 631 <a href="@url" 632 target="_blank" 633 class="option-link @selectedText @optionDisabled @(string.IsNullOrWhiteSpace(inputItem.StylingText) ? "" : inputItem.StylingText)" 634 id="@($"{inputGroupPrefix}_optionVisible_{inputItem.Name}_{option.Value.Replace(" ", "")}")" 635 onclick="selectOption(this,true);"> 636 637 @if( !string.IsNullOrEmpty(option.Image) ) 638 { 639 <img src="@option.Image" class="@imageClass" /> 640 } 641 @if(!hideOptionLabel) 642 { 643 <label for="@optionId" class="option-label">@option.Label</label> 644 } 645 </a> 646 } 647 } 648 649 </div> 650 </div> 651 } 652 </div> 653 </form> 654 } 655 </div> 656
Operation No Type Route Link Code Description Run Time
No Description Group Quantity Per Length (mm) Routing Link Code
Item No Description UOM Unit Cost List Price Customer Disc. Unit Sell Qty Line Cost Line Sell Disc. Unit Sell Disc. Line Sell
Summary Value