Error compiling template "Designs/Swift/Paragraph/CPQ_Card.cshtml"
Line 29: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.
Line 65: No overload for method 'DeleteCarditemInQuote' takes 2 arguments
Line 83: 'CPQCard' does not contain a definition for 'DeleteDynamicwebQuoteCardState'
Line 89: 'CPQCard' does not contain a definition for 'CreateSalesQuoteFromCardsWithoutAssemblyBom'
Line 97: 'CPQCard' does not contain a definition for 'UpdateExistingQuoteFromCard'
Line 108: 'IResponse.Redirect(string)' is obsolete: 'Do not use'
Line 113: 'CPQCard' does not contain a definition for 'LoadQuoteHeaderInfo'
Line 140: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.
Line 753: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.
Line 831: 'BOMInfo' does not contain a definition for 'BCStatus' and no accessible extension method 'BCStatus' accepting a first argument of type 'BOMInfo' could be found (are you missing a using directive or an assembly reference?)
Line 831: 'BOMInfo' does not contain a definition for 'BCStatus' and no accessible extension method 'BCStatus' accepting a first argument of type 'BOMInfo' could be found (are you missing a using directive or an assembly reference?)

1 // <auto-generated/> 2 #pragma warning disable 1591 3 namespace CompiledRazorTemplates.Dynamic 4 { 5 #line hidden 6 using System.Threading.Tasks; 7 using System.Collections.Generic; 8 using Dynamicweb.Ecommerce.ProductCatalog; 9 using System; 10 using System.Linq; 11 using System.Text.Json; 12 using DW_CPQ_API; 13 using DW_CPQ_API.Classes; 14 using DW_CPQ_API.Helpers; 15 internal class RazorEngine_bf1a800eb6e04c538dc610425bb408f2 : Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 16 { 17 #pragma warning disable 1998 18 public async override global::System.Threading.Tasks.Task ExecuteAsync() 19 { 20 WriteLiteral("\r\n"); 21 22 ModelController modelController = new ModelController(Model.PageID, Dynamicweb.Context.Current.Request.Params); // expected sales quote no 23 24 if(modelController!=null && string.IsNullOrEmpty( modelController.SalesQuoteNo)) 25 { 26 modelController.SalesQuoteNo="0000"; // to be removed later 27 } 28 29 System.Collections.Specialized.NameValueCollection? requestVars = Dynamicweb.Context.Current.Request.Params; 30 if(requestVars!=null && requestVars["quote"]!=null) 31 { 32 modelController.SalesQuoteNo=requestVars["quote"]!; 33 } 34 35 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? $"theme {Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower()}" : "alert-dark"; 36 37 var cpqPage = Dynamicweb.Content.Services.Pages.GetPage(Model.PageID); 38 string cpqTheme = cpqPage.Item["CPQ_Theme"]?.ToString() ?? "cpq-bold"; 39 40 string cardModelName = Pageview.Page.Item["CPQ_ModelVersionId"]?.ToString() ?? ""; 41 string pageUserId = (Pageview.User?.ID ?? 0).ToString(); 42 DW_CPQ_API.CPQCard card= new DW_CPQ_API.CPQCard(cardModelName); 43 string debgug = Dynamicweb.Context.Current.Request.QueryString["debugmode"] ?? ""; 44 string result=""; 45 if(requestVars!=null && requestVars["cardaction"]!=null && Dynamicweb.Context.Current.Request.HttpMethod == "POST") 46 { 47 if( requestVars["cardaction"].ToString()=="addcardtoquote") 48 { 49 50 string templateId=requestVars["templateId"]; 51 52 card.AddCardTempletetoQuote(modelController.SalesQuoteNo,templateId); 53 54 } 55 else if( requestVars["cardaction"].ToString()=="deletecarditem") 56 { 57 string itemdatakeyline=requestVars["itemdatakeyline"]; 58 string quoteNoForDelete = requestVars["salesQuoteNo"]?.ToString() ?? modelController.SalesQuoteNo; 59 60 if (string.IsNullOrWhiteSpace(requestVars["quote"])) 61 { 62 quoteNoForDelete = "0000"; 63 } 64 65 result = CPQCard.DeleteCarditemInQuote(itemdatakeyline, quoteNoForDelete); 66 if (!string.IsNullOrWhiteSpace(result)) 67 { 68 Dynamicweb.Context.Current.Session["redirectdata"] = result; 69 } 70 71 } 72 else if( requestVars["cardaction"].ToString()=="duplicatecarditem") 73 { 74 string itemdatakeyline=requestVars["itemdatakeyline"]; 75 CPQCard.DuplicateCarditemInQuote(itemdatakeyline); 76 77 } 78 else if (requestVars["cardaction"].ToString() == "clearCardItemsOnRefresh") 79 { 80 string refreshQuoteNo = requestVars["salesQuoteNo"]?.ToString() ?? modelController.SalesQuoteNo; 81 if (!string.IsNullOrWhiteSpace(refreshQuoteNo) && refreshQuoteNo == "0000") 82 { 83 CPQCard.DeleteDynamicwebQuoteCardState(refreshQuoteNo); 84 } 85 } 86 else if( requestVars["cardaction"].ToString()=="createQuote") 87 { 88 // result=CPQCard.CreateSalesQuoteFromCards(cardModelName,modelController.SalesQuoteNo); 89 result=CPQCard.CreateSalesQuoteFromCardsWithoutAssemblyBom(cardModelName,modelController.SalesQuoteNo); 90 91 Dynamicweb.Context.Current.Session["redirectdata"] = result; 92 Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] = "true"; 93 94 } 95 else if (requestVars["cardaction"].ToString() == "saveEditedQuote") 96 { 97 result = CPQCard.UpdateExistingQuoteFromCard(cardModelName, requestVars["salesQuoteNo"]?.ToString() ?? ""); 98 Dynamicweb.Context.Current.Session["redirectdata"] = result; 99 } 100 else if (requestVars["cardaction"].ToString() == "createQuoteExample") 101 { 102 result = CPQCard.CreateExampleQuote(cardModelName, requestVars["pageuserid"]?.ToString() ?? "0", requestVars["salesQuoteNo"]?.ToString() ?? ""); 103 Dynamicweb.Context.Current.Session["redirectdata"] = result; 104 Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] = "true"; 105 106 } 107 108 Dynamicweb.Context.Current.Response.Redirect(Dynamicweb.Context.Current.Request.Url.AbsoluteUri); // to prevent resubmission when refreshing 109 return; 110 111 } 112 Dictionary<string,object> carditems =CPQCard.LoadCardItemsByQuote(cardModelName,modelController.SalesQuoteNo); 113 Dictionary<string, object> quoteHeader = CPQCard.LoadQuoteHeaderInfo(cardModelName, modelController.SalesQuoteNo); 114 115 string quoteHeaderSource = quoteHeader.ContainsKey("source") ? quoteHeader["source"]?.ToString() ?? "" : ""; 116 string quoteNoDisplay = quoteHeader.ContainsKey("sales_quote_no") ? quoteHeader["sales_quote_no"]?.ToString() ?? modelController.SalesQuoteNo : modelController.SalesQuoteNo; 117 string quoteRevisionDisplay = quoteHeader.ContainsKey("quote_revision_no") ? quoteHeader["quote_revision_no"]?.ToString() ?? "0" : "0"; 118 string customerName = quoteHeader.ContainsKey("customer_name") ? quoteHeader["customer_name"]?.ToString() ?? "" : ""; 119 string customerNumber = quoteHeader.ContainsKey("customer_number") ? quoteHeader["customer_number"]?.ToString() ?? "" : ""; 120 string customerContact = quoteHeader.ContainsKey("contact") ? quoteHeader["contact"]?.ToString() ?? "" : ""; 121 string customerEmail = quoteHeader.ContainsKey("email") ? quoteHeader["email"]?.ToString() ?? "" : ""; 122 string customerPhone = quoteHeader.ContainsKey("phone") ? quoteHeader["phone"]?.ToString() ?? "" : ""; 123 string address = quoteHeader.ContainsKey("address") ? quoteHeader["address"]?.ToString() ?? "" : ""; 124 string address2 = quoteHeader.ContainsKey("address_2") ? quoteHeader["address_2"]?.ToString() ?? "" : ""; 125 string city = quoteHeader.ContainsKey("city") ? quoteHeader["city"]?.ToString() ?? "" : ""; 126 string postCode = quoteHeader.ContainsKey("post_code") ? quoteHeader["post_code"]?.ToString() ?? "" : ""; 127 string country = quoteHeader.ContainsKey("country") ? quoteHeader["country"]?.ToString() ?? "" : ""; 128 string quoteStatus = quoteHeader.ContainsKey("status") ? quoteHeader["status"]?.ToString() ?? "" : ""; 129 string quoteOrderDate = quoteHeader.ContainsKey("order_date") ? quoteHeader["order_date"]?.ToString() ?? "" : ""; 130 string quoteDueDate = quoteHeader.ContainsKey("due_date") ? quoteHeader["due_date"]?.ToString() ?? "" : ""; 131 132 var targetPage = Dynamicweb.Content.Services.Pages 133 .GetPages() 134 .FirstOrDefault(p => 135 (p.NavigationTag?.Contains("cpqcustom") ?? false) && 136 (p.Item["CPQ_ModelVersionId"]?.ToString() ?? "") == cardModelName 137 ); 138 139 string editUrl = targetPage != null ? $"/Default.aspx?ID={targetPage.ID}" : "#"; 140 string? myData = Dynamicweb.Context.Current.Session["redirectdata"] as string; 141 string createQuoteErrorNote = ""; 142 string[] createQuoteErrorLines = Array.Empty<string>(); 143 string deleteCardItemNote = ""; 144 string[] deleteCardItemNoteLines = Array.Empty<string>(); 145 146 const string odataErrorMarker = "[ODATA_ERROR_NOTE]"; 147 const string deleteCardItemNoteMarker = "[DELETE_CARDITEM_NOTE]"; 148 if (!string.IsNullOrWhiteSpace(myData)) 149 { 150 int markerIndex = myData.IndexOf(odataErrorMarker, StringComparison.Ordinal); 151 if (markerIndex >= 0) 152 { 153 int noteStart = markerIndex + odataErrorMarker.Length; 154 createQuoteErrorNote = myData.Substring(noteStart).Trim(); 155 myData = myData.Substring(0, markerIndex).Trim(); 156 createQuoteErrorLines = createQuoteErrorNote 157 .Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries) 158 .Select(line => line.Trim()) 159 .Where(line => !string.IsNullOrWhiteSpace(line)) 160 .ToArray(); 161 } 162 163 int deleteMarkerIndex = myData.IndexOf(deleteCardItemNoteMarker, StringComparison.Ordinal); 164 if (deleteMarkerIndex >= 0) 165 { 166 int noteStart = deleteMarkerIndex + deleteCardItemNoteMarker.Length; 167 deleteCardItemNote = myData.Substring(noteStart).Trim(); 168 myData = myData.Substring(0, deleteMarkerIndex).Trim(); 169 deleteCardItemNoteLines = deleteCardItemNote 170 .Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries) 171 .Select(line => line.Trim()) 172 .Where(line => !string.IsNullOrWhiteSpace(line)) 173 .ToArray(); 174 } 175 } 176 177 myData = myData != null ? myData.Replace("\"", "\\\"") : ""; // Escape double quotes for JavaScript 178 string refreshAfterQuoteCreate = (Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] as string) ?? ""; 179 Dynamicweb.Context.Current.Session.Remove("redirectdata"); 180 Dynamicweb.Context.Current.Session.Remove("refreshAfterQuoteCreate"); 181 WriteLiteral("<script>\r\n window.editUrl = \""); 182 Write(editUrl); 183 WriteLiteral(@"""; 184 185 function addcardtolist(templateId) { 186 187 FormaddItem.templateId.value = templateId; 188 FormaddItem.submit(); 189 } 190 function editcarditem(keyline,pageid) { 191 Formedititem.itemdatakeyline.value = keyline; 192 Formedititem.action= ""/Default.aspx?ID=""+pageid+""&quote=""+encodeURIComponent(Formedititem.salesQuoteNo.value || """"); 193 let dgb = document.getElementById(""debugmod"").value; 194 if(dgb === ""true"") { 195 Formedititem.action= ""/Default.aspx?ID=""+pageid+""&quote=""+encodeURIComponent(Formedititem.salesQuoteNo.value || """")+""&debugmode=true""; 196 } 197 Formedititem.submit(); 198 } 199 function deleteitem(keyline) { 200 FormdelItem.itemdatakeyline.value = keyline; 201 FormdelItem.submit(); 202 } 203 204 function duplicateitem(keyline) { 205 FormduplicateItem.itemdatakeyline.value = keyline; 206 FormduplicateItem.submit(); 207 } 208 209 function toggleBom(itemId) { 210 var panel = document.getElementById(""bom-panel-"" + itemId); 211 if (!panel) { 212 "); 213 WriteLiteral(@" return; 214 } 215 216 var isOpen = panel.classList.contains(""open""); 217 var allPanels = document.querySelectorAll("".bom-panel""); 218 allPanels.forEach(function (node) { 219 node.classList.remove(""open""); 220 }); 221 222 if (!isOpen) { 223 panel.classList.add(""open""); 224 } 225 } 226 227 function createSalesQuote() { 228 FormCreateQuote.submit(); 229 } 230 231 function saveEditedQuote() { 232 FormSaveEditedQuote.submit(); 233 } 234 235 function closeCpqCard() { 236 window.location.href = ""/my-account/my-quotes""; 237 } 238 239 function createQuote() { 240 "); 241 WriteLiteral(@" FormCreateQuoteExample.submit(); 242 } 243 244 function isCreateSalesQuoteSuccess(rawData) { 245 if (!rawData) { 246 return false; 247 } 248 249 try { 250 var parsed = JSON.parse(rawData || """"); 251 if (parsed && parsed.quoteId) { 252 return true; 253 } 254 } catch (error) { 255 } 256 257 return (rawData || """").indexOf(""quoteId"") !== -1; 258 } 259 260 document.addEventListener(""DOMContentLoaded"", function () { 261 var clearForm = document.getElementById(""FormClearOnRefresh""); 262 var navEntries = performance.getEntriesByType(""navigation""); 263 var isReload = navEntries && navEntries.length > 0 && navEntries[0].type === ""reload""; 264 var shouldRefreshAfterQuoteCreate = """); 265 Write(refreshAfterQuoteCreate); 266 WriteLiteral("\" === \"true\";\r\n var hasCreateQuoteError = "); 267 Write(createQuoteErrorLines.Length > 0 ? "true" : "false"); 268 WriteLiteral(";\r\n var refreshQuoteInput = clearForm ? clearForm.querySelector(\"input[name=\'salesQuoteNo\']\") : null;\r\n var refreshQuoteNo = refreshQuoteInput ? (refreshQuoteInput.value || \"\").trim() : \"\";\r\n var myData = \""); 269 Write(myData); 270 WriteLiteral(@"""; 271 var hasRedirectPayload = !!(myData && myData.trim()); 272 273 // Only clear on a plain manual reload of temporary quote state. 274 // Do not clear right after create/sync responses, so notes remain visible. 275 if (isReload && refreshQuoteNo === ""0000"" && !hasCreateQuoteError && !shouldRefreshAfterQuoteCreate && !hasRedirectPayload && clearForm) { 276 clearForm.submit(); 277 return; 278 } 279 280 if (myData && !hasCreateQuoteError && shouldRefreshAfterQuoteCreate) { 281 return; 282 } 283 }); 284 </script> 285 286 <style> 287 .cpq-bc-shell { 288 --bc-bg: #f4f6fb; 289 --bc-surface: #ffffff; 290 --bc-border: #dde3ed; 291 --bc-text: #1a2433; 292 --bc-muted: #5a6b85; 293 --bc-primary: #0066b8; 294 --bc-primary-strong: #004a8b; 295 --bc-danger: #c0392b; 296 --bc-shadow: 0 1px 2px rgba(21, 38, 62, 0.06), 0 6px 16px rgba(21, 38, 62, 0.06); 297 background: linear-gradient(180deg, #f8f9fc 0%, var(--bc"); 298 WriteLiteral(@"-bg) 100%); 299 color: var(--bc-text); 300 border-radius: 10px; 301 padding: 18px 16px 20px; 302 } 303 304 .cpq-bc-shell .bc-list { 305 background: var(--bc-surface); 306 border: 1px solid var(--bc-border); 307 border-radius: 8px; 308 box-shadow: var(--bc-shadow); 309 overflow: hidden; 310 } 311 312 .cpq-bc-shell .bc-section-title { 313 margin: 0; 314 padding: 10px 12px; 315 background: #eef3fb; 316 border-bottom: 1px solid var(--bc-border); 317 color: #22324a; 318 font-size: 13px; 319 font-weight: 600; 320 letter-spacing: 0.2px; 321 text-transform: uppercase; 322 } 323 324 .cpq-bc-shell .bc-row { 325 display: grid; 326 grid-template-columns: minmax(180px, 2fr) minmax(140px, 1.2fr) minmax(140px, 1.2fr) minmax(120px, 1fr) auto auto auto; 327 gap: 8px; 328 align-items: center; 329 padding: 8px 12px; 330 border-bottom: 1px solid #edf1f7; 331 font-size: 13px; 332 } 333 334 .cpq-bc-shell .bc-row:"); 335 WriteLiteral(@"last-child { 336 border-bottom: none; 337 } 338 339 .cpq-bc-shell .bc-row.header { 340 background: #f7f9fd; 341 font-weight: 600; 342 color: #273958; 343 font-size: 12px; 344 text-transform: uppercase; 345 letter-spacing: 0.2px; 346 } 347 348 .cpq-bc-shell .cell { 349 min-width: 0; 350 } 351 352 .cpq-bc-shell .cell.desc { 353 color: var(--bc-text); 354 overflow: hidden; 355 text-overflow: ellipsis; 356 white-space: nowrap; 357 } 358 359 .cpq-bc-shell .cell.meta { 360 color: var(--bc-muted); 361 } 362 363 .cpq-bc-shell .bc-empty { 364 padding: 22px 12px; 365 color: var(--bc-muted); 366 font-size: 13px; 367 background: #fcfdff; 368 } 369 370 .cpq-bc-shell .action-bar { 371 display: flex; 372 flex-wrap: wrap; 373 gap: 8px; 374 margin-bottom: 12px; 375 } 376 377 .cpq-bc-shell .action { 378 display: inline-flex; 379 align-items: center; 380 gap: 8px; 381 background: #ffffff; 382 border:"); 383 WriteLiteral(@" 1px solid #cfd8e6; 384 color: #1f314c; 385 border-radius: 6px; 386 padding: 7px 10px; 387 cursor: pointer; 388 transition: background-color 120ms ease, border-color 120ms ease; 389 } 390 391 .cpq-bc-shell .action:hover { 392 background: #f2f7ff; 393 border-color: #9fbce0; 394 } 395 396 .cpq-bc-shell .action .label { 397 font-size: 13px; 398 font-weight: 600; 399 } 400 401 .cpq-bc-shell .bc-action-btn { 402 border: 1px solid #c9d5e6; 403 border-radius: 4px; 404 background: #fff; 405 color: #22344f; 406 font-size: 12px; 407 font-weight: 600; 408 padding: 4px 8px; 409 cursor: pointer; 410 } 411 412 .cpq-bc-shell .bc-action-btn:hover { 413 background: #f2f7ff; 414 border-color: #9fbce0; 415 } 416 417 .cpq-bc-shell .bc-action-btn.delete { 418 color: var(--bc-danger); 419 border-color: #e6c8c4; 420 background: #fffafa; 421 } 422 423 .cpq-bc-shell .bc-footer-actions { 424 display: flex; 425 flex-w"); 426 WriteLiteral(@"rap: wrap; 427 justify-content: flex-end; 428 gap: 8px; 429 margin-top: 12px; 430 } 431 432 .cpq-bc-shell .bc-error-note { 433 margin: 10px 12px 12px; 434 padding: 10px 12px; 435 border-radius: 6px; 436 border: 1px solid #e6b8b2; 437 background: #fff5f4; 438 color: #7f1d1d; 439 font-size: 12px; 440 line-height: 1.45; 441 } 442 443 .cpq-bc-shell .bc-error-note strong { 444 display: block; 445 margin-bottom: 4px; 446 font-size: 12px; 447 text-transform: uppercase; 448 letter-spacing: 0.2px; 449 } 450 451 .cpq-bc-shell .bc-status-note { 452 margin: 10px 12px 12px; 453 padding: 10px 12px; 454 border-radius: 6px; 455 border: 1px solid #bfd3ea; 456 background: #f4f8fd; 457 color: #1f4268; 458 font-size: 12px; 459 line-height: 1.45; 460 } 461 462 .cpq-bc-shell .bc-status-note strong { 463 display: block; 464 margin-bottom: 4px; 465 font-size: 12px; 466 text-transform: uppercase;"); 467 WriteLiteral(@" 468 letter-spacing: 0.2px; 469 } 470 471 .cpq-bc-shell .bom-panel { 472 width: 100%; 473 border: 1px solid #dbe4f2; 474 border-radius: 6px; 475 background: #fbfdff; 476 margin: 2px 0 8px; 477 display: none; 478 } 479 480 .cpq-bc-shell .bom-panel.open { 481 display: block; 482 } 483 484 .cpq-bc-shell .bom-list { 485 border-top: 1px solid #e8eef8; 486 padding: 8px 10px 10px; 487 } 488 489 .cpq-bc-shell .bom-title { 490 font-size: 12px; 491 font-weight: 600; 492 color: #29405f; 493 padding: 8px 10px 0; 494 } 495 496 .cpq-bc-shell .bom-line { 497 display: grid; 498 grid-template-columns: minmax(110px, 0.9fr) minmax(180px, 1.6fr) minmax(80px, 0.7fr) minmax(110px, 0.9fr) minmax(110px, 0.9fr) minmax(120px, 1fr) minmax(120px, 1fr); 499 gap: 8px; 500 font-size: 12px; 501 color: #304763; 502 padding: 4px 0; 503 border-bottom: 1px dashed #eaf0f8; 504 } 505 506 .cpq-bc-shell .bom-line:last-child { 507 border-bot"); 508 WriteLiteral(@"tom: none; 509 } 510 511 .cpq-bc-shell .bom-line.header { 512 text-transform: uppercase; 513 font-weight: 600; 514 color: #4f6684; 515 font-size: 11px; 516 } 517 518 .cpq-bc-shell .bom-total { 519 margin-top: 8px; 520 font-size: 12px; 521 font-weight: 700; 522 color: #1d3552; 523 text-align: right; 524 } 525 526 .cpq-bc-shell .bc-primary-btn, 527 .cpq-bc-shell .bc-secondary-btn { 528 border-radius: 5px; 529 padding: 7px 12px; 530 font-size: 13px; 531 font-weight: 600; 532 border: 1px solid transparent; 533 cursor: pointer; 534 } 535 536 .cpq-bc-shell .bc-primary-btn { 537 background: var(--bc-primary); 538 color: #fff; 539 border-color: var(--bc-primary); 540 } 541 542 .cpq-bc-shell .bc-primary-btn:hover { 543 background: var(--bc-primary-strong); 544 border-color: var(--bc-primary-strong); 545 } 546 547 .cpq-bc-shell .bc-secondary-btn { 548 background: #ffffff; 549 color: #22344f; 550 border-co"); 551 WriteLiteral("lor: #c9d5e6;\r\n }\r\n\r\n .cpq-bc-shell .bc-secondary-btn:hover {\r\n background: #f2f7ff;\r\n border-color: #9fbce0;\r\n }\r\n\r\n "); 552 WriteLiteral("@media (max-width: 991px) {\r\n .cpq-bc-shell .bc-row {\r\n grid-template-columns: 1fr 1fr;\r\n gap: 6px 10px;\r\n }\r\n\r\n .cpq-bc-shell .bc-row .code {\r\n justify-self: start;\r\n }\r\n }\r\n\r\n "); 553 WriteLiteral(@"@media (max-width: 640px) { 554 .cpq-bc-shell { 555 padding: 12px 10px 14px; 556 } 557 558 .cpq-bc-shell .bc-row { 559 grid-template-columns: 1fr; 560 } 561 562 .cpq-bc-shell .cell.desc { 563 white-space: normal; 564 } 565 566 .cpq-bc-shell .bom-line { 567 grid-template-columns: 1fr; 568 gap: 4px; 569 } 570 } 571 </style> 572 573 "); 574 WriteLiteral("\r\n <input type=\"hidden\" id=\"debugmod\""); 575 BeginWriteAttribute("value", " value=\"", 20573, "\"", 20588, 1); 576 WriteAttributeValue("", 20581, debgug, 20581, 7, false); 577 EndWriteAttribute(); 578 WriteLiteral(" />\r\n\r\n<form name=\"FormaddItem\" id=\"FormaddItem\" method=\"post\""); 579 BeginWriteAttribute("action", " action=\"", 20651, "\"", 20660, 0); 580 EndWriteAttribute(); 581 WriteLiteral(">\r\n <input type=\"hidden\" name=\"modelversionid\" id=\"modelversionid\""); 582 BeginWriteAttribute("value", " value=\"", 20730, "\"", 20754, 1); 583 WriteAttributeValue("", 20738, cardModelName, 20738, 16, false); 584 EndWriteAttribute(); 585 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"addcardtoquote\" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\" id=\"salesQuoteNo\""); 586 BeginWriteAttribute("value", " value=\"", 20909, "\"", 20948, 1); 587 WriteAttributeValue("", 20917, modelController.SalesQuoteNo, 20917, 31, false); 588 EndWriteAttribute(); 589 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"templateId\" id=\"templateId\""); 590 BeginWriteAttribute("value", " value=\"", 21012, "\"", 21020, 0); 591 EndWriteAttribute(); 592 WriteLiteral(" />\r\n</form>\r\n<form name=\"FormduplicateItem\" id=\"FormduplicateItem\" method=\"post\""); 593 BeginWriteAttribute("action", " action=\"", 21102, "\"", 21111, 0); 594 EndWriteAttribute(); 595 WriteLiteral(">\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"duplicatecarditem\" />\r\n <input type=\"hidden\" name=\"itemdatakeyline\" id=\"itemdatakeyline\""); 596 BeginWriteAttribute("value", " value=\"", 21274, "\"", 21282, 0); 597 EndWriteAttribute(); 598 WriteLiteral(" />\r\n</form>\r\n<form name=\"FormdelItem\" id=\"FormdelItem\" method=\"post\""); 599 BeginWriteAttribute("action", " action=\"", 21352, "\"", 21361, 0); 600 EndWriteAttribute(); 601 WriteLiteral(">\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"deletecarditem\" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\" id=\"salesQuoteNo\""); 602 BeginWriteAttribute("value", " value=\"", 21514, "\"", 21553, 1); 603 WriteAttributeValue("", 21522, modelController.SalesQuoteNo, 21522, 31, false); 604 EndWriteAttribute(); 605 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"itemdatakeyline\" id=\"itemdatakeyline\""); 606 BeginWriteAttribute("value", " value=\"", 21628, "\"", 21636, 0); 607 EndWriteAttribute(); 608 WriteLiteral(" />\r\n</form>\r\n<form name=\"Formedititem\" id=\"Formedititem\" method=\"post\""); 609 BeginWriteAttribute("action", " action=\"", 21708, "\"", 21717, 0); 610 EndWriteAttribute(); 611 WriteLiteral(">\r\n <input type=\"hidden\" name=\"templatemodelversionid\" id=\"modelversionid\""); 612 BeginWriteAttribute("value", " value=\"", 21795, "\"", 21819, 1); 613 WriteAttributeValue("", 21803, cardModelName, 21803, 16, false); 614 EndWriteAttribute(); 615 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"pageid\" id=\"pageid\""); 616 BeginWriteAttribute("value", " value=\"", 21876, "\"", 21884, 0); 617 EndWriteAttribute(); 618 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"editcarditem\" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\" id=\"salesQuoteNo\""); 619 BeginWriteAttribute("value", " value=\"", 22036, "\"", 22075, 1); 620 WriteAttributeValue("", 22044, modelController.SalesQuoteNo, 22044, 31, false); 621 EndWriteAttribute(); 622 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"itemdatakeyline\" id=\"itemdatakeyline\""); 623 BeginWriteAttribute("value", " value=\"", 22149, "\"", 22157, 0); 624 EndWriteAttribute(); 625 WriteLiteral(" />\r\n</form>\r\n<form name=\"FormCreateQuote\" id=\"FormCreateQuote\" method=\"post\""); 626 BeginWriteAttribute("action", " action=\"", 22235, "\"", 22244, 0); 627 EndWriteAttribute(); 628 WriteLiteral(">\r\n <input type=\"hidden\" name=\"modelversionid\" id=\"modelversionid\""); 629 BeginWriteAttribute("value", " value=\"", 22314, "\"", 22338, 1); 630 WriteAttributeValue("", 22322, cardModelName, 22322, 16, false); 631 EndWriteAttribute(); 632 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"createQuote\" />\r\n <input type=\"hidden\" name=\"quote\" id=\"quote\""); 633 BeginWriteAttribute("value", " value=\"", 22475, "\"", 22514, 1); 634 WriteAttributeValue("", 22483, modelController.SalesQuoteNo, 22483, 31, false); 635 EndWriteAttribute(); 636 WriteLiteral(" />\r\n \r\n</form>\r\n<form name=\"FormCreateQuoteExample\" id=\"FormCreateQuoteExample\" method=\"post\""); 637 BeginWriteAttribute("action", " action=\"", 22611, "\"", 22620, 0); 638 EndWriteAttribute(); 639 WriteLiteral(">\r\n <input type=\"hidden\" name=\"modelversionid\" id=\"modelversionid\""); 640 BeginWriteAttribute("value", " value=\"", 22690, "\"", 22714, 1); 641 WriteAttributeValue("", 22698, cardModelName, 22698, 16, false); 642 EndWriteAttribute(); 643 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"createQuoteExample\" />\r\n <input type=\"hidden\" name=\"pageuserid\" id=\"pageuserid\""); 644 BeginWriteAttribute("value", " value=\"", 22868, "\"", 22889, 1); 645 WriteAttributeValue("", 22876, pageUserId, 22876, 13, false); 646 EndWriteAttribute(); 647 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\" id=\"salesQuoteNo\""); 648 BeginWriteAttribute("value", " value=\"", 22957, "\"", 22996, 1); 649 WriteAttributeValue("", 22965, modelController.SalesQuoteNo, 22965, 31, false); 650 EndWriteAttribute(); 651 WriteLiteral(" />\r\n</form>\r\n<form name=\"FormSaveEditedQuote\" id=\"FormSaveEditedQuote\" method=\"post\""); 652 BeginWriteAttribute("action", " action=\"", 23082, "\"", 23091, 0); 653 EndWriteAttribute(); 654 WriteLiteral(">\r\n <input type=\"hidden\" name=\"modelversionid\" id=\"modelversionid\""); 655 BeginWriteAttribute("value", " value=\"", 23161, "\"", 23185, 1); 656 WriteAttributeValue("", 23169, cardModelName, 23169, 16, false); 657 EndWriteAttribute(); 658 WriteLiteral(" />\r\n <input type=\"hidden\" name=\"cardaction\" id=\"cardaction\" value=\"saveEditedQuote\" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\" id=\"salesQuoteNo\""); 659 BeginWriteAttribute("value", " value=\"", 23340, "\"", 23379, 1); 660 WriteAttributeValue("", 23348, modelController.SalesQuoteNo, 23348, 31, false); 661 EndWriteAttribute(); 662 WriteLiteral(" />\r\n</form>\r\n<form name=\"FormClearOnRefresh\" id=\"FormClearOnRefresh\" method=\"post\""); 663 BeginWriteAttribute("action", " action=\"", 23463, "\"", 23472, 0); 664 EndWriteAttribute(); 665 WriteLiteral(">\r\n <input type=\"hidden\" name=\"cardaction\" value=\"clearCardItemsOnRefresh\" />\r\n <input type=\"hidden\" name=\"salesQuoteNo\""); 666 BeginWriteAttribute("value", " value=\"", 23599, "\"", 23638, 1); 667 WriteAttributeValue("", 23607, modelController.SalesQuoteNo, 23607, 31, false); 668 EndWriteAttribute(); 669 WriteLiteral(" />\r\n</form>\r\n<div class=\"container mt-3 cpq-bc-shell\">\r\n <div class=\"bc-list mb-3\">\r\n <h3 class=\"bc-section-title\">Quote Header</h3>\r\n <div class=\"bc-row\">\r\n <span class=\"cell desc\"><strong>Sales Quote</strong>: "); 670 Write(quoteNoDisplay); 671 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Revision</strong>: "); 672 Write(quoteRevisionDisplay); 673 WriteLiteral("</span>\r\n <span class=\"cell desc meta\"><strong>Source</strong>: "); 674 Write(string.IsNullOrWhiteSpace(quoteHeaderSource) ? "N/A" : quoteHeaderSource); 675 WriteLiteral("</span>\r\n </div>\r\n <div class=\"bc-row\">\r\n <span class=\"cell desc\"><strong>Customer</strong>: "); 676 Write(string.IsNullOrWhiteSpace(customerName) ? "N/A" : customerName); 677 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Customer No</strong>: "); 678 Write(string.IsNullOrWhiteSpace(customerNumber) ? "N/A" : customerNumber); 679 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Status</strong>: "); 680 Write(string.IsNullOrWhiteSpace(quoteStatus) ? "N/A" : quoteStatus); 681 WriteLiteral("</span>\r\n </div>\r\n <div class=\"bc-row\">\r\n <span class=\"cell desc\"><strong>Address</strong>: "); 682 Write(string.IsNullOrWhiteSpace(address) ? "N/A" : address); 683 WriteLiteral("</span>\r\n <span class=\"cell desc\">"); 684 Write(string.IsNullOrWhiteSpace(address2) ? "" : address2); 685 WriteLiteral("</span>\r\n <span class=\"cell desc\">"); 686 Write(string.IsNullOrWhiteSpace(city) && string.IsNullOrWhiteSpace(postCode) && string.IsNullOrWhiteSpace(country) ? "" : $"{city} {postCode} {country}".Trim()); 687 WriteLiteral("</span>\r\n </div>\r\n <div class=\"bc-row\">\r\n <span class=\"cell desc\"><strong>Contact</strong>: "); 688 Write(string.IsNullOrWhiteSpace(customerContact) ? "N/A" : customerContact); 689 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Email</strong>: "); 690 Write(string.IsNullOrWhiteSpace(customerEmail) ? "N/A" : customerEmail); 691 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Phone</strong>: "); 692 Write(string.IsNullOrWhiteSpace(customerPhone) ? "N/A" : customerPhone); 693 WriteLiteral("</span>\r\n </div>\r\n <div class=\"bc-row\">\r\n <span class=\"cell desc\"><strong>Order Date</strong>: "); 694 Write(string.IsNullOrWhiteSpace(quoteOrderDate) ? "N/A" : quoteOrderDate); 695 WriteLiteral("</span>\r\n <span class=\"cell desc\"><strong>Due Date</strong>: "); 696 Write(string.IsNullOrWhiteSpace(quoteDueDate) ? "N/A" : quoteDueDate); 697 WriteLiteral("</span>\r\n <span class=\"cell desc\"></span>\r\n </div>\r\n </div>\r\n\r\n"); 698 if( !string.IsNullOrEmpty(modelController.SalesQuoteNo) ) 699 { 700 WriteLiteral(" <div class=\"action-bar\">\r\n"); 701 foreach(var item in card.Cards) 702 { 703 WriteLiteral(" <button class=\"action\""); 704 BeginWriteAttribute("onclick", " onclick=\"", 26144, "\"", 26189, 3); 705 WriteAttributeValue("", 26154, "addcardtolist(\'", 26154, 15, true); 706 WriteAttributeValue("", 26169, item.TemplateId, 26169, 18, false); 707 WriteAttributeValue("", 26187, "\')", 26187, 2, true); 708 EndWriteAttribute(); 709 WriteLiteral(">\r\n <span class=\"icon\">\r\n"); 710 if(item.Image != null && item.Image != ""){ 711 WriteLiteral(" <img"); 712 BeginWriteAttribute("src", " src=\"", 26336, "\"", 26353, 1); 713 WriteAttributeValue("", 26342, item.Image, 26342, 11, false); 714 EndWriteAttribute(); 715 WriteLiteral(" width=\"50px\" />\r\n"); 716 } 717 WriteLiteral(" </span>\r\n <span class=\"label\">+ "); 718 Write(item.Name); 719 WriteLiteral("</span>\r\n </button>\r\n"); 720 } 721 WriteLiteral(" </div>\r\n"); 722 } 723 WriteLiteral(@" 724 <div class=""bc-list mb-3""> 725 <h3 class=""bc-section-title"">Card Items</h3> 726 <div class=""bc-row header""> 727 <span class=""cell desc"">Description</span> 728 <span class=""cell desc"">BC Item No</span> 729 <span class=""cell desc"">Total BOM Price</span> 730 <span class=""cell desc"">BOM</span> 731 <span class=""cell code"">Edit</span> 732 <span class=""cell code"">Copy</span> 733 <span class=""cell code"">Delete</span> 734 </div> 735 "); 736 if (carditems == null || !carditems.Any()) 737 { 738 WriteLiteral(" <div class=\"bc-empty list-group-item text-center text-muted no-item\">No Item</div>\r\n"); 739 } 740 else 741 { 742 foreach (var key in carditems.Keys.ToList()) 743 { 744 Dictionary<string,object> citem = (Dictionary<string,object>)carditems[key]; 745 string cpageid= citem.ContainsKey("pageid") ? citem["pageid"].ToString()! : ""; 746 string description= citem.ContainsKey("itemlabel") ? citem["itemlabel"].ToString()! : ""; 747 string parentItemNo = citem.ContainsKey("ItemNo") 748 ? citem["ItemNo"]?.ToString() ?? "" 749 : (citem.ContainsKey("itemno") 750 ? citem["itemno"]?.ToString() ?? "" 751 : (citem.ContainsKey("item_no") ? citem["item_no"]?.ToString() ?? "" : "")); 752 string cardItemPayload = JsonSerializer.Serialize(citem, JsonHelper.JsonOptions); 753 CardItem? cardItemTyped = JsonSerializer.Deserialize<CardItem>(cardItemPayload, JsonHelper.JsonOptions) 754 ?? JsonSerializer.Deserialize<CardItem>(cardItemPayload); 755 List<BOMInfo> bomLines = cardItemTyped?.bomlines ?? new List<BOMInfo>(); 756 decimal totalBomPrice = cardItemTyped?.bomtotal?.TotalSell ?? bomLines.Sum(line => line?.LineSell ?? 0m); 757 WriteLiteral(" <div class=\"bc-row\" style=\"cursor: pointer;\""); 758 BeginWriteAttribute("onclick", " onclick=\"", 28543, "\"", 28572, 3); 759 WriteAttributeValue("", 28553, "toggleBom(\'", 28553, 11, true); 760 WriteAttributeValue("", 28564, key, 28564, 6, false); 761 WriteAttributeValue("", 28570, "\')", 28570, 2, true); 762 EndWriteAttribute(); 763 WriteLiteral(">\r\n <span class=\"cell desc\">"); 764 Write(description); 765 WriteLiteral("</span>\r\n <span class=\"cell desc\">"); 766 Write(string.IsNullOrWhiteSpace(parentItemNo) ? "-" : parentItemNo); 767 WriteLiteral("</span>\r\n <span class=\"cell desc\">"); 768 Write(totalBomPrice.ToString("N2")); 769 WriteLiteral("</span>\r\n <span class=\"cell desc\">"); 770 Write(bomLines.Count); 771 WriteLiteral(" line(s)</span>\r\n <span class=\"cell code\"><button type=\"button\" class=\"bc-action-btn\""); 772 BeginWriteAttribute("onclick", " onclick=\"", 29002, "\"", 29071, 5); 773 WriteAttributeValue("", 29012, "event.stopPropagation();editcarditem(\'", 29012, 38, true); 774 WriteAttributeValue("", 29050, key, 29050, 6, false); 775 WriteAttributeValue("", 29056, "\',\'", 29056, 3, true); 776 WriteAttributeValue("", 29059, cpageid, 29059, 10, false); 777 WriteAttributeValue("", 29069, "\')", 29069, 2, true); 778 EndWriteAttribute(); 779 WriteLiteral(">Edit</button></span>\r\n <span class=\"cell code\"><button type=\"button\" class=\"bc-action-btn\""); 780 BeginWriteAttribute("onclick", " onclick=\"", 29182, "\"", 29239, 3); 781 WriteAttributeValue("", 29192, "event.stopPropagation();duplicateitem(\'", 29192, 39, true); 782 WriteAttributeValue("", 29231, key, 29231, 6, false); 783 WriteAttributeValue("", 29237, "\')", 29237, 2, true); 784 EndWriteAttribute(); 785 WriteLiteral(">Copy</button></span>\r\n <span class=\"cell code\"><button type=\"button\" class=\"bc-action-btn delete\""); 786 BeginWriteAttribute("onclick", " onclick=\"", 29357, "\"", 29411, 3); 787 WriteAttributeValue("", 29367, "event.stopPropagation();deleteitem(\'", 29367, 36, true); 788 WriteAttributeValue("", 29403, key, 29403, 6, false); 789 WriteAttributeValue("", 29409, "\')", 29409, 2, true); 790 EndWriteAttribute(); 791 WriteLiteral(">Delete</button></span>\r\n </div>\r\n <div class=\"bom-panel\""); 792 BeginWriteAttribute("id", " id=\"", 29499, "\"", 29520, 2); 793 WriteAttributeValue("", 29504, "bom-panel-", 29504, 10, true); 794 WriteAttributeValue("", 29514, key, 29514, 6, false); 795 EndWriteAttribute(); 796 WriteLiteral(">\r\n \r\n <div class=\"bom-list\">\r\n"); 797 if (bomLines.Count == 0) 798 { 799 WriteLiteral(" <div class=\"cell desc\">No BOM lines available.</div>\r\n"); 800 } 801 else 802 { 803 WriteLiteral(@" <div class=""bom-line header""> 804 <span>Item No</span> 805 <span>Description</span> 806 <span>Qty</span> 807 <span>Unit Sell</span> 808 <span>Line Sell</span> 809 <span>BC Status</span> 810 </div> 811 "); 812 foreach (var line in bomLines) 813 { 814 decimal unitSell = line?.UnitSell ?? 0m; 815 decimal lineSell = line?.LineSell ?? 0m; 816 decimal qty = line?.Qty ?? 0m; 817 string lineDescription = !string.IsNullOrWhiteSpace(line?.Description) 818 ? line.Description! 819 : (line?.LabelName ?? ""); 820 WriteLiteral(" <div class=\"bom-line\">\r\n <span>"); 821 Write(line?.ItemNo ?? ""); 822 WriteLiteral("</span>\r\n <span>"); 823 Write(lineDescription); 824 WriteLiteral("</span>\r\n <span>"); 825 Write(qty.ToString("N2")); 826 WriteLiteral("</span>\r\n <span>"); 827 Write(unitSell.ToString("N2")); 828 WriteLiteral("</span>\r\n <span>"); 829 Write(lineSell.ToString("N2")); 830 WriteLiteral("</span>\r\n <span>"); 831 Write(string.IsNullOrWhiteSpace(line?.BCStatus) ? "-" : line?.BCStatus); 832 WriteLiteral("</span>\r\n </div>\r\n"); 833 } 834 } 835 WriteLiteral(" <div class=\"bom-total\">Total BOM Price: "); 836 Write(totalBomPrice.ToString("N2")); 837 WriteLiteral("</div>\r\n </div>\r\n </div>\r\n"); 838 } 839 } 840 if (!string.IsNullOrWhiteSpace(createQuoteErrorNote)) 841 { 842 WriteLiteral(" <div class=\"bc-error-note\">\r\n <strong>Create Sales Quote OData Errors</strong>\r\n"); 843 foreach (var errorLine in createQuoteErrorLines) 844 { 845 WriteLiteral(" <div>"); 846 Write(errorLine); 847 WriteLiteral("</div>\r\n"); 848 } 849 WriteLiteral(" </div>\r\n"); 850 } 851 if (!string.IsNullOrWhiteSpace(deleteCardItemNote)) 852 { 853 WriteLiteral(" <div class=\"bc-status-note\">\r\n <strong>Delete Card Item BC Cleanup</strong>\r\n"); 854 foreach (var statusLine in deleteCardItemNoteLines) 855 { 856 WriteLiteral(" <div>"); 857 Write(statusLine); 858 WriteLiteral("</div>\r\n"); 859 } 860 WriteLiteral(" </div>\r\n"); 861 } 862 WriteLiteral(" </div>\r\n\r\n <div class=\"ms-4 mt-8 text-end bc-footer-actions\">\r\n"); 863 if( !string.IsNullOrEmpty(modelController.SalesQuoteNo) && modelController.SalesQuoteNo.StartsWith("QUOTE", StringComparison.OrdinalIgnoreCase) ) 864 { 865 WriteLiteral(" <button type=\"button\" class=\"bc-primary-btn\" onclick=\"saveEditedQuote()\">Save edited CPQ Card</button>\r\n <button type=\"button\" class=\"bc-secondary-btn\" onclick=\"closeCpqCard()\">Close</button>\r\n"); 866 } 867 else if( !string.IsNullOrEmpty(modelController.SalesQuoteLineNo) ) 868 { 869 WriteLiteral(" <button type=\"button\" class=\"bc-secondary-btn\" onclick=\"closeCpqCard()\">Close</button>\r\n"); 870 } 871 else 872 { 873 WriteLiteral(@" <button type=""button"" class=""bc-primary-btn"" onclick=""createQuote()"">Create Quote</button> 874 <button type=""button"" class=""bc-primary-btn"" onclick=""createSalesQuote()"">Save to Quote</button> 875 <button type=""button"" class=""bc-secondary-btn"" onclick=""closeCpqCard()"">Close</button> 876 "); 877 } 878 WriteLiteral(" </div>\r\n</div>"); 879 } 880 #pragma warning restore 1998 881 } 882 } 883 #pragma warning restore 1591 884

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using System 4 @using System.Linq 5 @using System.Text.Json 6 @using DW_CPQ_API 7 @using DW_CPQ_API.Classes 8 @using DW_CPQ_API.Helpers 9 10 @{ 11 ModelController modelController = new ModelController(Model.PageID, Dynamicweb.Context.Current.Request.Params); // expected sales quote no 12 13 if(modelController!=null && string.IsNullOrEmpty( modelController.SalesQuoteNo)) 14 { 15 modelController.SalesQuoteNo="0000"; // to be removed later 16 } 17 18 System.Collections.Specialized.NameValueCollection? requestVars = Dynamicweb.Context.Current.Request.Params; 19 if(requestVars!=null && requestVars["quote"]!=null) 20 { 21 modelController.SalesQuoteNo=requestVars["quote"]!; 22 } 23 24 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? $"theme {Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower()}" : "alert-dark"; 25 26 var cpqPage = Dynamicweb.Content.Services.Pages.GetPage(Model.PageID); 27 string cpqTheme = cpqPage.Item["CPQ_Theme"]?.ToString() ?? "cpq-bold"; 28 29 string cardModelName = Pageview.Page.Item["CPQ_ModelVersionId"]?.ToString() ?? ""; 30 string pageUserId = (Pageview.User?.ID ?? 0).ToString(); 31 DW_CPQ_API.CPQCard card= new DW_CPQ_API.CPQCard(cardModelName); 32 string debgug = Dynamicweb.Context.Current.Request.QueryString["debugmode"] ?? ""; 33 string result=""; 34 if(requestVars!=null && requestVars["cardaction"]!=null && Dynamicweb.Context.Current.Request.HttpMethod == "POST") 35 { 36 if( requestVars["cardaction"].ToString()=="addcardtoquote") 37 { 38 39 string templateId=requestVars["templateId"]; 40 41 card.AddCardTempletetoQuote(modelController.SalesQuoteNo,templateId); 42 43 } 44 else if( requestVars["cardaction"].ToString()=="deletecarditem") 45 { 46 string itemdatakeyline=requestVars["itemdatakeyline"]; 47 string quoteNoForDelete = requestVars["salesQuoteNo"]?.ToString() ?? modelController.SalesQuoteNo; 48 49 if (string.IsNullOrWhiteSpace(requestVars["quote"])) 50 { 51 quoteNoForDelete = "0000"; 52 } 53 54 result = CPQCard.DeleteCarditemInQuote(itemdatakeyline, quoteNoForDelete); 55 if (!string.IsNullOrWhiteSpace(result)) 56 { 57 Dynamicweb.Context.Current.Session["redirectdata"] = result; 58 } 59 60 } 61 else if( requestVars["cardaction"].ToString()=="duplicatecarditem") 62 { 63 string itemdatakeyline=requestVars["itemdatakeyline"]; 64 CPQCard.DuplicateCarditemInQuote(itemdatakeyline); 65 66 } 67 else if (requestVars["cardaction"].ToString() == "clearCardItemsOnRefresh") 68 { 69 string refreshQuoteNo = requestVars["salesQuoteNo"]?.ToString() ?? modelController.SalesQuoteNo; 70 if (!string.IsNullOrWhiteSpace(refreshQuoteNo) && refreshQuoteNo == "0000") 71 { 72 CPQCard.DeleteDynamicwebQuoteCardState(refreshQuoteNo); 73 } 74 } 75 else if( requestVars["cardaction"].ToString()=="createQuote") 76 { 77 // result=CPQCard.CreateSalesQuoteFromCards(cardModelName,modelController.SalesQuoteNo); 78 result=CPQCard.CreateSalesQuoteFromCardsWithoutAssemblyBom(cardModelName,modelController.SalesQuoteNo); 79 80 Dynamicweb.Context.Current.Session["redirectdata"] = result; 81 Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] = "true"; 82 83 } 84 else if (requestVars["cardaction"].ToString() == "saveEditedQuote") 85 { 86 result = CPQCard.UpdateExistingQuoteFromCard(cardModelName, requestVars["salesQuoteNo"]?.ToString() ?? ""); 87 Dynamicweb.Context.Current.Session["redirectdata"] = result; 88 } 89 else if (requestVars["cardaction"].ToString() == "createQuoteExample") 90 { 91 result = CPQCard.CreateExampleQuote(cardModelName, requestVars["pageuserid"]?.ToString() ?? "0", requestVars["salesQuoteNo"]?.ToString() ?? ""); 92 Dynamicweb.Context.Current.Session["redirectdata"] = result; 93 Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] = "true"; 94 95 } 96 97 Dynamicweb.Context.Current.Response.Redirect(Dynamicweb.Context.Current.Request.Url.AbsoluteUri); // to prevent resubmission when refreshing 98 return; 99 100 } 101 Dictionary<string,object> carditems =CPQCard.LoadCardItemsByQuote(cardModelName,modelController.SalesQuoteNo); 102 Dictionary<string, object> quoteHeader = CPQCard.LoadQuoteHeaderInfo(cardModelName, modelController.SalesQuoteNo); 103 104 string quoteHeaderSource = quoteHeader.ContainsKey("source") ? quoteHeader["source"]?.ToString() ?? "" : ""; 105 string quoteNoDisplay = quoteHeader.ContainsKey("sales_quote_no") ? quoteHeader["sales_quote_no"]?.ToString() ?? modelController.SalesQuoteNo : modelController.SalesQuoteNo; 106 string quoteRevisionDisplay = quoteHeader.ContainsKey("quote_revision_no") ? quoteHeader["quote_revision_no"]?.ToString() ?? "0" : "0"; 107 string customerName = quoteHeader.ContainsKey("customer_name") ? quoteHeader["customer_name"]?.ToString() ?? "" : ""; 108 string customerNumber = quoteHeader.ContainsKey("customer_number") ? quoteHeader["customer_number"]?.ToString() ?? "" : ""; 109 string customerContact = quoteHeader.ContainsKey("contact") ? quoteHeader["contact"]?.ToString() ?? "" : ""; 110 string customerEmail = quoteHeader.ContainsKey("email") ? quoteHeader["email"]?.ToString() ?? "" : ""; 111 string customerPhone = quoteHeader.ContainsKey("phone") ? quoteHeader["phone"]?.ToString() ?? "" : ""; 112 string address = quoteHeader.ContainsKey("address") ? quoteHeader["address"]?.ToString() ?? "" : ""; 113 string address2 = quoteHeader.ContainsKey("address_2") ? quoteHeader["address_2"]?.ToString() ?? "" : ""; 114 string city = quoteHeader.ContainsKey("city") ? quoteHeader["city"]?.ToString() ?? "" : ""; 115 string postCode = quoteHeader.ContainsKey("post_code") ? quoteHeader["post_code"]?.ToString() ?? "" : ""; 116 string country = quoteHeader.ContainsKey("country") ? quoteHeader["country"]?.ToString() ?? "" : ""; 117 string quoteStatus = quoteHeader.ContainsKey("status") ? quoteHeader["status"]?.ToString() ?? "" : ""; 118 string quoteOrderDate = quoteHeader.ContainsKey("order_date") ? quoteHeader["order_date"]?.ToString() ?? "" : ""; 119 string quoteDueDate = quoteHeader.ContainsKey("due_date") ? quoteHeader["due_date"]?.ToString() ?? "" : ""; 120 121 var targetPage = Dynamicweb.Content.Services.Pages 122 .GetPages() 123 .FirstOrDefault(p => 124 (p.NavigationTag?.Contains("cpqcustom") ?? false) && 125 (p.Item["CPQ_ModelVersionId"]?.ToString() ?? "") == cardModelName 126 ); 127 128 string editUrl = targetPage != null ? $"/Default.aspx?ID={targetPage.ID}" : "#"; 129 string? myData = Dynamicweb.Context.Current.Session["redirectdata"] as string; 130 string createQuoteErrorNote = ""; 131 string[] createQuoteErrorLines = Array.Empty<string>(); 132 string deleteCardItemNote = ""; 133 string[] deleteCardItemNoteLines = Array.Empty<string>(); 134 135 const string odataErrorMarker = "[ODATA_ERROR_NOTE]"; 136 const string deleteCardItemNoteMarker = "[DELETE_CARDITEM_NOTE]"; 137 if (!string.IsNullOrWhiteSpace(myData)) 138 { 139 int markerIndex = myData.IndexOf(odataErrorMarker, StringComparison.Ordinal); 140 if (markerIndex >= 0) 141 { 142 int noteStart = markerIndex + odataErrorMarker.Length; 143 createQuoteErrorNote = myData.Substring(noteStart).Trim(); 144 myData = myData.Substring(0, markerIndex).Trim(); 145 createQuoteErrorLines = createQuoteErrorNote 146 .Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries) 147 .Select(line => line.Trim()) 148 .Where(line => !string.IsNullOrWhiteSpace(line)) 149 .ToArray(); 150 } 151 152 int deleteMarkerIndex = myData.IndexOf(deleteCardItemNoteMarker, StringComparison.Ordinal); 153 if (deleteMarkerIndex >= 0) 154 { 155 int noteStart = deleteMarkerIndex + deleteCardItemNoteMarker.Length; 156 deleteCardItemNote = myData.Substring(noteStart).Trim(); 157 myData = myData.Substring(0, deleteMarkerIndex).Trim(); 158 deleteCardItemNoteLines = deleteCardItemNote 159 .Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries) 160 .Select(line => line.Trim()) 161 .Where(line => !string.IsNullOrWhiteSpace(line)) 162 .ToArray(); 163 } 164 } 165 166 myData = myData != null ? myData.Replace("\"", "\\\"") : ""; // Escape double quotes for JavaScript 167 string refreshAfterQuoteCreate = (Dynamicweb.Context.Current.Session["refreshAfterQuoteCreate"] as string) ?? ""; 168 Dynamicweb.Context.Current.Session.Remove("redirectdata"); 169 Dynamicweb.Context.Current.Session.Remove("refreshAfterQuoteCreate"); 170 } 171 <script> 172 window.editUrl = "@editUrl"; 173 174 function addcardtolist(templateId) { 175 176 FormaddItem.templateId.value = templateId; 177 FormaddItem.submit(); 178 } 179 function editcarditem(keyline,pageid) { 180 Formedititem.itemdatakeyline.value = keyline; 181 Formedititem.action= "/Default.aspx?ID="+pageid+"&quote="+encodeURIComponent(Formedititem.salesQuoteNo.value || ""); 182 let dgb = document.getElementById("debugmod").value; 183 if(dgb === "true") { 184 Formedititem.action= "/Default.aspx?ID="+pageid+"&quote="+encodeURIComponent(Formedititem.salesQuoteNo.value || "")+"&debugmode=true"; 185 } 186 Formedititem.submit(); 187 } 188 function deleteitem(keyline) { 189 FormdelItem.itemdatakeyline.value = keyline; 190 FormdelItem.submit(); 191 } 192 193 function duplicateitem(keyline) { 194 FormduplicateItem.itemdatakeyline.value = keyline; 195 FormduplicateItem.submit(); 196 } 197 198 function toggleBom(itemId) { 199 var panel = document.getElementById("bom-panel-" + itemId); 200 if (!panel) { 201 return; 202 } 203 204 var isOpen = panel.classList.contains("open"); 205 var allPanels = document.querySelectorAll(".bom-panel"); 206 allPanels.forEach(function (node) { 207 node.classList.remove("open"); 208 }); 209 210 if (!isOpen) { 211 panel.classList.add("open"); 212 } 213 } 214 215 function createSalesQuote() { 216 FormCreateQuote.submit(); 217 } 218 219 function saveEditedQuote() { 220 FormSaveEditedQuote.submit(); 221 } 222 223 function closeCpqCard() { 224 window.location.href = "/my-account/my-quotes"; 225 } 226 227 function createQuote() { 228 @* var quoteNo = (FormCreateQuote.quote && FormCreateQuote.quote.value ? FormCreateQuote.quote.value : "").trim(); 229 if (!quoteNo || quoteNo === "0000") { 230 FormCreateQuoteExample.submit(); 231 return; 232 } *@ 233 FormCreateQuoteExample.submit(); 234 } 235 236 function isCreateSalesQuoteSuccess(rawData) { 237 if (!rawData) { 238 return false; 239 } 240 241 try { 242 var parsed = JSON.parse(rawData || ""); 243 if (parsed && parsed.quoteId) { 244 return true; 245 } 246 } catch (error) { 247 } 248 249 return (rawData || "").indexOf("quoteId") !== -1; 250 } 251 252 document.addEventListener("DOMContentLoaded", function () { 253 var clearForm = document.getElementById("FormClearOnRefresh"); 254 var navEntries = performance.getEntriesByType("navigation"); 255 var isReload = navEntries && navEntries.length > 0 && navEntries[0].type === "reload"; 256 var shouldRefreshAfterQuoteCreate = "@refreshAfterQuoteCreate" === "true"; 257 var hasCreateQuoteError = @(createQuoteErrorLines.Length > 0 ? "true" : "false"); 258 var refreshQuoteInput = clearForm ? clearForm.querySelector("input[name='salesQuoteNo']") : null; 259 var refreshQuoteNo = refreshQuoteInput ? (refreshQuoteInput.value || "").trim() : ""; 260 var myData = "@myData"; 261 var hasRedirectPayload = !!(myData && myData.trim()); 262 263 // Only clear on a plain manual reload of temporary quote state. 264 // Do not clear right after create/sync responses, so notes remain visible. 265 if (isReload && refreshQuoteNo === "0000" && !hasCreateQuoteError && !shouldRefreshAfterQuoteCreate && !hasRedirectPayload && clearForm) { 266 clearForm.submit(); 267 return; 268 } 269 270 if (myData && !hasCreateQuoteError && shouldRefreshAfterQuoteCreate) { 271 return; 272 } 273 }); 274 </script> 275 276 <style> 277 .cpq-bc-shell { 278 --bc-bg: #f4f6fb; 279 --bc-surface: #ffffff; 280 --bc-border: #dde3ed; 281 --bc-text: #1a2433; 282 --bc-muted: #5a6b85; 283 --bc-primary: #0066b8; 284 --bc-primary-strong: #004a8b; 285 --bc-danger: #c0392b; 286 --bc-shadow: 0 1px 2px rgba(21, 38, 62, 0.06), 0 6px 16px rgba(21, 38, 62, 0.06); 287 background: linear-gradient(180deg, #f8f9fc 0%, var(--bc-bg) 100%); 288 color: var(--bc-text); 289 border-radius: 10px; 290 padding: 18px 16px 20px; 291 } 292 293 .cpq-bc-shell .bc-list { 294 background: var(--bc-surface); 295 border: 1px solid var(--bc-border); 296 border-radius: 8px; 297 box-shadow: var(--bc-shadow); 298 overflow: hidden; 299 } 300 301 .cpq-bc-shell .bc-section-title { 302 margin: 0; 303 padding: 10px 12px; 304 background: #eef3fb; 305 border-bottom: 1px solid var(--bc-border); 306 color: #22324a; 307 font-size: 13px; 308 font-weight: 600; 309 letter-spacing: 0.2px; 310 text-transform: uppercase; 311 } 312 313 .cpq-bc-shell .bc-row { 314 display: grid; 315 grid-template-columns: minmax(180px, 2fr) minmax(140px, 1.2fr) minmax(140px, 1.2fr) minmax(120px, 1fr) auto auto auto; 316 gap: 8px; 317 align-items: center; 318 padding: 8px 12px; 319 border-bottom: 1px solid #edf1f7; 320 font-size: 13px; 321 } 322 323 .cpq-bc-shell .bc-row:last-child { 324 border-bottom: none; 325 } 326 327 .cpq-bc-shell .bc-row.header { 328 background: #f7f9fd; 329 font-weight: 600; 330 color: #273958; 331 font-size: 12px; 332 text-transform: uppercase; 333 letter-spacing: 0.2px; 334 } 335 336 .cpq-bc-shell .cell { 337 min-width: 0; 338 } 339 340 .cpq-bc-shell .cell.desc { 341 color: var(--bc-text); 342 overflow: hidden; 343 text-overflow: ellipsis; 344 white-space: nowrap; 345 } 346 347 .cpq-bc-shell .cell.meta { 348 color: var(--bc-muted); 349 } 350 351 .cpq-bc-shell .bc-empty { 352 padding: 22px 12px; 353 color: var(--bc-muted); 354 font-size: 13px; 355 background: #fcfdff; 356 } 357 358 .cpq-bc-shell .action-bar { 359 display: flex; 360 flex-wrap: wrap; 361 gap: 8px; 362 margin-bottom: 12px; 363 } 364 365 .cpq-bc-shell .action { 366 display: inline-flex; 367 align-items: center; 368 gap: 8px; 369 background: #ffffff; 370 border: 1px solid #cfd8e6; 371 color: #1f314c; 372 border-radius: 6px; 373 padding: 7px 10px; 374 cursor: pointer; 375 transition: background-color 120ms ease, border-color 120ms ease; 376 } 377 378 .cpq-bc-shell .action:hover { 379 background: #f2f7ff; 380 border-color: #9fbce0; 381 } 382 383 .cpq-bc-shell .action .label { 384 font-size: 13px; 385 font-weight: 600; 386 } 387 388 .cpq-bc-shell .bc-action-btn { 389 border: 1px solid #c9d5e6; 390 border-radius: 4px; 391 background: #fff; 392 color: #22344f; 393 font-size: 12px; 394 font-weight: 600; 395 padding: 4px 8px; 396 cursor: pointer; 397 } 398 399 .cpq-bc-shell .bc-action-btn:hover { 400 background: #f2f7ff; 401 border-color: #9fbce0; 402 } 403 404 .cpq-bc-shell .bc-action-btn.delete { 405 color: var(--bc-danger); 406 border-color: #e6c8c4; 407 background: #fffafa; 408 } 409 410 .cpq-bc-shell .bc-footer-actions { 411 display: flex; 412 flex-wrap: wrap; 413 justify-content: flex-end; 414 gap: 8px; 415 margin-top: 12px; 416 } 417 418 .cpq-bc-shell .bc-error-note { 419 margin: 10px 12px 12px; 420 padding: 10px 12px; 421 border-radius: 6px; 422 border: 1px solid #e6b8b2; 423 background: #fff5f4; 424 color: #7f1d1d; 425 font-size: 12px; 426 line-height: 1.45; 427 } 428 429 .cpq-bc-shell .bc-error-note strong { 430 display: block; 431 margin-bottom: 4px; 432 font-size: 12px; 433 text-transform: uppercase; 434 letter-spacing: 0.2px; 435 } 436 437 .cpq-bc-shell .bc-status-note { 438 margin: 10px 12px 12px; 439 padding: 10px 12px; 440 border-radius: 6px; 441 border: 1px solid #bfd3ea; 442 background: #f4f8fd; 443 color: #1f4268; 444 font-size: 12px; 445 line-height: 1.45; 446 } 447 448 .cpq-bc-shell .bc-status-note strong { 449 display: block; 450 margin-bottom: 4px; 451 font-size: 12px; 452 text-transform: uppercase; 453 letter-spacing: 0.2px; 454 } 455 456 .cpq-bc-shell .bom-panel { 457 width: 100%; 458 border: 1px solid #dbe4f2; 459 border-radius: 6px; 460 background: #fbfdff; 461 margin: 2px 0 8px; 462 display: none; 463 } 464 465 .cpq-bc-shell .bom-panel.open { 466 display: block; 467 } 468 469 .cpq-bc-shell .bom-list { 470 border-top: 1px solid #e8eef8; 471 padding: 8px 10px 10px; 472 } 473 474 .cpq-bc-shell .bom-title { 475 font-size: 12px; 476 font-weight: 600; 477 color: #29405f; 478 padding: 8px 10px 0; 479 } 480 481 .cpq-bc-shell .bom-line { 482 display: grid; 483 grid-template-columns: minmax(110px, 0.9fr) minmax(180px, 1.6fr) minmax(80px, 0.7fr) minmax(110px, 0.9fr) minmax(110px, 0.9fr) minmax(120px, 1fr) minmax(120px, 1fr); 484 gap: 8px; 485 font-size: 12px; 486 color: #304763; 487 padding: 4px 0; 488 border-bottom: 1px dashed #eaf0f8; 489 } 490 491 .cpq-bc-shell .bom-line:last-child { 492 border-bottom: none; 493 } 494 495 .cpq-bc-shell .bom-line.header { 496 text-transform: uppercase; 497 font-weight: 600; 498 color: #4f6684; 499 font-size: 11px; 500 } 501 502 .cpq-bc-shell .bom-total { 503 margin-top: 8px; 504 font-size: 12px; 505 font-weight: 700; 506 color: #1d3552; 507 text-align: right; 508 } 509 510 .cpq-bc-shell .bc-primary-btn, 511 .cpq-bc-shell .bc-secondary-btn { 512 border-radius: 5px; 513 padding: 7px 12px; 514 font-size: 13px; 515 font-weight: 600; 516 border: 1px solid transparent; 517 cursor: pointer; 518 } 519 520 .cpq-bc-shell .bc-primary-btn { 521 background: var(--bc-primary); 522 color: #fff; 523 border-color: var(--bc-primary); 524 } 525 526 .cpq-bc-shell .bc-primary-btn:hover { 527 background: var(--bc-primary-strong); 528 border-color: var(--bc-primary-strong); 529 } 530 531 .cpq-bc-shell .bc-secondary-btn { 532 background: #ffffff; 533 color: #22344f; 534 border-color: #c9d5e6; 535 } 536 537 .cpq-bc-shell .bc-secondary-btn:hover { 538 background: #f2f7ff; 539 border-color: #9fbce0; 540 } 541 542 @@media (max-width: 991px) { 543 .cpq-bc-shell .bc-row { 544 grid-template-columns: 1fr 1fr; 545 gap: 6px 10px; 546 } 547 548 .cpq-bc-shell .bc-row .code { 549 justify-self: start; 550 } 551 } 552 553 @@media (max-width: 640px) { 554 .cpq-bc-shell { 555 padding: 12px 10px 14px; 556 } 557 558 .cpq-bc-shell .bc-row { 559 grid-template-columns: 1fr; 560 } 561 562 .cpq-bc-shell .cell.desc { 563 white-space: normal; 564 } 565 566 .cpq-bc-shell .bom-line { 567 grid-template-columns: 1fr; 568 gap: 4px; 569 } 570 } 571 </style> 572 573 @* need to be considered : 574 carditem's modelversionid can be different from cardtemplete's modelversionid or pageid's modelversion 575 our design is, here at cardtemplete user can combine manny carditems with different CPQ model (modelversionid) 576 *@ 577 578 <input type="hidden" id="debugmod" value="@debgug" /> 579 580 <form name="FormaddItem" id="FormaddItem" method="post" action=""> 581 <input type="hidden" name="modelversionid" id="modelversionid" value="@(cardModelName)" /> 582 <input type="hidden" name="cardaction" id="cardaction" value="addcardtoquote" /> 583 <input type="hidden" name="salesQuoteNo" id="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 584 <input type="hidden" name="templateId" id="templateId" value="" /> 585 </form> 586 <form name="FormduplicateItem" id="FormduplicateItem" method="post" action=""> 587 <input type="hidden" name="cardaction" id="cardaction" value="duplicatecarditem" /> 588 <input type="hidden" name="itemdatakeyline" id="itemdatakeyline" value="" /> 589 </form> 590 <form name="FormdelItem" id="FormdelItem" method="post" action=""> 591 <input type="hidden" name="cardaction" id="cardaction" value="deletecarditem" /> 592 <input type="hidden" name="salesQuoteNo" id="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 593 <input type="hidden" name="itemdatakeyline" id="itemdatakeyline" value="" /> 594 </form> 595 <form name="Formedititem" id="Formedititem" method="post" action=""> 596 <input type="hidden" name="templatemodelversionid" id="modelversionid" value="@(cardModelName)" /> 597 <input type="hidden" name="pageid" id="pageid" value="" /> 598 <input type="hidden" name="cardaction" id="cardaction" value="editcarditem" /> 599 <input type="hidden" name="salesQuoteNo" id="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 600 <input type="hidden" name="itemdatakeyline" id="itemdatakeyline" value="" /> 601 </form> 602 <form name="FormCreateQuote" id="FormCreateQuote" method="post" action=""> 603 <input type="hidden" name="modelversionid" id="modelversionid" value="@(cardModelName)" /> 604 <input type="hidden" name="cardaction" id="cardaction" value="createQuote" /> 605 <input type="hidden" name="quote" id="quote" value="@(modelController.SalesQuoteNo)" /> 606 607 </form> 608 <form name="FormCreateQuoteExample" id="FormCreateQuoteExample" method="post" action=""> 609 <input type="hidden" name="modelversionid" id="modelversionid" value="@(cardModelName)" /> 610 <input type="hidden" name="cardaction" id="cardaction" value="createQuoteExample" /> 611 <input type="hidden" name="pageuserid" id="pageuserid" value="@(pageUserId)" /> 612 <input type="hidden" name="salesQuoteNo" id="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 613 </form> 614 <form name="FormSaveEditedQuote" id="FormSaveEditedQuote" method="post" action=""> 615 <input type="hidden" name="modelversionid" id="modelversionid" value="@(cardModelName)" /> 616 <input type="hidden" name="cardaction" id="cardaction" value="saveEditedQuote" /> 617 <input type="hidden" name="salesQuoteNo" id="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 618 </form> 619 <form name="FormClearOnRefresh" id="FormClearOnRefresh" method="post" action=""> 620 <input type="hidden" name="cardaction" value="clearCardItemsOnRefresh" /> 621 <input type="hidden" name="salesQuoteNo" value="@(modelController.SalesQuoteNo)" /> 622 </form> 623 <div class="container mt-3 cpq-bc-shell"> 624 <div class="bc-list mb-3"> 625 <h3 class="bc-section-title">Quote Header</h3> 626 <div class="bc-row"> 627 <span class="cell desc"><strong>Sales Quote</strong>: @quoteNoDisplay</span> 628 <span class="cell desc"><strong>Revision</strong>: @quoteRevisionDisplay</span> 629 <span class="cell desc meta"><strong>Source</strong>: @(string.IsNullOrWhiteSpace(quoteHeaderSource) ? "N/A" : quoteHeaderSource)</span> 630 </div> 631 <div class="bc-row"> 632 <span class="cell desc"><strong>Customer</strong>: @(string.IsNullOrWhiteSpace(customerName) ? "N/A" : customerName)</span> 633 <span class="cell desc"><strong>Customer No</strong>: @(string.IsNullOrWhiteSpace(customerNumber) ? "N/A" : customerNumber)</span> 634 <span class="cell desc"><strong>Status</strong>: @(string.IsNullOrWhiteSpace(quoteStatus) ? "N/A" : quoteStatus)</span> 635 </div> 636 <div class="bc-row"> 637 <span class="cell desc"><strong>Address</strong>: @(string.IsNullOrWhiteSpace(address) ? "N/A" : address)</span> 638 <span class="cell desc">@(string.IsNullOrWhiteSpace(address2) ? "" : address2)</span> 639 <span class="cell desc">@(string.IsNullOrWhiteSpace(city) && string.IsNullOrWhiteSpace(postCode) && string.IsNullOrWhiteSpace(country) ? "" : $"{city} {postCode} {country}".Trim())</span> 640 </div> 641 <div class="bc-row"> 642 <span class="cell desc"><strong>Contact</strong>: @(string.IsNullOrWhiteSpace(customerContact) ? "N/A" : customerContact)</span> 643 <span class="cell desc"><strong>Email</strong>: @(string.IsNullOrWhiteSpace(customerEmail) ? "N/A" : customerEmail)</span> 644 <span class="cell desc"><strong>Phone</strong>: @(string.IsNullOrWhiteSpace(customerPhone) ? "N/A" : customerPhone)</span> 645 </div> 646 <div class="bc-row"> 647 <span class="cell desc"><strong>Order Date</strong>: @(string.IsNullOrWhiteSpace(quoteOrderDate) ? "N/A" : quoteOrderDate)</span> 648 <span class="cell desc"><strong>Due Date</strong>: @(string.IsNullOrWhiteSpace(quoteDueDate) ? "N/A" : quoteDueDate)</span> 649 <span class="cell desc"></span> 650 </div> 651 </div> 652 653 @if( !string.IsNullOrEmpty(modelController.SalesQuoteNo) ) 654 { 655 <div class="action-bar"> 656 @foreach(var item in card.Cards) 657 { 658 <button class="action" onclick="addcardtolist('@(item.TemplateId)')"> 659 <span class="icon"> 660 @if(item.Image != null && item.Image != ""){ 661 <img src="@item.Image" width="50px" /> 662 } 663 </span> 664 <span class="label">+ @item.Name</span> 665 </button> 666 } 667 </div> 668 } 669 670 <div class="bc-list mb-3"> 671 <h3 class="bc-section-title">Card Items</h3> 672 <div class="bc-row header"> 673 <span class="cell desc">Description</span> 674 <span class="cell desc">BC Item No</span> 675 <span class="cell desc">Total BOM Price</span> 676 <span class="cell desc">BOM</span> 677 <span class="cell code">Edit</span> 678 <span class="cell code">Copy</span> 679 <span class="cell code">Delete</span> 680 </div> 681 @if (carditems == null || !carditems.Any()) 682 { 683 <div class="bc-empty list-group-item text-center text-muted no-item">No Item</div> 684 } 685 else 686 { 687 @foreach (var key in carditems.Keys.ToList()) 688 { 689 Dictionary<string,object> citem = (Dictionary<string,object>)carditems[key]; 690 string cpageid= citem.ContainsKey("pageid") ? citem["pageid"].ToString()! : ""; 691 string description= citem.ContainsKey("itemlabel") ? citem["itemlabel"].ToString()! : ""; 692 string parentItemNo = citem.ContainsKey("ItemNo") 693 ? citem["ItemNo"]?.ToString() ?? "" 694 : (citem.ContainsKey("itemno") 695 ? citem["itemno"]?.ToString() ?? "" 696 : (citem.ContainsKey("item_no") ? citem["item_no"]?.ToString() ?? "" : "")); 697 string cardItemPayload = JsonSerializer.Serialize(citem, JsonHelper.JsonOptions); 698 CardItem? cardItemTyped = JsonSerializer.Deserialize<CardItem>(cardItemPayload, JsonHelper.JsonOptions) 699 ?? JsonSerializer.Deserialize<CardItem>(cardItemPayload); 700 List<BOMInfo> bomLines = cardItemTyped?.bomlines ?? new List<BOMInfo>(); 701 decimal totalBomPrice = cardItemTyped?.bomtotal?.TotalSell ?? bomLines.Sum(line => line?.LineSell ?? 0m); 702 <div class="bc-row" style="cursor: pointer;" onclick="toggleBom('@(key)')"> 703 <span class="cell desc">@description</span> 704 <span class="cell desc">@(string.IsNullOrWhiteSpace(parentItemNo) ? "-" : parentItemNo)</span> 705 <span class="cell desc">@totalBomPrice.ToString("N2")</span> 706 <span class="cell desc">@bomLines.Count line(s)</span> 707 <span class="cell code"><button type="button" class="bc-action-btn" onclick="event.stopPropagation();editcarditem('@(key)','@(cpageid)')">Edit</button></span> 708 <span class="cell code"><button type="button" class="bc-action-btn" onclick="event.stopPropagation();duplicateitem('@(key)')">Copy</button></span> 709 <span class="cell code"><button type="button" class="bc-action-btn delete" onclick="event.stopPropagation();deleteitem('@(key)')">Delete</button></span> 710 </div> 711 <div class="bom-panel" id="bom-panel-@(key)"> 712 713 <div class="bom-list"> 714 @if (bomLines.Count == 0) 715 { 716 <div class="cell desc">No BOM lines available.</div> 717 } 718 else 719 { 720 <div class="bom-line header"> 721 <span>Item No</span> 722 <span>Description</span> 723 <span>Qty</span> 724 <span>Unit Sell</span> 725 <span>Line Sell</span> 726 <span>BC Status</span> 727 </div> 728 @foreach (var line in bomLines) 729 { 730 decimal unitSell = line?.UnitSell ?? 0m; 731 decimal lineSell = line?.LineSell ?? 0m; 732 decimal qty = line?.Qty ?? 0m; 733 string lineDescription = !string.IsNullOrWhiteSpace(line?.Description) 734 ? line.Description! 735 : (line?.LabelName ?? ""); 736 <div class="bom-line"> 737 <span>@(line?.ItemNo ?? "")</span> 738 <span>@lineDescription</span> 739 <span>@qty.ToString("N2")</span> 740 <span>@unitSell.ToString("N2")</span> 741 <span>@lineSell.ToString("N2")</span> 742 <span>@(string.IsNullOrWhiteSpace(line?.BCStatus) ? "-" : line?.BCStatus)</span> 743 </div> 744 } 745 } 746 <div class="bom-total">Total BOM Price: @totalBomPrice.ToString("N2")</div> 747 </div> 748 </div> 749 } 750 } 751 @if (!string.IsNullOrWhiteSpace(createQuoteErrorNote)) 752 { 753 <div class="bc-error-note"> 754 <strong>Create Sales Quote OData Errors</strong> 755 @foreach (var errorLine in createQuoteErrorLines) 756 { 757 <div>@errorLine</div> 758 } 759 </div> 760 } 761 @if (!string.IsNullOrWhiteSpace(deleteCardItemNote)) 762 { 763 <div class="bc-status-note"> 764 <strong>Delete Card Item BC Cleanup</strong> 765 @foreach (var statusLine in deleteCardItemNoteLines) 766 { 767 <div>@statusLine</div> 768 } 769 </div> 770 } 771 </div> 772 773 <div class="ms-4 mt-8 text-end bc-footer-actions"> 774 @if( !string.IsNullOrEmpty(modelController.SalesQuoteNo) && modelController.SalesQuoteNo.StartsWith("QUOTE", StringComparison.OrdinalIgnoreCase) ) 775 { 776 <button type="button" class="bc-primary-btn" onclick="saveEditedQuote()">Save edited CPQ Card</button> 777 <button type="button" class="bc-secondary-btn" onclick="closeCpqCard()">Close</button> 778 } 779 else if( !string.IsNullOrEmpty(modelController.SalesQuoteLineNo) ) 780 { 781 <button type="button" class="bc-secondary-btn" onclick="closeCpqCard()">Close</button> 782 } 783 else 784 { 785 <button type="button" class="bc-primary-btn" onclick="createQuote()">Create Quote</button> 786 <button type="button" class="bc-primary-btn" onclick="createSalesQuote()">Save to Quote</button> 787 <button type="button" class="bc-secondary-btn" onclick="closeCpqCard()">Close</button> 788 } 789 </div> 790 </div>