PageRenderTime 65ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Apttus.SNowPS/Apttus.SNowPS.Repository/Products/ProdQuoteRepository.cs

https://bitbucket.org/apttus_bmodi/renewals_1.4_new_5feb2018
C# | 1411 lines | 971 code | 178 blank | 262 comment | 259 complexity | a2d4d3ab98388a4c4e3c9f6bcd0a1e53 MD5 | raw file
  1. /****************************************************************************************
  2. @Name: QuoteRepository.cs
  3. @Author: Asha Tank
  4. @CreateDate: 11 Oct 2017
  5. @Description: Quote header related process
  6. @UsedBy: This will be used by ProdQuoteRepository controller
  7. @ModifiedBy:
  8. @ModifiedDate:
  9. @ChangeDescription:
  10. *****************************************************************************************/
  11. using Apttus.DataAccess.Common.Enums;
  12. using Apttus.DataAccess.Common.Model;
  13. using Apttus.SNowPS.Common;
  14. using Apttus.SNowPS.Model;
  15. using Newtonsoft.Json;
  16. using Newtonsoft.Json.Linq;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Linq;
  20. using System.Net.Http;
  21. using System.Xml.Linq;
  22. using System.IO;
  23. using System.Reflection;
  24. namespace Apttus.SNowPS.Respository
  25. {
  26. public class ProdQuoteRepository
  27. {
  28. /// <summary>
  29. /// Calculate financial fields of quote header for paased quote id
  30. /// </summary>
  31. /// <param name="QuoteId"></param>
  32. /// <param name="accessToken"></param>
  33. /// <returns></returns>
  34. public HttpResponseMessage GetQuoteDetail(string QuoteId, string accessToken)
  35. {
  36. var errors = new List<Model.ErrorInfo>();
  37. try
  38. {
  39. //Build AQL Query to fetch Quote,Quote Line Items & Product details
  40. var query = new Query(Constants.OBJ_QUOTE);
  41. query.AddColumns(Constants.OBJ_FIELDQUOTELINEITEM.Split(Constants.CHAR_COMMA));
  42. Expression exp = new Expression(ExpressionOperator.AND);
  43. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  44. query.SetCriteria(exp);
  45. Join quoteLineItem = new Join(Constants.OBJ_QUOTE, Constants.OBJ_CPQ_QUOTELINEITEM, Constants.FIELD_ID, Constants.FIELD_QUOTEID, JoinType.LEFT);
  46. quoteLineItem.EntityAlias = Constants.OBJ_CPQ_QUOTELINEITEM;
  47. query.AddJoin(quoteLineItem);
  48. Join lineItem = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_LINEITEM, Constants.FIELD_DERIVEDFROMId, Constants.FIELD_ID, JoinType.LEFT);
  49. lineItem.EntityAlias = Constants.OBJ_LINEITEM;
  50. query.AddJoin(lineItem);
  51. Join product = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_PRODUCT, Constants.FIELD_PRODUCTID, Constants.FIELD_ID, JoinType.LEFT);
  52. product.EntityAlias = Constants.OBJ_PRODUCT;
  53. query.AddJoin(product);
  54. var jsonQuery = query.Serialize();
  55. //
  56. var reqConfig = new RequestConfigModel();
  57. reqConfig.accessToken = accessToken;
  58. reqConfig.searchType = SearchType.AQL;
  59. reqConfig.objectName = Constants.OBJ_QUOTE;
  60. var response = Utilities.Search(jsonQuery, reqConfig);
  61. ResultQuoteHeaderModel resultQuoteHeaderModel = new ResultQuoteHeaderModel();
  62. if (response != null && response.IsSuccessStatusCode)
  63. {
  64. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  65. List<QuoteQuoteLineDetails> QuoteLineList = new List<QuoteQuoteLineDetails>();
  66. QuoteLineList = JsonConvert.DeserializeObject<List<QuoteQuoteLineDetails>>(responseString);
  67. if (QuoteLineList != null && QuoteLineList.Count > 0)
  68. {
  69. DailyExcnageRate objDailyExcnageRate = new DailyExcnageRate();
  70. objDailyExcnageRate = GetExchangeRateDetails(QuoteLineList.FirstOrDefault().cpq_lineitem.CurrencyId, accessToken);
  71. decimal EstimatedTotal = 0;
  72. decimal ProfesionalServiceTotal = 0;
  73. //Calculate quote fields
  74. for (int i = 0; i < QuoteLineList.Count; i++)
  75. {
  76. switch (QuoteLineList[i].crm_Product.ContributesTo.Value)
  77. {
  78. case Constants.TOTALPSREVENUE:
  79. resultQuoteHeaderModel.ext_EducationalServicesandKnowledgeandOther = resultQuoteHeaderModel.ext_EducationalServicesandKnowledgeandOther + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  80. resultQuoteHeaderModel.ext_TotalServicesRevenue = resultQuoteHeaderModel.ext_TotalServicesRevenue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  81. resultQuoteHeaderModel.ext_TotalPSRevenue = resultQuoteHeaderModel.ext_TotalPSRevenue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  82. break;
  83. case Constants.SUBSCRIPTIONANDLICENSEREVENUE:
  84. resultQuoteHeaderModel.ext_TotalLicenseValue = resultQuoteHeaderModel.ext_TotalLicenseValue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  85. resultQuoteHeaderModel.ext_TotalSubscriptionACV = resultQuoteHeaderModel.ext_TotalSubscriptionACV + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.AnnualContractValue);
  86. break;
  87. case Constants.LICENSEREVENUE:
  88. resultQuoteHeaderModel.ext_TotalLicenseValue = resultQuoteHeaderModel.ext_TotalLicenseValue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  89. break;
  90. case Constants.TRAININGREVENUE:
  91. resultQuoteHeaderModel.ext_TotalServicesRevenue = resultQuoteHeaderModel.ext_TotalServicesRevenue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  92. resultQuoteHeaderModel.ext_TotalTrainingRevenue = resultQuoteHeaderModel.ext_TotalTrainingRevenue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  93. break;
  94. case Constants.OTHERREVENUE:
  95. resultQuoteHeaderModel.ext_TotalOtherRevenue = resultQuoteHeaderModel.ext_TotalOtherRevenue + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  96. break;
  97. }
  98. if (QuoteLineList[i].crm_Product.Family != null && QuoteLineList[i].crm_Product.Family.Value == "Professional Services")
  99. {
  100. ProfesionalServiceTotal = ProfesionalServiceTotal + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  101. }
  102. resultQuoteHeaderModel.ext_TotalAnnualListPrice = resultQuoteHeaderModel.ext_TotalAnnualListPrice + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.AnnualContractValue);
  103. EstimatedTotal = EstimatedTotal + Convert.ToDecimal(QuoteLineList[i].cpq_QuoteLineItem.EstimatedTotal);
  104. }
  105. resultQuoteHeaderModel.ext_PreTaxTotals = Convert.ToDecimal(resultQuoteHeaderModel.ext_TotalLicenseValue + resultQuoteHeaderModel.ext_TotalServicesRevenue + resultQuoteHeaderModel.ext_TotalOtherRevenue);
  106. if (ProfesionalServiceTotal != 0)
  107. {
  108. resultQuoteHeaderModel.ext_EstimatedTravelExpenseFees = (ProfesionalServiceTotal * 10) / 100;
  109. }
  110. resultQuoteHeaderModel.ext_EstimatedTotal = EstimatedTotal + resultQuoteHeaderModel.ext_EstimatedTravelExpenseFees;
  111. resultQuoteHeaderModel.Id = QuoteLineList.FirstOrDefault().Id;
  112. //Calculation of USD fields
  113. resultQuoteHeaderModel.ext_USDTotalAnnualListPrice = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalAnnualListPrice);
  114. resultQuoteHeaderModel.ext_USDTotalLicenseValue = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalLicenseValue);
  115. resultQuoteHeaderModel.ext_USDTotalOtherRevenue = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalOtherRevenue);
  116. resultQuoteHeaderModel.ext_USDTotalPSRevenue = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalPSRevenue);
  117. resultQuoteHeaderModel.ext_USDTotalServicesRevenue = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalServicesRevenue);
  118. resultQuoteHeaderModel.ext_USDTotalSubscriptionACV = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalSubscriptionACV);
  119. resultQuoteHeaderModel.ext_USDTotalTrainingRevenue = Convert.ToDecimal(objDailyExcnageRate.ext_Rate * resultQuoteHeaderModel.ext_TotalTrainingRevenue);
  120. //Calculation of USD fields end
  121. }
  122. //return response
  123. List<ResultQuoteHeaderModel> quoteHeaderList = new List<ResultQuoteHeaderModel>();
  124. quoteHeaderList.Add(resultQuoteHeaderModel);
  125. var responseResult = UpdateQuoteHeader(quoteHeaderList, accessToken);
  126. return responseResult;
  127. }
  128. else
  129. {
  130. HttpResponseMessage jsonResponse = new HttpResponseMessage();
  131. Model.ErrorInfo errorInfo = new Model.ErrorInfo();
  132. errorInfo.Message = "Error";
  133. var dict = new Dictionary<string, object>
  134. {
  135. {"Message", "Fail to update records"}
  136. };
  137. errorInfo.Record = dict;
  138. errors.Add(errorInfo);
  139. Utilities.CreateResponse(jsonResponse, errors);
  140. return jsonResponse;
  141. }
  142. }
  143. catch (Exception ex)
  144. {
  145. var resp = new HttpResponseMessage
  146. {
  147. Content = new StringContent("Message :" + ex.Message + " " + "StackStrace :" + ex.StackTrace, System.Text.Encoding.UTF8, "application/json"),
  148. StatusCode = System.Net.HttpStatusCode.BadRequest
  149. };
  150. return resp;
  151. }
  152. }
  153. /// <summary>
  154. /// Get Currency exchange rate based on currency code
  155. /// </summary>
  156. /// <param name="currencyCode"></param>
  157. /// <returns></returns>
  158. public DailyExcnageRate GetExchangeRateDetails(string currencyId, string accessToken)
  159. {
  160. //currencyCode = "USD";
  161. DailyExcnageRate ExchangeRates = new DailyExcnageRate();
  162. accessToken = accessToken != null ? accessToken : Utilities.GetAuthToken();
  163. var reqExchangeRateLineItem = Utilities.GetRequestConfiguration(Constants.OBJ_DAILYEXCHANGERATE, Constants.FIELD_CURRENCYCODE, Constants.FIELD_CURRENCYCODE);
  164. var dictContent = new List<Dictionary<string, object>> { new Dictionary<string, object>() { { "ext_CurrencyCode", currencyId } } };
  165. var resExchangeRate = Utilities.Search(dictContent, reqExchangeRateLineItem);
  166. if (resExchangeRate != null && resExchangeRate.IsSuccessStatusCode)
  167. {
  168. var responseString = JObject.Parse(resExchangeRate.Content.ReadAsStringAsync().Result).SelectToken("SerializedResultEntities").ToString();
  169. List<DailyExcnageRate> ListExchgRates = JsonConvert.DeserializeObject<List<DailyExcnageRate>>(responseString);
  170. // Getting last Created/Modified currency rate
  171. ExchangeRates = ListExchgRates.OrderByDescending(x => x.ModifiedOn).FirstOrDefault();
  172. }
  173. return ExchangeRates;
  174. }
  175. /// <summary>
  176. /// Update Quote Line Items
  177. /// </summary>
  178. /// <param name="lineItems"></param>
  179. /// <param name="accessToken"></param>
  180. /// <returns></returns>
  181. public HttpResponseMessage UpdateQuoteHeader(List<ResultQuoteHeaderModel> quoteHeaderList, string accessToken)
  182. {
  183. var reqConfig = new RequestConfigModel();
  184. reqConfig.accessToken = accessToken;
  185. reqConfig.objectName = Constants.OBJ_QUOTE;
  186. var lstQuoteToUpdate = new List<dynamic>();
  187. foreach (var lstQuoteItems in quoteHeaderList)
  188. {
  189. lstQuoteToUpdate.Add(new
  190. {
  191. Id = lstQuoteItems.Id,
  192. ext_EducationalServicesandKnowledgeandOther = lstQuoteItems.ext_EducationalServicesandKnowledgeandOther,
  193. ext_TotalServicesRevenue = lstQuoteItems.ext_TotalServicesRevenue,
  194. ext_TotalPSRevenue = lstQuoteItems.ext_TotalPSRevenue,
  195. ext_TotalSubscriptionACV = lstQuoteItems.ext_TotalSubscriptionACV,
  196. ext_TotalLicenseValue = lstQuoteItems.ext_TotalLicenseValue,
  197. ext_TotalTrainingRevenue = lstQuoteItems.ext_TotalTrainingRevenue,
  198. ext_TotalOtherRevenue = lstQuoteItems.ext_TotalOtherRevenue,
  199. ext_TotalAnnualListPrice = lstQuoteItems.ext_TotalAnnualListPrice,
  200. ext_PreTaxTotals = lstQuoteItems.ext_PreTaxTotals,
  201. ext_EstimatedTravelExpenseFees = lstQuoteItems.ext_EstimatedTravelExpenseFees,
  202. ext_EstimatedTotal = lstQuoteItems.ext_EstimatedTotal,
  203. ext_USDTotalAnnualListPrice = lstQuoteItems.ext_USDTotalAnnualListPrice,
  204. ext_USDTotalLicenseValue = lstQuoteItems.ext_USDTotalLicenseValue,
  205. ext_USDTotalOtherRevenue = lstQuoteItems.ext_USDTotalOtherRevenue,
  206. ext_USDTotalPSRevenue = lstQuoteItems.ext_USDTotalPSRevenue,
  207. ext_USDTotalServicesRevenue = lstQuoteItems.ext_USDTotalServicesRevenue,
  208. ext_USDTotalSubscriptionACV = lstQuoteItems.ext_USDTotalSubscriptionACV,
  209. ext_USDTotalTrainingRevenue = lstQuoteItems.ext_USDTotalTrainingRevenue
  210. });
  211. }
  212. var responseString = Utilities.Update(lstQuoteToUpdate, reqConfig);
  213. return responseString;
  214. }
  215. #region Commented Code
  216. ///// <summary>
  217. ///// Calculate financial fields of Quote line items for given QuoteId
  218. ///// </summary>
  219. ///// <param name="QuoteId"></param>
  220. ///// <param name="accessToken"></param>
  221. ///// <returns></returns>
  222. //public HttpResponseMessage UpdateQuoteLineItemFields(string QuoteId, string accessToken)
  223. //{
  224. // var errors = new List<Model.ErrorInfo>();
  225. // try
  226. // {
  227. // //Build AQL Query to fetch Quote,Quote Line Items & Product details
  228. // var query = new Query(Constants.OBJ_QUOTE);
  229. // query.AddColumns(Constants.OBJ_FIELDQUOTELINEITEMFINANCIAL.Split(Constants.CHAR_COMMA));
  230. // Expression exp = new Expression(ExpressionOperator.AND);
  231. // exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  232. // query.SetCriteria(exp);
  233. // Join quoteLineItem = new Join(Constants.OBJ_QUOTE, Constants.OBJ_CPQ_QUOTELINEITEM, Constants.FIELD_ID, Constants.FIELD_QUOTEID, JoinType.LEFT);
  234. // quoteLineItem.EntityAlias = Constants.OBJ_CPQ_QUOTELINEITEM;
  235. // query.AddJoin(quoteLineItem);
  236. // Join lineItem = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_LINEITEM, Constants.FIELD_DERIVEDFROMId, Constants.FIELD_ID, JoinType.LEFT);
  237. // lineItem.EntityAlias = Constants.OBJ_LINEITEM;
  238. // query.AddJoin(lineItem);
  239. // Join product = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_PRODUCT, Constants.FIELD_PRODUCTID, Constants.FIELD_ID, JoinType.LEFT);
  240. // product.EntityAlias = Constants.OBJ_PRODUCT;
  241. // query.AddJoin(product);
  242. // var jsonQuery = query.Serialize();
  243. // var reqConfig = new RequestConfigModel();
  244. // reqConfig.accessToken = accessToken;
  245. // reqConfig.searchType = SearchType.AQL;
  246. // reqConfig.objectName = Constants.OBJ_QUOTE;
  247. // var response = Utilities.Search(jsonQuery, reqConfig);
  248. // ResultUSDQuoteHeaderLineItemFields resultQuoteHeaderAndLIneItems = new ResultUSDQuoteHeaderLineItemFields();
  249. // ResultQuoteHeaderModel resultQuoteHeaderModel = new ResultQuoteHeaderModel();
  250. // List<ResultQuoteLineItem> lstResultQuoteLineItem = new List<ResultQuoteLineItem>();
  251. // if (response != null && response.IsSuccessStatusCode)
  252. // {
  253. // var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  254. // List<QuoteQuoteLineDetails> QuoteLineList = new List<QuoteQuoteLineDetails>();
  255. // QuoteLineList = JsonConvert.DeserializeObject<List<QuoteQuoteLineDetails>>(responseString);
  256. // if (QuoteLineList != null && QuoteLineList.Count > 0)
  257. // {
  258. // LineItemRepository lineItemRepo = new LineItemRepository();
  259. // //Calculate quote line item USD fields
  260. // for (int i = 0; i < QuoteLineList.Count; i++)
  261. // {
  262. // ResultQuoteLineItem objResultQuoteLineItem = new ResultQuoteLineItem();
  263. // objResultQuoteLineItem.Id = QuoteLineList[i].cpq_QuoteLineItem.Id;
  264. // //get daily currenct exchange rates based on currency code
  265. // DailyExcnageRate objDailyExcnageRate = lineItemRepo.GetExchangeRateDetails(QuoteLineList[i].cpq_lineitem.CurrencyId, accessToken);
  266. // //USD fields
  267. // if (objDailyExcnageRate != null)
  268. // {
  269. // objResultQuoteLineItem.ext_USDAdjustment = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.Ext_AdjustmentAmount;
  270. // objResultQuoteLineItem.ext_USDBasePrice = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.BasePrice;
  271. // objResultQuoteLineItem.ext_USDTotalValue = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.NetPrice);
  272. // objResultQuoteLineItem.ext_USDListPrice = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.ListPrice);
  273. // objResultQuoteLineItem.ext_USDSalesPrice = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.NetUnitPrice);
  274. // objResultQuoteLineItem.ext_USDAnnualContractValue = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.AnnualContractValue;
  275. // objResultQuoteLineItem.ext_USDAnnualListPrice = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.AnnualListPrice;
  276. // }
  277. // lstResultQuoteLineItem.Add(objResultQuoteLineItem);
  278. // }
  279. // }
  280. // resultQuoteHeaderAndLIneItems.ListQuoteLineItemFinFields = lstResultQuoteLineItem;
  281. // var responseResult = UpdateQuoteLineItems(lstResultQuoteLineItem, accessToken);
  282. // return responseResult;
  283. // }
  284. // else
  285. // {
  286. // HttpResponseMessage jsonResponse = new HttpResponseMessage();
  287. // Model.ErrorInfo errorInfo = new Model.ErrorInfo();
  288. // errorInfo.Message = "Error";
  289. // var dict = new Dictionary<string, object>
  290. // {
  291. // {"Message", "Fail to update records"}
  292. // };
  293. // errorInfo.Record = dict;
  294. // errors.Add(errorInfo);
  295. // Utilities.CreateResponse(jsonResponse, errors);
  296. // return jsonResponse;
  297. // }
  298. // //return response
  299. // }
  300. // catch (Exception ex)
  301. // {
  302. // var resp = new HttpResponseMessage
  303. // {
  304. // Content = new StringContent("Message :" + ex.Message + " " + "StackStrace :" + ex.StackTrace, System.Text.Encoding.UTF8, "application/json"),
  305. // StatusCode = System.Net.HttpStatusCode.BadRequest
  306. // };
  307. // return resp;
  308. // }
  309. //}
  310. #endregion
  311. /// <summary>
  312. /// Calculate financial fields of Quote line items for given QuoteId
  313. /// </summary>
  314. /// <param name="QuoteId"></param>
  315. /// <param name="accessToken"></param>
  316. /// <returns></returns>
  317. public HttpResponseMessage UpdateQuoteLineItemFields(string QuoteId, string accessToken)
  318. {
  319. var errors = new List<Model.ErrorInfo>();
  320. try
  321. {
  322. //Build AQL Query to fetch Quote,Quote Line Items & Product details
  323. var query = new Query(Constants.OBJ_QUOTE);
  324. query.AddColumns(Constants.OBJ_FIELDQUOTELINEITEMFINANCIAL.Split(Constants.CHAR_COMMA));
  325. Expression exp = new Expression(ExpressionOperator.AND);
  326. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  327. query.SetCriteria(exp);
  328. Join quoteLineItem = new Join(Constants.OBJ_QUOTE, Constants.OBJ_CPQ_QUOTELINEITEM, Constants.FIELD_ID, Constants.FIELD_QUOTEID, JoinType.LEFT);
  329. quoteLineItem.EntityAlias = Constants.OBJ_CPQ_QUOTELINEITEM;
  330. query.AddJoin(quoteLineItem);
  331. Join lineItem = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_LINEITEM, Constants.FIELD_DERIVEDFROMId, Constants.FIELD_ID, JoinType.LEFT);
  332. lineItem.EntityAlias = Constants.OBJ_LINEITEM;
  333. query.AddJoin(lineItem);
  334. Join product = new Join(Constants.OBJ_CPQ_QUOTELINEITEM, Constants.OBJ_PRODUCT, Constants.FIELD_PRODUCTID, Constants.FIELD_ID, JoinType.LEFT);
  335. product.EntityAlias = Constants.OBJ_PRODUCT;
  336. query.AddJoin(product);
  337. var jsonQuery = query.Serialize();
  338. var reqConfig = new RequestConfigModel();
  339. reqConfig.accessToken = accessToken;
  340. reqConfig.searchType = SearchType.AQL;
  341. reqConfig.objectName = Constants.OBJ_QUOTE;
  342. var response = Utilities.Search(jsonQuery, reqConfig);
  343. ResultUSDQuoteHeaderLineItemFields resultQuoteHeaderAndLIneItems = new ResultUSDQuoteHeaderLineItemFields();
  344. ResultQuoteHeaderModel resultQuoteHeaderModel = new ResultQuoteHeaderModel();
  345. List<ResultQuoteLineItem> lstResultQuoteLineItem = new List<ResultQuoteLineItem>();
  346. if (response != null && response.IsSuccessStatusCode)
  347. {
  348. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  349. List<QuoteQuoteLineDetails> QuoteLineList = new List<QuoteQuoteLineDetails>();
  350. QuoteLineList = JsonConvert.DeserializeObject<List<QuoteQuoteLineDetails>>(responseString);
  351. if (QuoteLineList != null && QuoteLineList.Count > 0)
  352. {
  353. LineItemRepository lineItemRepo = new LineItemRepository();
  354. //Calculate quote line item USD fields
  355. for (int i = 0; i < QuoteLineList.Count; i++)
  356. {
  357. ResultQuoteLineItem objResultQuoteLineItem = new ResultQuoteLineItem();
  358. objResultQuoteLineItem.Id = QuoteLineList[i].cpq_QuoteLineItem.Id;
  359. objResultQuoteLineItem.ext_ListPriceWithAdjustments = QuoteLineList[i].cpq_QuoteLineItem.BasePrice.ConvertToDecimal();
  360. if (QuoteLineList[i].cpq_QuoteLineItem.ListPrice != 0)
  361. {
  362. objResultQuoteLineItem.ext_AdjustmentAmount = (QuoteLineList[i].cpq_QuoteLineItem.ListPrice.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Quantity2.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Term.ConvertToDecimal()) - QuoteLineList[i].cpq_QuoteLineItem.NetPrice.ConvertToDecimal();
  363. objResultQuoteLineItem.ext_AdjustmentDiscountPercent = objResultQuoteLineItem.ext_AdjustmentAmount * 100 / (QuoteLineList[i].cpq_QuoteLineItem.ListPrice.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Quantity2.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Term.ConvertToDecimal());
  364. }
  365. if (QuoteLineList[i].crm_Product.Family != null && QuoteLineList[i].crm_Product.Family.Value.ConvertToStringNull() != null && QuoteLineList[i].cpq_QuoteLineItem.ProductId.Ext_Family.Value.ToString() != Constants.STR_SUBSCRIPTION)
  366. {
  367. objResultQuoteLineItem.ext_AnnualContractValue = 0;
  368. objResultQuoteLineItem.ext_AnnualListPrice = 0;
  369. }
  370. else
  371. {
  372. if (QuoteLineList[i].cpq_QuoteLineItem.SellingFrequency != null && QuoteLineList[i].cpq_QuoteLineItem.SellingFrequency.ConvertToStringNull() != null && QuoteLineList[i].cpq_QuoteLineItem.SellingFrequency.Value.ToString() == Constants.STR_YEARLY)
  373. {
  374. objResultQuoteLineItem.ext_AnnualContractValue = QuoteLineList[i].cpq_QuoteLineItem.NetUnitPrice.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Quantity2;
  375. objResultQuoteLineItem.ext_AnnualListPrice = QuoteLineList[i].cpq_QuoteLineItem.ListPrice.ConvertToDecimal() * QuoteLineList[i].cpq_QuoteLineItem.Quantity2;
  376. }
  377. else
  378. {
  379. objResultQuoteLineItem.ext_AnnualContractValue = QuoteLineList[i].cpq_QuoteLineItem.NetUnitPrice.ConvertToDecimal() * 12 * QuoteLineList[i].cpq_QuoteLineItem.Quantity2;
  380. objResultQuoteLineItem.ext_AnnualListPrice = QuoteLineList[i].cpq_QuoteLineItem.ListPrice.ConvertToDecimal() * 12 * QuoteLineList[i].cpq_QuoteLineItem.Quantity2;
  381. }
  382. }
  383. objResultQuoteLineItem.ext_EstimatedTax = QuoteLineList[i].cpq_QuoteLineItem.ext_EstimatedTax.ConvertToDecimal();
  384. //Estimated Total: Total Value + EstimatedTax
  385. objResultQuoteLineItem.ext_EstimatedTotal = QuoteLineList[i].cpq_QuoteLineItem.NetPrice.ConvertToDecimal() + objResultQuoteLineItem.ext_EstimatedTax.ConvertToDecimal();
  386. //Sales Price
  387. objResultQuoteLineItem.ext_SalesPrice = QuoteLineList[i].cpq_QuoteLineItem.NetUnitPrice.ConvertToDecimal();
  388. //get daily currenct exchange rates based on currency code
  389. DailyExcnageRate objDailyExcnageRate = lineItemRepo.GetExchangeRateDetails(QuoteLineList[i].cpq_lineitem.CurrencyId, accessToken);
  390. //USD fields
  391. if (objDailyExcnageRate != null)
  392. {
  393. objResultQuoteLineItem.ext_USDAdjustment = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.Ext_AdjustmentAmount.ConvertToDecimal();
  394. objResultQuoteLineItem.ext_USDBasePrice = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.BasePrice.ConvertToDecimal();
  395. objResultQuoteLineItem.ext_USDTotalValue = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.NetPrice.ConvertToDecimal());
  396. objResultQuoteLineItem.ext_USDListPrice = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.ListPrice.ConvertToDecimal());
  397. objResultQuoteLineItem.ext_USDSalesPrice = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.NetUnitPrice.ConvertToDecimal());
  398. objResultQuoteLineItem.ext_USDAnnualContractValue = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.AnnualContractValue.ConvertToDecimal();
  399. objResultQuoteLineItem.ext_USDAnnualListPrice = objDailyExcnageRate.ext_Rate * QuoteLineList[i].cpq_QuoteLineItem.AnnualListPrice.ConvertToDecimal();
  400. }
  401. lstResultQuoteLineItem.Add(objResultQuoteLineItem);
  402. }
  403. }
  404. resultQuoteHeaderAndLIneItems.ListQuoteLineItemFinFields = lstResultQuoteLineItem;
  405. var responseResult = UpdateQuoteLineItems(lstResultQuoteLineItem, accessToken);
  406. return responseResult;
  407. }
  408. else
  409. {
  410. HttpResponseMessage jsonResponse = new HttpResponseMessage();
  411. Model.ErrorInfo errorInfo = new Model.ErrorInfo();
  412. errorInfo.Message = "Error";
  413. var dict = new Dictionary<string, object>
  414. {
  415. {"Message", "Fail to update records"}
  416. };
  417. errorInfo.Record = dict;
  418. errors.Add(errorInfo);
  419. Utilities.CreateResponse(jsonResponse, errors);
  420. return jsonResponse;
  421. }
  422. //return response
  423. }
  424. catch (Exception ex)
  425. {
  426. var resp = new HttpResponseMessage
  427. {
  428. Content = new StringContent("Message :" + ex.Message + " " + "StackStrace :" + ex.StackTrace, System.Text.Encoding.UTF8, "application/json"),
  429. StatusCode = System.Net.HttpStatusCode.BadRequest
  430. };
  431. return resp;
  432. }
  433. }
  434. /// <summary>
  435. /// Update calculated Quote line items details
  436. /// </summary>
  437. /// <param name="lineItems">list of fileds to be update</param>
  438. /// <returns></returns>
  439. public HttpResponseMessage UpdateQuoteLineItems(List<ResultQuoteLineItem> quoteLineItems, string accessToken)
  440. {
  441. var reqConfig = new RequestConfigModel();
  442. reqConfig.accessToken = accessToken;
  443. reqConfig.objectName = Constants.OBJ_CPQ_QUOTELINEITEM;
  444. var lstLineItemsToUpdate = new List<dynamic>();
  445. foreach (var lstLineItems in quoteLineItems)
  446. {
  447. lstLineItemsToUpdate.Add(new
  448. {
  449. Id = lstLineItems.Id,
  450. ext_ListPriceWithAdjustments = lstLineItems.ext_ListPriceWithAdjustments,
  451. ext_AdjustmentAmount = lstLineItems.ext_AdjustmentAmount,
  452. ext_AdjustmentDiscountPercent = lstLineItems.ext_AdjustmentDiscountPercent,
  453. ext_EstimatedTax = lstLineItems.ext_EstimatedTax,
  454. ext_AnnualContractValue = lstLineItems.ext_AnnualContractValue,
  455. ext_AnnualListPrice = lstLineItems.ext_AnnualListPrice,
  456. ext_EstimatedTotal = lstLineItems.ext_EstimatedTotal,
  457. ext_SalesPrice = lstLineItems.ext_SalesPrice,
  458. ext_USDAdjustment = lstLineItems.ext_USDAdjustment,
  459. ext_USDBasePrice = lstLineItems.ext_USDBasePrice,
  460. ext_USDTotalValue = lstLineItems.ext_USDTotalValue,
  461. ext_USDListPrice = lstLineItems.ext_USDListPrice,
  462. ext_USDSalesPrice = lstLineItems.ext_USDSalesPrice,
  463. ext_USDAnnualContractValue = lstLineItems.ext_USDAnnualContractValue,
  464. ext_USDAnnualListPrice = lstLineItems.ext_USDAnnualListPrice,
  465. });
  466. }
  467. var responseString = Utilities.Update(lstLineItemsToUpdate, reqConfig);
  468. return responseString;
  469. }
  470. /// <summary>
  471. /// Default quote details based on rule conditions
  472. /// </summary>
  473. /// <param name="QuoteId"></param>
  474. /// <param name="accessToken"></param>
  475. /// <returns></returns>
  476. public HttpResponseMessage DefaultQuoteDetails(string QuoteId, string accessToken)
  477. {
  478. try
  479. {
  480. //Build AQL Query to fetch Quote's opprtunityID
  481. var updateResult = new HttpResponseMessage();
  482. var query = new Query(Constants.OBJ_QUOTE);
  483. query.AddColumns(Constants.OBJ_QUOTEVALIDATE_DEFAULT_SELECTFIELD.Split(Constants.CHAR_COMMA));
  484. Expression exp = new Expression(ExpressionOperator.AND);
  485. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  486. Join account = new Join(Constants.OBJ_QUOTE, Constants.OBJ_ACCOUNT, Constants.FIELD_ACCOUNTID, Constants.FIELD_ID, JoinType.LEFT);
  487. account.EntityAlias = Constants.OBJ_ACCOUNT;
  488. query.AddJoin(account);
  489. query.SetCriteria(exp);
  490. var jsonQuery = query.Serialize();
  491. var reqConfig = new RequestConfigModel();
  492. reqConfig.accessToken = accessToken;
  493. reqConfig.searchType = SearchType.AQL;
  494. reqConfig.objectName = Constants.OBJ_QUOTE;
  495. var response = Utilities.Search(jsonQuery, reqConfig);
  496. ValidateDefaultQuoteResult objValidateDefaultQuoteResult = new ValidateDefaultQuoteResult();
  497. List<Dictionary<string, object>> ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  498. if (response != null && response.IsSuccessStatusCode)
  499. {
  500. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  501. List<QuoteValidate> objQuoteOppoDetails = new List<QuoteValidate>();
  502. objQuoteOppoDetails = JsonConvert.DeserializeObject<List<QuoteValidate>>(responseString);
  503. if (objQuoteOppoDetails != null && objQuoteOppoDetails.Count > 0)
  504. {
  505. #region "Set default data center based on Country"
  506. if (objQuoteOppoDetails.FirstOrDefault().crm_Account != null && objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country != null)
  507. {
  508. #region get country and data center mapping data from xml file
  509. Dictionary<string, string> countryDCDict = new Dictionary<string, string>();
  510. string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"XMLFiles\DataCenterCountryMapping.xml");
  511. XDocument XDoc = XDocument.Load(path);
  512. try
  513. {
  514. countryDCDict = XDoc.Descendants("Country").ToDictionary(d => (string)d.Attribute("Name"), d => (string)d);
  515. if (countryDCDict.ContainsKey(objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country))
  516. {
  517. objValidateDefaultQuoteResult.ext_datacenter = countryDCDict[objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country];
  518. }
  519. else
  520. { //setting default data center to United States
  521. objValidateDefaultQuoteResult.ext_datacenter = countryDCDict[Constants.STR_UNITEDSTATES];
  522. }
  523. }
  524. catch (Exception ex)
  525. {
  526. objValidateDefaultQuoteResult.ErrorMessage = "DataCenterCountryMapping :" + ex.Message;
  527. }
  528. #endregion
  529. }
  530. #endregion
  531. #region "Set Selling entity"
  532. if (objQuoteOppoDetails.FirstOrDefault().crm_Account != null && objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country != null)
  533. {
  534. #region get country and selling entity mapping data from xml file
  535. Dictionary<string, string> countryDCDict = new Dictionary<string, string>();
  536. string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"XMLFiles\CountryandSellingEntityMapping.xml");
  537. XDocument XDoc = XDocument.Load(path);
  538. try
  539. {
  540. countryDCDict = XDoc.Descendants("Country").ToDictionary(d => (string)d.Attribute("Name"), d => (string)d);
  541. if (countryDCDict.ContainsKey(objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country))
  542. {
  543. objValidateDefaultQuoteResult.ext_SellingEntity = countryDCDict[objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country];
  544. }
  545. else
  546. {
  547. objValidateDefaultQuoteResult.ext_SellingEntity = countryDCDict[Constants.STR_NEDERLAND];
  548. }
  549. }
  550. catch (Exception ex)
  551. {
  552. objValidateDefaultQuoteResult.ErrorMessage += " CountryandSellingEntityMapping :" + ex.Message;
  553. }
  554. #endregion
  555. }
  556. #endregion
  557. #region "Set PriceList based on currency and vice versa"
  558. //Build AQL Query to fetch pricelist details
  559. var priceListId = objQuoteOppoDetails.FirstOrDefault().PriceListId != null ? objQuoteOppoDetails.FirstOrDefault().PriceListId.Id : null;
  560. if (!string.IsNullOrEmpty(priceListId))
  561. {
  562. var queryPricelist = new Query(Constants.OBJ_PRICELIST);
  563. queryPricelist.AddColumns(Constants.OBJ_PRICELIST_SELECTFIELD.Split(Constants.CHAR_COMMA));
  564. Expression expPriceList = new Expression(ExpressionOperator.AND);
  565. expPriceList.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, priceListId));
  566. queryPricelist.SetCriteria(expPriceList);
  567. jsonQuery = queryPricelist.Serialize();
  568. reqConfig = new RequestConfigModel();
  569. reqConfig.accessToken = accessToken;
  570. reqConfig.searchType = SearchType.AQL;
  571. reqConfig.objectName = Constants.OBJ_PRICELIST;
  572. var responsePricelistDetail = Utilities.Search(jsonQuery, reqConfig);
  573. if (responsePricelistDetail != null && responsePricelistDetail.IsSuccessStatusCode)
  574. {
  575. var responsePriceListString = JObject.Parse(responsePricelistDetail.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  576. List<QQuoteLineItem> objPriceListResult = new List<QQuoteLineItem>();
  577. objPriceListResult = JsonConvert.DeserializeObject<List<QQuoteLineItem>>(responsePriceListString);
  578. if (objPriceListResult != null && objPriceListResult.Count > 0)
  579. {
  580. if (!string.IsNullOrEmpty(objPriceListResult.FirstOrDefault().CurrencyId))
  581. {
  582. objValidateDefaultQuoteResult.BaseCurrency = objPriceListResult.FirstOrDefault().CurrencyId;
  583. }
  584. }
  585. }
  586. }
  587. // PricelistId will be null when Quote is created outside Apttus
  588. if (!string.IsNullOrEmpty(objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency) && string.IsNullOrEmpty(priceListId))
  589. {
  590. if (objQuoteOppoDetails.FirstOrDefault().ext_Type.Value.ToLower() == Constants.SERVICES || objQuoteOppoDetails.FirstOrDefault().ext_Type.Value.ToLower() == Constants.STR_TRAINING.ToLower())
  591. {
  592. #region get Currency and Pricelist mapping data from xml file for Services
  593. Dictionary<string, string> currencyDCDict = new Dictionary<string, string>();
  594. string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"XMLFiles\CurrencyandPriceListMappingServices.xml");
  595. XDocument XDoc = XDocument.Load(path);
  596. try
  597. {
  598. currencyDCDict = XDoc.Descendants("Currency").ToDictionary(d => (string)d.Attribute("Name"), d => (string)d);
  599. if (currencyDCDict.ContainsKey(objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency))
  600. {
  601. objValidateDefaultQuoteResult.PriceListName = currencyDCDict[objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency];
  602. if (objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency == Constants.STR_USD)
  603. {
  604. if (objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country == Constants.STR_AUSTRALIA)
  605. {
  606. objValidateDefaultQuoteResult.PriceListName = "Australian (USD) Services";
  607. }
  608. else if (objQuoteOppoDetails.FirstOrDefault().crm_Account.ext_Country == Constants.STR_JAPAN)
  609. {
  610. objValidateDefaultQuoteResult.PriceListName = "Japan (USD) Subscription";
  611. }
  612. }
  613. }
  614. else
  615. {
  616. objValidateDefaultQuoteResult.PriceListName = currencyDCDict[Constants.STR_USD];
  617. }
  618. }
  619. catch (Exception ex)
  620. {
  621. objValidateDefaultQuoteResult.ErrorMessage += " CurrencyandPriceListMappingServices :" + ex.Message;
  622. }
  623. #endregion
  624. }
  625. else// Remaining types will be for Subscription
  626. {
  627. #region get Currency and Pricelist mapping data from xml file for Subscription
  628. Dictionary<string, string> currencyDCDict = new Dictionary<string, string>();
  629. string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"XMLFiles\CurrencyandPriceListMapping.xml");
  630. XDocument XDoc = XDocument.Load(path);
  631. try
  632. {
  633. currencyDCDict = XDoc.Descendants("Currency").ToDictionary(d => (string)d.Attribute("Name"), d => (string)d);
  634. if (currencyDCDict.ContainsKey(objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency))
  635. {
  636. objValidateDefaultQuoteResult.PriceListName = currencyDCDict[objQuoteOppoDetails.FirstOrDefault().ext_BaseCurrency];
  637. }
  638. else
  639. {
  640. objValidateDefaultQuoteResult.PriceListName = currencyDCDict[Constants.STR_USD];
  641. }
  642. }
  643. catch (Exception ex)
  644. {
  645. objValidateDefaultQuoteResult.ErrorMessage += " CurrencyandPriceListMapping :" + ex.Message;
  646. }
  647. #endregion
  648. }
  649. }
  650. #endregion
  651. //Update Quote fileds to default values
  652. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  653. Dictionary<string, object> QuoteFieldToUpdate = new Dictionary<string, object>();
  654. QuoteFieldToUpdate.Add("Id", QuoteId);
  655. if (!string.IsNullOrEmpty(objValidateDefaultQuoteResult.ext_datacenter))
  656. {
  657. QuoteFieldToUpdate.Add("ext_datacenter", objValidateDefaultQuoteResult.ext_datacenter);
  658. }
  659. if (!string.IsNullOrEmpty(objValidateDefaultQuoteResult.ext_SellingEntity))
  660. {
  661. //Build AQL Query to fetch Account details
  662. var queryQuote = new Query(Constants.OBJ_ACCOUNT);
  663. queryQuote.AddColumns(Constants.OBJ_ACCOUNT_SELECTFIELD.Split(Constants.CHAR_COMMA));
  664. Expression expQuote = new Expression(ExpressionOperator.AND);
  665. expQuote.AddCondition(new Condition(Constants.FIELD_NAME, FilterOperator.Equal, objValidateDefaultQuoteResult.ext_SellingEntity));
  666. queryQuote.SetCriteria(expQuote);
  667. jsonQuery = queryQuote.Serialize();
  668. reqConfig = new RequestConfigModel();
  669. reqConfig.accessToken = accessToken;
  670. reqConfig.searchType = SearchType.AQL;
  671. reqConfig.objectName = Constants.OBJ_ACCOUNT;
  672. var responseAccountDetail = Utilities.Search(jsonQuery, reqConfig);
  673. if (responseAccountDetail != null && responseAccountDetail.IsSuccessStatusCode)
  674. {
  675. var responseAccountString = JObject.Parse(responseAccountDetail.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  676. List<AccountCountry> objAccountResult = new List<AccountCountry>();
  677. objAccountResult = JsonConvert.DeserializeObject<List<AccountCountry>>(responseAccountString);
  678. if (objAccountResult != null && objAccountResult.Count > 0)
  679. {
  680. Dictionary<string, object> dictAccount = new Dictionary<string, object>();
  681. dictAccount.Add("Id", objAccountResult.FirstOrDefault().Id);
  682. dictAccount.Add("Name", objAccountResult.FirstOrDefault().Name);
  683. QuoteFieldToUpdate.Add("ext_SellingEntity", dictAccount);
  684. }
  685. }
  686. }
  687. if (!string.IsNullOrEmpty(objValidateDefaultQuoteResult.PriceListName))
  688. {
  689. //Build AQL Query to fetch Account details
  690. var queryPriceList = new Query(Constants.OBJ_PRICELIST);
  691. queryPriceList.AddColumns(Constants.OBJ_PRICELIST_SELECTFIELD.Split(Constants.CHAR_COMMA));
  692. Expression expPriceLIst = new Expression(ExpressionOperator.AND);
  693. expPriceLIst.AddCondition(new Condition(Constants.FIELD_NAME, FilterOperator.Equal, objValidateDefaultQuoteResult.PriceListName));
  694. queryPriceList.SetCriteria(expPriceLIst);
  695. jsonQuery = queryPriceList.Serialize();
  696. reqConfig = new RequestConfigModel();
  697. reqConfig.accessToken = accessToken;
  698. reqConfig.searchType = SearchType.AQL;
  699. reqConfig.objectName = Constants.OBJ_PRICELIST;
  700. var responsePricelistDetail = Utilities.Search(jsonQuery, reqConfig);
  701. if (responsePricelistDetail != null && responsePricelistDetail.IsSuccessStatusCode)
  702. {
  703. var responsePricelistString = JObject.Parse(responsePricelistDetail.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  704. List<LookUp> objPriceListResult = new List<LookUp>();
  705. objPriceListResult = JsonConvert.DeserializeObject<List<LookUp>>(responsePricelistString);
  706. if (objPriceListResult != null && objPriceListResult.Count > 0)
  707. {
  708. Dictionary<string, object> dictAccount = new Dictionary<string, object>();
  709. dictAccount.Add("Id", objPriceListResult.FirstOrDefault().Id);
  710. dictAccount.Add("Name", objPriceListResult.FirstOrDefault().Name);
  711. QuoteFieldToUpdate.Add("PriceListId", dictAccount);
  712. }
  713. }
  714. }
  715. if (!string.IsNullOrEmpty(objValidateDefaultQuoteResult.BaseCurrency))
  716. {
  717. QuoteFieldToUpdate.Add("ext_BaseCurrency", objValidateDefaultQuoteResult.BaseCurrency);
  718. }
  719. #region "Set Sales Partner"
  720. //Build AQL Query to fetch Sales Partner Account details
  721. if (objQuoteOppoDetails.Count > 0 && objQuoteOppoDetails.FirstOrDefault().ext_PartnerAccountMDMID != null)
  722. {
  723. var querySalesParnterAccount = new Query(Constants.OBJ_ACCOUNT);
  724. querySalesParnterAccount.AddColumns(Constants.OBJ_ACCOUNT_SELECTFIELD.Split(Constants.CHAR_COMMA));
  725. Expression expSalesPartner = new Expression(ExpressionOperator.AND);
  726. expSalesPartner.AddCondition(new Condition(Constants.FIELD_EXTERNALID, FilterOperator.Equal, objQuoteOppoDetails.FirstOrDefault().ext_PartnerAccountMDMID));
  727. querySalesParnterAccount.SetCriteria(expSalesPartner);
  728. jsonQuery = querySalesParnterAccount.Serialize();
  729. reqConfig = new RequestConfigModel();
  730. reqConfig.accessToken = accessToken;
  731. reqConfig.searchType = SearchType.AQL;
  732. reqConfig.objectName = Constants.OBJ_ACCOUNT;
  733. var responseSalesParnterAccountDetail = Utilities.Search(jsonQuery, reqConfig);
  734. if (responseSalesParnterAccountDetail != null && responseSalesParnterAccountDetail.IsSuccessStatusCode)
  735. {
  736. var responseAccountString = JObject.Parse(responseSalesParnterAccountDetail.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  737. List<AccountCountry> objAccountResult = new List<AccountCountry>();
  738. objAccountResult = JsonConvert.DeserializeObject<List<AccountCountry>>(responseAccountString);
  739. if (objAccountResult != null && objAccountResult.Count > 0)
  740. {
  741. Dictionary<string, object> dictAccount = new Dictionary<string, object>();
  742. dictAccount.Add("Id", objAccountResult.FirstOrDefault().Id);
  743. dictAccount.Add("Name", objAccountResult.FirstOrDefault().Name);
  744. QuoteFieldToUpdate.Add("ext_SalesPartner", dictAccount);
  745. }
  746. }
  747. }
  748. #endregion
  749. ListQuoteFieldToUpdate.Add(QuoteFieldToUpdate);
  750. updateResult = UpdateQuoteIsPrimary(ListQuoteFieldToUpdate, accessToken);
  751. }
  752. }
  753. if (updateResult.IsSuccessStatusCode)
  754. {//Create response message
  755. var resp = new HttpResponseMessage
  756. {
  757. Content = new StringContent(JsonConvert.SerializeObject(objValidateDefaultQuoteResult), System.Text.Encoding.UTF8, "application/json"),
  758. StatusCode = System.Net.HttpStatusCode.OK
  759. };
  760. return resp;
  761. }
  762. else
  763. {
  764. return updateResult;
  765. }
  766. }
  767. catch (Exception ex)
  768. {
  769. var resp = new HttpResponseMessage
  770. {
  771. Content = new StringContent("Message :" + ex.Message + " " + "StackStrace :" + ex.StackTrace, System.Text.Encoding.UTF8, "application/json"),
  772. StatusCode = System.Net.HttpStatusCode.BadRequest
  773. };
  774. return resp;
  775. }
  776. }
  777. /// <summary>
  778. /// Validate Quote details
  779. /// </summary>
  780. /// <param name="QuoteId"></param>
  781. /// <param name="setIsPrimary"></param>
  782. /// <param name="accessToken"></param>
  783. /// <returns></returns>
  784. public HttpResponseMessage ValidateQuoteDetails(string QuoteId, bool setIsPrimary, string accessToken)
  785. {
  786. try
  787. {
  788. //Build AQL Query to fetch Quote's opprtunityID
  789. var updateResult = new HttpResponseMessage();
  790. var query = new Query(Constants.OBJ_QUOTE);
  791. query.AddColumns(Constants.OBJ_QUOTEVALIDATE_DEFAULT_SELECTFIELD.Split(Constants.CHAR_COMMA));
  792. Expression exp = new Expression(ExpressionOperator.AND);
  793. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  794. Join account = new Join(Constants.OBJ_QUOTE, Constants.OBJ_ACCOUNT, Constants.FIELD_ACCOUNTID, Constants.FIELD_ID, JoinType.LEFT);
  795. account.EntityAlias = Constants.OBJ_ACCOUNT;
  796. query.AddJoin(account);
  797. query.SetCriteria(exp);
  798. var jsonQuery = query.Serialize();
  799. var reqConfig = new RequestConfigModel();
  800. reqConfig.accessToken = accessToken;
  801. reqConfig.searchType = SearchType.AQL;
  802. reqConfig.objectName = Constants.OBJ_QUOTE;
  803. var response = Utilities.Search(jsonQuery, reqConfig);
  804. ValidateDefaultQuoteResult objValidateDefaultQuoteResult = new ValidateDefaultQuoteResult();
  805. List<Dictionary<string, object>> ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  806. if (response != null && response.IsSuccessStatusCode)
  807. {
  808. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  809. List<QuoteValidate> objQuoteOppoDetails = new List<QuoteValidate>();
  810. objQuoteOppoDetails = JsonConvert.DeserializeObject<List<QuoteValidate>>(responseString);
  811. if (objQuoteOppoDetails != null && objQuoteOppoDetails.Count > 0)
  812. {
  813. #region "Validate and Set IsPrimary true for only current Quote"
  814. //Validate all quotes for an opportunity and update current Quote IsPrimary field set to true and rest of the Quotes IsPrimary will be set to false.
  815. if (objQuoteOppoDetails.FirstOrDefault().IsPrimary != null)
  816. {
  817. setIsPrimary = Convert.ToBoolean(ConversionHelper.ConvertToBool(objQuoteOppoDetails.FirstOrDefault().IsPrimary));
  818. }
  819. else
  820. {
  821. setIsPrimary = false;
  822. }
  823. if (setIsPrimary && objQuoteOppoDetails.FirstOrDefault().ext_OpportunitySysId != null)
  824. {
  825. //Build AQL Query to fetch all quotes of opprtunityID
  826. var queryQuote = new Query(Constants.OBJ_QUOTE);
  827. queryQuote.AddColumns(Constants.OBJ_QUOTEOPPORTUNITY_SELECTFIELD.Split(Constants.CHAR_COMMA));
  828. Expression expQuote = new Expression(ExpressionOperator.AND);
  829. expQuote.AddCondition(new Condition(Constants.FIELD_OPPORTUNITYSYSID, FilterOperator.Equal, objQuoteOppoDetails[0].ext_OpportunitySysId));
  830. queryQuote.SetCriteria(expQuote);
  831. jsonQuery = queryQuote.Serialize();
  832. reqConfig = new RequestConfigModel();
  833. reqConfig.accessToken = accessToken;
  834. reqConfig.searchType = SearchType.AQL;
  835. reqConfig.objectName = Constants.OBJ_QUOTE;
  836. var responseQuotewithOppo = Utilities.Search(jsonQuery, reqConfig);
  837. if (responseQuotewithOppo != null && responseQuotewithOppo.IsSuccessStatusCode)
  838. {
  839. var responseQuotewithOppoString = JObject.Parse(responseQuotewithOppo.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  840. List<QuoteValidate> objQuoteOppoResult = new List<QuoteValidate>();
  841. objQuoteOppoResult = JsonConvert.DeserializeObject<List<QuoteValidate>>(responseQuotewithOppoString);
  842. //Check for any other Quote is set to IsPrimary to true
  843. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  844. Dictionary<string, object> QuoteFieldToUpdate = new Dictionary<string, object>();
  845. var otherQuoteIsPrimary = objQuoteOppoResult.Where(x => x.Id != QuoteId && x.IsPrimary == true);
  846. if (otherQuoteIsPrimary != null && otherQuoteIsPrimary.Count() > 0)
  847. {
  848. //Set any other Quotes IsPrimary value to false
  849. foreach (var item in otherQuoteIsPrimary)
  850. {
  851. QuoteFieldToUpdate = new Dictionary<string, object>();
  852. QuoteFieldToUpdate.Add("Id", item.Id);
  853. QuoteFieldToUpdate.Add("IsPrimary", false);
  854. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  855. ListQuoteFieldToUpdate.Add(QuoteFieldToUpdate);
  856. UpdateQuoteIsPrimary(ListQuoteFieldToUpdate, accessToken);
  857. }
  858. }
  859. //Update only current Quote as IsPrimary true
  860. QuoteFieldToUpdate = new Dictionary<string, object>();
  861. QuoteFieldToUpdate.Add("Id", QuoteId);
  862. QuoteFieldToUpdate.Add("IsPrimary", true);
  863. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  864. ListQuoteFieldToUpdate.Add(QuoteFieldToUpdate);
  865. updateResult = UpdateQuoteIsPrimary(ListQuoteFieldToUpdate, accessToken);
  866. objValidateDefaultQuoteResult.IsPrimarySet = updateResult.IsSuccessStatusCode;
  867. }
  868. }
  869. #endregion
  870. #region "Currency Based on pricing"
  871. if (objQuoteOppoDetails.Count > 0 && objQuoteOppoDetails.FirstOrDefault().PriceListId != null)
  872. {
  873. var queryPriceListCurrency = new Query(Constants.OBJ_PRICELIST);
  874. queryPriceListCurrency.AddColumns(Constants.OBJ_PRICELIST_SELECTFIELD.Split(Constants.CHAR_COMMA));
  875. Expression expPriceListCurrency = new Expression(ExpressionOperator.AND);
  876. expPriceListCurrency.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, objQuoteOppoDetails.FirstOrDefault().PriceListId.Id));
  877. queryPriceListCurrency.SetCriteria(expPriceListCurrency);
  878. jsonQuery = queryPriceListCurrency.Serialize();
  879. reqConfig = new RequestConfigModel();
  880. reqConfig.accessToken = accessToken;
  881. reqConfig.searchType = SearchType.AQL;
  882. reqConfig.objectName = Constants.OBJ_PRICELIST;
  883. var responsePricelistCurrencyDetail = Utilities.Search(jsonQuery, reqConfig);
  884. if (responsePricelistCurrencyDetail != null && responsePricelistCurrencyDetail.IsSuccessStatusCode)
  885. {
  886. var responsePricelistString = JObject.Parse(responsePricelistCurrencyDetail.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  887. List<QQuoteLineItem> objPriceListResult = new List<QQuoteLineItem>();
  888. objPriceListResult = JsonConvert.DeserializeObject<List<QQuoteLineItem>>(responsePricelistString);
  889. if (objPriceListResult != null && objPriceListResult.Count > 0)
  890. {
  891. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  892. Dictionary<string, object> QuoteFieldToUpdate = new Dictionary<string, object>();
  893. QuoteFieldToUpdate = new Dictionary<string, object>();
  894. QuoteFieldToUpdate.Add("Id", QuoteId);
  895. QuoteFieldToUpdate.Add("ext_BaseCurrency", Convert.ToString(objPriceListResult.FirstOrDefault().CurrencyId));
  896. ListQuoteFieldToUpdate = new List<Dictionary<string, object>>();
  897. ListQuoteFieldToUpdate.Add(QuoteFieldToUpdate);
  898. updateResult = UpdateQuoteIsPrimary(ListQuoteFieldToUpdate, accessToken);
  899. //objValidateDefaultQuoteResult.IsPrimarySet = updateResult.IsSuccessStatusCode;
  900. }
  901. }
  902. }
  903. #endregion
  904. }
  905. }
  906. return updateResult;
  907. }
  908. catch (Exception ex)
  909. {
  910. var resp = new HttpResponseMessage
  911. {
  912. Content = new StringContent("Message :" + ex.Message + " " + "StackStrace :" + ex.StackTrace, System.Text.Encoding.UTF8, "application/json"),
  913. StatusCode = System.Net.HttpStatusCode.BadRequest
  914. };
  915. return resp;
  916. }
  917. }
  918. /// <summary>
  919. /// To update IsPrimary field of Quote
  920. /// </summary>
  921. /// <param name="quoteHeaderList"></param>
  922. /// <param name="accessToken"></param>
  923. /// <returns></returns>
  924. public HttpResponseMessage UpdateQuoteIsPrimary(List<Dictionary<string, object>> quoteHeaderList, string accessToken)
  925. {
  926. var reqConfig = new RequestConfigModel();
  927. reqConfig.accessToken = accessToken;
  928. reqConfig.objectName = Constants.OBJ_QUOTE;
  929. var responseString = Utilities.Update(quoteHeaderList, reqConfig);
  930. return responseString;
  931. }
  932. #region Approvals On Quote
  933. /// <summary>
  934. /// Get, Calculate and update Approval Fields
  935. /// </summary>
  936. /// <param name="QuoteId"></param>
  937. /// <param name="accessToken"></param>
  938. /// <returns></returns>
  939. public HttpResponseMessage CalculateApprovalFields(string QuoteId, string accessToken)
  940. {
  941. try
  942. {
  943. //Build AQL Query to fetch Quote's opprtunityID
  944. var updateResult = new HttpResponseMessage();
  945. var query = new Query(Constants.OBJ_QUOTE);
  946. query.AddColumns(Constants.OBJ_APPROVALCALCULATION_DEFAULT_SELECTFIELDS.Split(Constants.CHAR_COMMA));
  947. Expression exp = new Expression(ExpressionOperator.AND);
  948. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  949. query.SetCriteria(exp);
  950. Join quoteLineItem = new Join(Constants.OBJ_QUOTE, Constants.OBJ_CPQ_QUOTELINEITEM, Constants.FIELD_ID, Constants.FIELD_QUOTEID, JoinType.LEFT, Constants.OBJALIAS_QUOTELINEITEM);
  951. query.AddJoin(quoteLineItem);
  952. Join agreement = new Join(Constants.OBJ_QUOTE, Constants.OBJ_AGREEMENT, Constants.FIELD_EXT_REFAGREEMENT, Constants.FIELD_ID, JoinType.LEFT, Constants.OBJALIAS_AGREEMENT);
  953. query.AddJoin(agreement);
  954. var jsonQuery = query.Serialize();
  955. var reqConfig = new RequestConfigModel()
  956. {
  957. accessToken = accessToken,
  958. searchType = SearchType.AQL,
  959. objectName = Constants.OBJ_QUOTE
  960. };
  961. var response = Utilities.Search(jsonQuery, reqConfig);
  962. if (response != null && response.IsSuccessStatusCode)
  963. {
  964. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  965. var quoteDetails = JsonConvert.DeserializeObject<List<QuoteResponseApproval>>(responseString);
  966. if (quoteDetails != null && quoteDetails.Count() > 0)
  967. {
  968. //Inialize variables
  969. double ext_DealSize = 0.0;
  970. decimal ext_MaxDiscount = 0.0m;
  971. int ext_RenewalCount = 0;
  972. bool ext_ApproverUserDiscount = false;
  973. bool ext_CustomerSatisfactionException = false;
  974. bool ext_EndOfLifeProducts = false;
  975. //Logic to update Approval Fields
  976. DealSizeCalculation(quoteDetails, ref ext_DealSize, accessToken);
  977. MaxDiscountCalculation(quoteDetails, ref ext_MaxDiscount);
  978. RenewalCountCalculation(quoteDetails, ref ext_RenewalCount);
  979. ApproverUserDiscountCalculation(quoteDetails, ref ext_ApproverUserDiscount);
  980. CustomerSatisfactionExceptionApprovalCalculation(quoteDetails, ref ext_CustomerSatisfactionException);
  981. EndOfLifeProductsApprovalCalculation(quoteDetails, ref ext_EndOfLifeProducts);
  982. //Add all approval fields into dictionary
  983. var QuoteFieldToUpdate = new Dictionary<string, object>
  984. {
  985. { "Id", QuoteId },
  986. { "ext_DealSize", ext_DealSize },
  987. { "ext_MaxDiscount", ext_MaxDiscount },
  988. { "ext_RenewalCount", ext_RenewalCount },
  989. { "ext_ApproverUserDiscount", ext_ApproverUserDiscount },
  990. { "ext_EndOfLifeProductsApproval", ext_EndOfLifeProducts },
  991. { "ext_CustomerSatisfactionExceptionApproval", ext_MaxDiscount }
  992. };
  993. //Update fields via API
  994. updateResult = UpdateQuoteWithApprovalFields(new List<Dictionary<string, object>>() { QuoteFieldToUpdate }, accessToken);
  995. }
  996. }
  997. return updateResult;
  998. }
  999. catch (Exception ex)
  1000. {
  1001. //TODO
  1002. throw;
  1003. }
  1004. }
  1005. /// <summary>
  1006. /// Deal size calculation
  1007. /// </summary>
  1008. /// <param name="quoteDetails"></param>
  1009. /// <param name="ext_DealSize"></param>
  1010. /// <returns></returns>
  1011. private void DealSizeCalculation(List<QuoteResponseApproval> quoteDetails, ref double ext_DealSize, string accessToken)
  1012. {
  1013. // Get subscription products
  1014. var subscriptionFamilyQuoteDetails = quoteDetails.Where(q => q.QLI.ProductId.ext_Family != null && q.QLI.ProductId.ext_Family.Key.ConvertToStringNull() == Constants.STR_PRODUCT_FAMILY_SUBSCRIPTIONS).ToList();
  1015. // New Business
  1016. if (quoteDetails.Where(q => q.ext_Type.ConvertToStringNull() != null && q.ext_Type.Key.ConvertToStringNull() != null && q.ext_Type.Key == Enums.QuoteType.NewBusiness.GetEnumDisplayName()).Count() > 0)
  1017. {
  1018. // A field on Quote Header.Rollup of USD Annual List Price of all the subscription products in the cart.
  1019. ext_DealSize = subscriptionFamilyQuoteDetails.Sum(s => s.QLI.ext_USDAnnualListPrice.ConvertToDouble());
  1020. }
  1021. // Upsell
  1022. if (quoteDetails.Where(q => !string.IsNullOrEmpty(q.ext_Type.Key) && q.ext_Type.Key == Enums.QuoteType.LicenseUpsell.GetEnumDisplayName()).Count() > 0)
  1023. {
  1024. //USD Total Annual List Price = Total Annual List Value from the agreement
  1025. ext_DealSize = quoteDetails.First().AGR.ext_QuoteId.ext_DealSize.ConvertToDouble();
  1026. //Calculate rollup of USD Annual List Price of all the subscription products in the cart
  1027. var rollUpUSDAnnualListPrice = 0.0;
  1028. //objResultQuoteLineItem.ext_USDListPrice = objDailyExcnageRate.ext_Rate * (QuoteLineList[i].cpq_QuoteLineItem.BasePrice); //To Do: Replace 'BasePrice' with 'ListPrice' while calculating QLI.ext_USDListPrice!!
  1029. subscriptionFamilyQuoteDetails.ForEach(p => rollUpUSDAnnualListPrice += (p.QLI.ext_USDListPrice.ConvertToDouble() * p.QLI.ext_ContractQuantity.ConvertToDouble()));
  1030. // Total Deal Size = Previous value(Agreement's DealSize) + ollup of USD Annual List Price of all the subscription products
  1031. ext_DealSize += rollUpUSDAnnualListPrice;
  1032. }
  1033. }
  1034. /// <summary>
  1035. /// Max Discount Calculation
  1036. /// </summary>
  1037. /// <param name="quoteDetails"></param>
  1038. /// <param name="ext_MaxDiscount"></param>
  1039. /// <returns></returns>
  1040. private void MaxDiscountCalculation(List<QuoteResponseApproval> quoteDetails, ref decimal ext_MaxDiscount)
  1041. {
  1042. var quoteType = quoteDetails.First().ext_Type?.Key.ConvertToStringNull();
  1043. var salesType = quoteDetails.First().ext_salestype?.Key.ConvertToStringNull();
  1044. if ((quoteType == Enums.QuoteType.NewBusiness.GetEnumDisplayName() || quoteType == Enums.QuoteType.LicenseUpsell.GetEnumDisplayName())
  1045. && (salesType == "Direct" || salesType == "InDirect"))
  1046. {
  1047. // Maximum % of all the discounts on line item.
  1048. ext_MaxDiscount = quoteDetails.Max(s => (s.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal()));
  1049. }
  1050. }
  1051. /// <summary>
  1052. /// Renewal count calculations
  1053. /// </summary>
  1054. /// <param name="quoteDetails"></param>
  1055. /// <param name="ext_RenewalCount"></param>
  1056. /// <returns></returns>
  1057. private void RenewalCountCalculation(List<QuoteResponseApproval> quoteDetails, ref int ext_RenewalCount)
  1058. {
  1059. // ext_AdjustmentDiscountPercent Renewal Count -If this.proposal has a previous proposal ( another field on quote ) and that previous proposal doesnt have any predecessor, the count will be calculated as 1.
  1060. var quote = quoteDetails.First();
  1061. if (quote.ext_Type != null && quote.ext_Type.Key.ConvertToStringNull() != null && quote.ext_Type.Key == "Renewal" && quote.AGR != null && quote.AGR.ext_QuoteId != null && quote.AGR.ext_QuoteId.Id.ConvertToString() != null)
  1062. {
  1063. ext_RenewalCount = 1;
  1064. }
  1065. }
  1066. /// <summary>
  1067. /// Approver User Discount Calculation
  1068. /// </summary>
  1069. /// <param name="quoteDetails"></param>
  1070. /// <param name="ext_ApproverUserDiscount"></param>
  1071. /// <returns></returns>
  1072. private void ApproverUserDiscountCalculation(List<QuoteResponseApproval> quoteDetails, ref bool ext_ApproverUserDiscount)
  1073. {
  1074. // For Direct Sale
  1075. if (quoteDetails.Where(q => q.ext_salestype != null && q.ext_salestype.Key.ConvertToStringNull() != null && q.ext_salestype.Key.Equals("Direct")).Count() > 0)
  1076. {
  1077. ext_ApproverUserDiscount = ((quoteDetails.Where(q => q.ext_salestype != null && q.ext_salestype.Key.ConvertToStringNull() != null && q.ext_salestype.Key == "Direct"
  1078. && q.QLI.AttributeValueId.ext_UserModel != null && q.QLI.AttributeValueId.ext_UserModel.Key.ConvertToStringNull() != null && q.QLI.AttributeValueId.ext_UserModel.Key == "Approver User"
  1079. && q.AccountId.ext_Segment != null && q.AccountId.ext_Segment.Key.ConvertToStringNull() != null && (q.AccountId.ext_Segment.Key.Equals("Commercial")
  1080. || q.AccountId.ext_Segment.Key.Equals("Mid-Market") || q.AccountId.ext_Segment.Key.Equals("Small Business"))).Count() > 0
  1081. && quoteDetails.Max(s => s.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal()) == 100.ConvertToDecimal())
  1082. ? true
  1083. : false);
  1084. }
  1085. // For InDirect Sale
  1086. else if (quoteDetails.Where(q => q.ext_salestype != null && q.ext_salestype.Key.ConvertToStringNull() != null && q.ext_salestype.Key.Equals("Indirect")
  1087. && q.ext_SalesPartner != null && !string.IsNullOrEmpty(q.ext_SalesPartner.Name)).Count() > 0)
  1088. {
  1089. ext_ApproverUserDiscount = ((quoteDetails.Where(q => q.ext_salestype != null && !string.IsNullOrEmpty(q.ext_salestype.Key) && q.ext_salestype.Key.Equals("Indirect")
  1090. && q.QLI.AttributeValueId.ext_UserModel != null && q.QLI.AttributeValueId.ext_UserModel.Key.ConvertToStringNull() != null && q.QLI.AttributeValueId.ext_UserModel.Key.Equals("Approver User")
  1091. && q.ext_SalesPartner.ext_Segment != null && q.ext_SalesPartner.ext_Segment.Key.ConvertToStringNull() != null && (q.ext_SalesPartner.ext_Segment.Key.Equals("Commercial")
  1092. || q.ext_SalesPartner.ext_Segment.Key.Equals("Mid-Market") || q.ext_SalesPartner.ext_Segment.Key.Equals("Small Business"))).Count() > 0
  1093. && quoteDetails.Max(s => s.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal()) == 100.ConvertToDecimal())
  1094. ? true
  1095. : false);
  1096. }
  1097. }
  1098. /// <summary>
  1099. /// Customer Satisfaction Exception Approval Calculation
  1100. /// </summary>
  1101. /// <param name="quoteDetails"></param>
  1102. /// <param name="ext_CustomerSatisfactionException"></param>
  1103. /// <returns></returns>
  1104. private void CustomerSatisfactionExceptionApprovalCalculation(List<QuoteResponseApproval> quoteDetails, ref bool ext_CustomerSatisfactionException)
  1105. {
  1106. if (quoteDetails.Where(s => s.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal() == 100.ConvertToDecimal()).ToList().Count > 0)
  1107. {
  1108. ext_CustomerSatisfactionException = true;
  1109. }
  1110. }
  1111. /// <summary>
  1112. /// Customer Satisfaction Exception Approval Calculation
  1113. /// </summary>
  1114. /// <param name="quoteDetails"></param>
  1115. /// <param name="ext_EndOfLifeProducts"></param>
  1116. /// <returns></returns>
  1117. private void EndOfLifeProductsApprovalCalculation(List<QuoteResponseApproval> quoteDetails, ref bool ext_EndOfLifeProducts)
  1118. {
  1119. if (quoteDetails.Where(q => q.ext_Type != null && q.ext_Type.Key.ConvertToStringNull() != null && q.ext_Type.Key.Equals("new_business")
  1120. && q.QLI.ProductId.ConvertToStringNull() != null && q.QLI.ProductId.ext_ProductLifecycleStatus.ConvertToStringNull() != null
  1121. && q.QLI.ProductId.ext_ProductLifecycleStatus.Key.ConvertToStringNull() != null && q.QLI.ProductId.ext_ProductLifecycleStatus.Key.Equals("EOS And Inactive")).Count() > 0)
  1122. {
  1123. ext_EndOfLifeProducts = true;
  1124. }
  1125. }
  1126. private HttpResponseMessage UpdateQuoteWithApprovalFields(List<Dictionary<string, object>> quoteHeaderList, string accessToken)
  1127. {
  1128. var reqConfig = new RequestConfigModel()
  1129. {
  1130. accessToken = accessToken,
  1131. objectName = Constants.OBJ_QUOTE
  1132. };
  1133. var responseString = Utilities.Update(quoteHeaderList, reqConfig);
  1134. return responseString;
  1135. }
  1136. /// <summary>
  1137. /// Get, Calculate and update Approval Fields
  1138. /// </summary>
  1139. /// <param name="QuoteId"></param>
  1140. /// <param name="accessToken"></param>
  1141. /// <returns></returns>
  1142. public HttpResponseMessage CalculatePSApprovalFields(string QuoteId, string accessToken)
  1143. {
  1144. try
  1145. {
  1146. var updateResult = new HttpResponseMessage();
  1147. //Build AQL Query to fetch Quote's opprtunityID
  1148. var query = new Query(Constants.OBJ_QUOTE);
  1149. query.AddColumns(Constants.OBJ_PSAPPROVALCALCULATION_DEFAULT_SELECTFIELDS.Split(Constants.CHAR_COMMA));
  1150. Expression exp = new Expression(ExpressionOperator.AND);
  1151. exp.AddCondition(new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId));
  1152. query.SetCriteria(exp);
  1153. Join quoteLineItem = new Join(Constants.OBJ_QUOTE, Constants.OBJ_CPQ_QUOTELINEITEM, Constants.FIELD_ID, Constants.FIELD_QUOTEID, JoinType.LEFT, Constants.OBJALIAS_QUOTELINEITEM)
  1154. {
  1155. JoinCriteria = new Expression { Conditions = new List<Condition>() { new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId) } }
  1156. };
  1157. query.AddJoin(quoteLineItem);
  1158. Join quoteMileStone = new Join(Constants.OBJ_QUOTE, Constants.OBJ_EXT_MILESTONE, Constants.FIELD_ID, Constants.FIELD_EXT_QUOTEID, JoinType.LEFT, Constants.OBJALIAS_MILESTONE)
  1159. {
  1160. JoinCriteria = new Expression { Conditions = new List<Condition>() { new Condition(Constants.FIELD_ID, FilterOperator.Equal, QuoteId) } }
  1161. };
  1162. query.AddJoin(quoteMileStone);
  1163. var jsonQuery = query.Serialize();
  1164. var reqConfig = new RequestConfigModel()
  1165. {
  1166. accessToken = accessToken,
  1167. searchType = SearchType.AQL,
  1168. objectName = Constants.OBJ_QUOTE
  1169. };
  1170. var response = Utilities.Search(jsonQuery, reqConfig);
  1171. if (response != null && response.IsSuccessStatusCode)
  1172. {
  1173. var responseString = JObject.Parse(response.Content.ReadAsStringAsync().Result).SelectToken(Constants.NODE_SERIALIZEDRESULTENTITIES).ToString();
  1174. var quoteDetails = JsonConvert.DeserializeObject<List<PSQuoteResponseApproval>>(responseString);
  1175. decimal ext_TEDiscount = 0.0m;
  1176. decimal ext_AverageDiscount = 0.0m;
  1177. bool ext_MilestoneExists = false;
  1178. //Logic to update PS Approval Fields
  1179. if (quoteDetails != null && quoteDetails.Count() > 0)
  1180. {
  1181. ext_MilestoneExists = (quoteDetails.Where(x => (x.MS != null) && (x.MS.Id.ConvertToStringNull() != null)).Count() > 0) ? true : false;
  1182. CalculateTEDiscount(quoteDetails, ref ext_TEDiscount);
  1183. CalculateAverageDiscount(quoteDetails, ref ext_AverageDiscount);
  1184. //Update all PS approval fields
  1185. var QuoteFieldToUpdate = new Dictionary<string, object>
  1186. {
  1187. { "ext_MilestoneExists", ext_MilestoneExists },
  1188. { "ext_TEDiscount2", ext_TEDiscount.ConvertToDecimal() },
  1189. { "ext_AverageDiscount", ext_AverageDiscount },
  1190. { "Id", QuoteId}
  1191. };
  1192. updateResult = UpdateQuoteWithApprovalFields(new List<Dictionary<string, object>>() { QuoteFieldToUpdate }, accessToken);
  1193. }
  1194. }
  1195. return updateResult;
  1196. }
  1197. catch (Exception ex)
  1198. {
  1199. //TODO
  1200. throw;
  1201. }
  1202. }
  1203. /// <summary>
  1204. /// TE discount Calculation
  1205. /// </summary>
  1206. /// <param name="quoteDetails"></param>
  1207. /// <param name="ext_TEDiscount"></param>
  1208. /// <returns></returns>
  1209. private void CalculateTEDiscount(List<PSQuoteResponseApproval> quoteDetails, ref decimal ext_TEDiscount)
  1210. {
  1211. var TAndEProducts = quoteDetails.Where(s => s.QLI.ProductId != null && s.QLI.ProductId.Name.ConvertToStringNull() != null && s.QLI.ProductId.Name.Equals("Travel and Expense"));
  1212. if (TAndEProducts.Count() > 0)
  1213. {
  1214. ext_TEDiscount = TAndEProducts.Max(x => x.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal());
  1215. }
  1216. }
  1217. /// <summary>
  1218. /// Average discount Calculation
  1219. /// </summary>
  1220. /// <param name="quoteDetails"></param>
  1221. /// <param name="ext_TEDiscount"></param>
  1222. /// <returns></returns>
  1223. private void CalculateAverageDiscount(List<PSQuoteResponseApproval> quoteDetails, ref decimal ext_AverageDiscount)
  1224. {
  1225. var filterdQLIs = quoteDetails.Where(s => s.QLI.ext_AdjustmentDiscountPercent != null && s.QLI.ext_AdjustmentDiscountPercent != 0.0m);
  1226. if (filterdQLIs.Count() > 0)
  1227. {
  1228. ext_AverageDiscount = filterdQLIs.Sum(x => x.QLI.ext_AdjustmentDiscountPercent.ConvertToDecimal()) / filterdQLIs.Count();
  1229. }
  1230. }
  1231. #endregion Approvals On Quote
  1232. }
  1233. }