PageRenderTime 98ms CodeModel.GetById 18ms RepoModel.GetById 2ms app.codeStats 1ms

/Web1.2/Import/ImportView.ascx.cs

#
C# | 976 lines | 860 code | 40 blank | 76 comment | 201 complexity | 37710d699f32a91276df4d2060bffe0c MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**********************************************************************************************************************
  2. * The contents of this file are subject to the SugarCRM Public License Version 1.1.3 ("License"); You may not use this
  3. * file except in compliance with the License. You may obtain a copy of the License at http://www.sugarcrm.com/SPL
  4. * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  5. * express or implied. See the License for the specific language governing rights and limitations under the License.
  6. *
  7. * All copies of the Covered Code must include on each user interface screen:
  8. * (i) the "Powered by SugarCRM" logo and
  9. * (ii) the SugarCRM copyright notice
  10. * (iii) the SplendidCRM copyright notice
  11. * in the same form as they appear in the distribution. See full license for requirements.
  12. *
  13. * The Original Code is: SplendidCRM Open Source
  14. * The Initial Developer of the Original Code is SplendidCRM Software, Inc.
  15. * Portions created by SplendidCRM Software are Copyright (C) 2005 SplendidCRM Software, Inc. All Rights Reserved.
  16. * Contributor(s): ______________________________________.
  17. *********************************************************************************************************************/
  18. using System;
  19. using System.IO;
  20. using System.Data;
  21. using System.Data.Common;
  22. using System.Collections;
  23. using System.Configuration;
  24. using System.Drawing;
  25. using System.Web;
  26. using System.Web.UI.WebControls;
  27. using System.Web.UI.HtmlControls;
  28. using System.Diagnostics;
  29. using System.Xml;
  30. using System.Text;
  31. //using Microsoft.VisualBasic;
  32. namespace SplendidCRM.Import
  33. {
  34. /// <summary>
  35. /// Summary description for ImportView.
  36. /// </summary>
  37. public class ImportView : SplendidControl
  38. {
  39. protected _controls.ModuleHeader ctlModuleHeader ;
  40. protected _controls.ListHeader ctlListHeader ;
  41. protected HtmlGenericControl divImportStep1 ;
  42. protected HtmlGenericControl divImportStep2 ;
  43. protected HtmlGenericControl divImportStep3 ;
  44. protected HtmlGenericControl divImportStep4 ;
  45. protected HtmlGenericControl divLastImported ;
  46. protected HtmlTable tblInstructionsExcel ;
  47. protected HtmlTable tblInstructionsXmlSpreadsheet;
  48. protected HtmlTable tblInstructionsXML ;
  49. protected HtmlTable tblInstructionsSalesForce ;
  50. protected HtmlTable tblInstructionsAct ;
  51. protected HtmlTable tblInstructionsCommaDelimited;
  52. protected HtmlTable tblInstructionsTabDelimited ;
  53. protected HtmlTable tblNotesAccounts ;
  54. protected HtmlTable tblNotesContacts ;
  55. protected HtmlTable tblNotesOpportunities ;
  56. protected RadioButton radEXCEL ;
  57. protected RadioButton radXML_SPREADSHEET ;
  58. protected RadioButton radXML ;
  59. protected RadioButton radSALESFORCE ;
  60. protected RadioButton radACT_2005 ;
  61. protected RadioButton radCUSTOM_CSV ;
  62. protected RadioButton radCUSTOM_TAB ;
  63. protected Button btnBack ;
  64. protected Button btnNext ;
  65. protected Button btnImport ;
  66. protected Button btnFinish ;
  67. protected DataView vwMain ;
  68. protected SplendidGrid grdMain ;
  69. protected Label lblError ;
  70. protected bool bDebug ;
  71. protected XmlDocument xml ;
  72. protected string sImportModule ;
  73. protected HtmlInputFile fileIMPORT ;
  74. protected RequiredFieldValidator reqFILENAME ;
  75. protected CheckBox chkHasHeader ;
  76. protected CheckBox chkSaveMap ;
  77. protected TextBox txtSaveMap ;
  78. protected int nImportStep ;
  79. protected HtmlTable tblImportMappings ;
  80. protected Hashtable hashFieldMappings ;
  81. protected StringBuilder sbImport ;
  82. protected Label lblStatus ;
  83. protected Label lblSuccessCount ;
  84. protected Label lblFailedCount ;
  85. public string Module
  86. {
  87. get { return sImportModule; }
  88. set { sImportModule = value; }
  89. }
  90. private void ShowStep()
  91. {
  92. divImportStep1 .Visible = (nImportStep == 1);
  93. divImportStep2 .Visible = (nImportStep == 2);
  94. divImportStep3 .Visible = (nImportStep == 3);
  95. divImportStep4 .Visible = (nImportStep == 4);
  96. divLastImported.Visible = divImportStep4.Visible;
  97. btnBack .Visible = (nImportStep > 1 && nImportStep < 4);
  98. btnNext .Visible = (nImportStep >= 1 && nImportStep < 4);
  99. btnImport.Visible = divImportStep4.Visible;
  100. btnFinish.Visible = divImportStep4.Visible;
  101. if ( nImportStep == 2 )
  102. {
  103. tblInstructionsExcel .Visible = radEXCEL .Checked;
  104. tblInstructionsXmlSpreadsheet.Visible = radXML_SPREADSHEET.Checked;
  105. tblInstructionsXML .Visible = radXML .Checked;
  106. tblInstructionsSalesForce .Visible = radSALESFORCE .Checked;
  107. tblInstructionsAct .Visible = radACT_2005 .Checked;
  108. tblInstructionsCommaDelimited.Visible = radCUSTOM_CSV .Checked;
  109. tblInstructionsTabDelimited .Visible = radCUSTOM_TAB .Checked;
  110. }
  111. switch ( nImportStep )
  112. {
  113. case 1: ctlModuleHeader.TitleText = L10n.Term("Import.LBL_MODULE_NAME") + " " + L10n.Term("Import.LBL_STEP_1_TITLE"); break;
  114. case 2: ctlModuleHeader.TitleText = L10n.Term("Import.LBL_MODULE_NAME") + " " + L10n.Term("Import.LBL_STEP_2_TITLE"); break;
  115. case 3: ctlModuleHeader.TitleText = L10n.Term("Import.LBL_MODULE_NAME") + " " + L10n.Term("Import.LBL_STEP_3_TITLE"); break;
  116. case 4: ctlModuleHeader.TitleText = L10n.Term("Import.LBL_MODULE_NAME") + " " + L10n.Term("Import.LBL_RESULTS" ); break;
  117. }
  118. if ( nImportStep == 3 )
  119. btnNext.Text = " " + L10n.Term("Import.LBL_IMPORT_NOW" ) + " ";
  120. else
  121. btnNext.Text = " " + L10n.Term(".LBL_NEXT_BUTTON_LABEL") + " ";
  122. }
  123. private DataView ModuleColumns()
  124. {
  125. DataTable dtColumns = SplendidCache.ImportColumns(sImportModule).Copy();
  126. foreach ( DataRow row in dtColumns.Rows )
  127. {
  128. row["DISPLAY_NAME"] = TableColumnName(sImportModule, Sql.ToString(row["DISPLAY_NAME"]));
  129. }
  130. DataView vwColumns = new DataView(dtColumns);
  131. vwColumns.Sort = "DISPLAY_NAME";
  132. return vwColumns;
  133. }
  134. private void UpdateImportMappings(bool bInitialize)
  135. {
  136. hashFieldMappings = new Hashtable();
  137. tblImportMappings.Rows.Clear();
  138. HtmlTableRow rowHeader = new HtmlTableRow();
  139. tblImportMappings.Rows.Add(rowHeader);
  140. HtmlTableCell cellField = new HtmlTableCell();
  141. HtmlTableCell cellRowHdr = new HtmlTableCell();
  142. HtmlTableCell cellRow1 = new HtmlTableCell();
  143. HtmlTableCell cellRow2 = new HtmlTableCell();
  144. rowHeader.Cells.Add(cellField );
  145. if ( chkHasHeader.Checked || radXML.Checked )
  146. rowHeader.Cells.Add(cellRowHdr);
  147. rowHeader.Cells.Add(cellRow1 );
  148. rowHeader.Cells.Add(cellRow2 );
  149. cellField .Attributes.Add("class", "tabDetailViewDL");
  150. cellRowHdr.Attributes.Add("class", "tabDetailViewDL");
  151. cellRow1 .Attributes.Add("class", "tabDetailViewDL");
  152. cellRow2 .Attributes.Add("class", "tabDetailViewDL");
  153. cellField .Attributes.Add("style", "TEXT-ALIGN: left");
  154. cellRowHdr.Attributes.Add("style", "TEXT-ALIGN: left");
  155. cellRow1 .Attributes.Add("style", "TEXT-ALIGN: left");
  156. cellRow2 .Attributes.Add("style", "TEXT-ALIGN: left");
  157. Label lblField = new Label();
  158. Label lblRowHdr = new Label();
  159. Label lblRow1 = new Label();
  160. Label lblRow2 = new Label();
  161. cellField .Controls.Add(lblField );
  162. cellRowHdr.Controls.Add(lblRowHdr);
  163. cellRow1 .Controls.Add(lblRow1 );
  164. cellRow2 .Controls.Add(lblRow2 );
  165. lblField .Font.Bold = true;
  166. lblRowHdr.Font.Bold = true;
  167. lblRow1 .Font.Bold = true;
  168. lblRow2 .Font.Bold = true;
  169. lblField .Text = L10n.Term("Import.LBL_DATABASE_FIELD");
  170. lblRowHdr.Text = L10n.Term("Import.LBL_HEADER_ROW" );
  171. lblRow1 .Text = L10n.Term("Import.LBL_ROW" ) + " 1";
  172. lblRow2 .Text = L10n.Term("Import.LBL_ROW" ) + " 2";
  173. string sXml = Sql.ToString(ViewState["xml"]);
  174. xml.LoadXml(sXml);
  175. XmlNodeList nl = xml.DocumentElement.SelectNodes(sImportModule.ToLower());
  176. if ( nl.Count > 0 )
  177. {
  178. DataView vwColumns = ModuleColumns();
  179. XmlNode nodeH = nl[0];
  180. XmlNode node1 = nl[0];
  181. XmlNode node2 = null;
  182. // 08/22/2006 Paul. An XML Spreadsheet will have a header record,
  183. // so don't assume that an XML file will use the tag names as the header.
  184. if ( chkHasHeader.Checked )
  185. {
  186. if ( nl.Count > 1 )
  187. node1 = nl[1];
  188. if ( nl.Count > 2 )
  189. node2 = nl[2];
  190. }
  191. else
  192. {
  193. if ( nl.Count > 1 )
  194. node2 = nl[1];
  195. }
  196. bool bDuplicateFields = false;
  197. Hashtable hashSelectedFields = new Hashtable();
  198. for ( int i = 0 ; i < nodeH.ChildNodes.Count ; i++ )
  199. {
  200. rowHeader = new HtmlTableRow();
  201. tblImportMappings.Rows.Add(rowHeader);
  202. cellField = new HtmlTableCell();
  203. cellRowHdr = new HtmlTableCell();
  204. cellRow1 = new HtmlTableCell();
  205. cellRow2 = new HtmlTableCell();
  206. rowHeader.Cells.Add(cellField );
  207. if ( chkHasHeader.Checked || radXML.Checked )
  208. rowHeader.Cells.Add(cellRowHdr);
  209. rowHeader.Cells.Add(cellRow1 );
  210. if ( node2 != null && i < node2.ChildNodes.Count )
  211. rowHeader.Cells.Add(cellRow2);
  212. cellField .Attributes.Add("class", "tabDetailViewDF");
  213. cellRowHdr.Attributes.Add("class", "tabDetailViewDF");
  214. cellRow1 .Attributes.Add("class", "tabDetailViewDF");
  215. cellRow2 .Attributes.Add("class", "tabDetailViewDF");
  216. DropDownList lstField = new DropDownList();
  217. lblRowHdr = new Label();
  218. lblRow1 = new Label();
  219. lblRow2 = new Label();
  220. cellField .Controls.Add(lstField );
  221. cellRowHdr.Controls.Add(lblRowHdr);
  222. cellRow1 .Controls.Add(lblRow1 );
  223. cellRow2 .Controls.Add(lblRow2 );
  224. // 08/20/2006 Paul. Clear any previous filters.
  225. vwColumns.RowFilter = null;
  226. // 08/20/2006 Paul. Don't use real column names as they may collide.
  227. lstField.ID = "ImportField" + i.ToString("000");
  228. lstField.DataValueField = "NAME";
  229. lstField.DataTextField = "DISPLAY_NAME";
  230. lstField.DataSource = vwColumns;
  231. lstField.DataBind();
  232. lstField.Items.Insert(0, new ListItem(L10n.Term("Import.LBL_DONT_MAP"), String.Empty));
  233. try
  234. {
  235. if ( bInitialize )
  236. {
  237. if ( chkHasHeader.Checked )
  238. {
  239. // 08/22/2006 Paul. If Has Header is checked, then always expect the body to contain the header names.
  240. string sFieldName = nodeH.ChildNodes[i].InnerText.Trim();
  241. // 08/20/2006 Paul. Use the DataView to locate matching fields so that we don't have to worry about case significance.
  242. vwColumns.RowFilter = "NAME = '" + sFieldName.Replace("'", "''") + "' or DISPLAY_NAME = '" + sFieldName.Replace("'", "''") + "'";
  243. if ( vwColumns.Count == 1 )
  244. {
  245. hashFieldMappings.Add(i, Sql.ToString(vwColumns[0]["NAME"]));
  246. lstField.SelectedValue = Sql.ToString(vwColumns[0]["NAME"]);
  247. }
  248. }
  249. else if ( radXML.Checked )
  250. {
  251. // 08/22/2006 Paul. If Has Header is not checked for XML, then use the tag ame as the field name.
  252. string sFieldName = nodeH.ChildNodes[i].Name;
  253. // 08/20/2006 Paul. Use the DataView to locate matching fields so that we don't have to worry about case significance.
  254. vwColumns.RowFilter = "NAME = '" + sFieldName.Replace("'", "''") + "' or DISPLAY_NAME = '" + sFieldName.Replace("'", "''") + "'";
  255. if ( vwColumns.Count == 1 )
  256. {
  257. hashFieldMappings.Add(i, Sql.ToString(vwColumns[0]["NAME"]));
  258. lstField.SelectedValue = Sql.ToString(vwColumns[0]["NAME"]);
  259. }
  260. }
  261. else
  262. hashFieldMappings.Add(i, "ImportField" + i.ToString("000"));
  263. }
  264. else
  265. {
  266. // 08/20/2006 Paul. Manually set the last value.
  267. hashFieldMappings.Add(i, Sql.ToString(Request[lstField.UniqueID]));
  268. lstField.SelectedValue = Sql.ToString(Request[lstField.UniqueID]);
  269. if ( lstField.SelectedValue.Length > 0 )
  270. {
  271. if ( hashSelectedFields.ContainsKey(lstField.SelectedValue) )
  272. {
  273. bDuplicateFields = true;
  274. }
  275. else
  276. {
  277. hashSelectedFields.Add(lstField.SelectedValue, null);
  278. }
  279. }
  280. }
  281. }
  282. catch
  283. {
  284. }
  285. // XML data will use the node-name as the header.
  286. if ( chkHasHeader.Checked )
  287. {
  288. // 08/22/2006 Paul. If Has Header is checked, then always expect the body to contain the header names.
  289. lblRowHdr.Text = nodeH.ChildNodes[i].InnerText;
  290. }
  291. else if ( radXML.Checked )
  292. {
  293. // 08/22/2006 Paul. If Has Header is not checked for XML, then use the tag ame as the field name.
  294. lblRowHdr.Text = nodeH.ChildNodes[i].Name;
  295. }
  296. if ( node1 != null && i < node1.ChildNodes.Count )
  297. lblRow1.Text = node1.ChildNodes[i].InnerText;
  298. if ( node2 != null && i < node2.ChildNodes.Count )
  299. lblRow2.Text = node2.ChildNodes[i].InnerText;
  300. }
  301. if ( bDuplicateFields )
  302. {
  303. throw(new Exception(L10n.Term("Import.ERR_MULTIPLE")));
  304. }
  305. if ( !bInitialize )
  306. {
  307. switch ( sImportModule )
  308. {
  309. case "Accounts":
  310. if ( !hashSelectedFields.ContainsKey("NAME") )
  311. throw ( new Exception(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Accounts.LBL_LIST_ACCOUNT_NAME")) );
  312. break;
  313. case "Contacts":
  314. if ( !hashSelectedFields.ContainsKey("LAST_NAME") )
  315. throw ( new Exception(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Contacts.LBL_LIST_LAST_NAME")) );
  316. break;
  317. case "Opportunities":
  318. StringBuilder sb = new StringBuilder();
  319. if ( !hashSelectedFields.ContainsKey("NAME") )
  320. sb.Append(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Opportunities.LBL_LIST_NAME") + ControlChars.CrLf);
  321. if ( !hashSelectedFields.ContainsKey("ACCOUNT_NAME") )
  322. sb.Append(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Opportunities.LBL_LIST_ACCOUNT_NAME") + ControlChars.CrLf);
  323. if ( !hashSelectedFields.ContainsKey("DATE_CLOSED") )
  324. sb.Append(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Opportunities.LBL_LIST_DATE_CLOSED") + ControlChars.CrLf);
  325. if ( !hashSelectedFields.ContainsKey("SALES_STAGE") )
  326. sb.Append(L10n.Term(".ERR_MISSING_REQUIRED_FIELDS") + " " + L10n.Term("Opportunities.LBL_LIST_SALES_STAGE") + ControlChars.CrLf);
  327. if ( sb.Length > 0 )
  328. throw ( new Exception(sb.ToString()) );
  329. break;
  330. }
  331. }
  332. }
  333. }
  334. protected void GenerateImport()
  335. {
  336. try
  337. {
  338. string sXml = Sql.ToString(ViewState["xml"]);
  339. xml.LoadXml(sXml);
  340. // 08/20/2006 Paul. Also map the header names to allow for a flexible XML.
  341. Hashtable hashHeaderMappings = new Hashtable();
  342. XmlNodeList nlRows = xml.DocumentElement.SelectNodes(sImportModule.ToLower());
  343. if ( nlRows.Count == 0 )
  344. throw(new Exception("Nothing to import."));
  345. // 08/22/2006 Paul. We should always use the header mappings instead of an index as nodes may move around.
  346. XmlNode node = nlRows[0];
  347. for ( int j = 0; j < node.ChildNodes.Count; j++ )
  348. {
  349. hashHeaderMappings.Add(node.ChildNodes[j].Name, hashFieldMappings[j]);
  350. }
  351. int nImported = 0;
  352. int nFailed = 0;
  353. //int nSkipped = 0;
  354. DataTable dtProcessed = new DataTable();
  355. dtProcessed.Columns.Add("Import_Row_Status", typeof(bool));
  356. dtProcessed.Columns.Add("Import_Row_Number", typeof(Int32));
  357. dtProcessed.Columns.Add("Import_Row_Error" );
  358. dtProcessed.Columns.Add("Import_Last_Column");
  359. SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), "Import Database Table: " + sImportModule);
  360. DbProviderFactory dbf = DbProviderFactories.GetFactory();
  361. using ( IDbConnection con = dbf.CreateConnection() )
  362. {
  363. con.Open();
  364. IDbCommand cmdImport = SqlProcs.Factory(con, "sp" + sImportModule.ToUpper() + "_Update");
  365. int i = 0;
  366. if ( chkHasHeader.Checked )
  367. i++;
  368. for ( int iRowNumber = 1; i < nlRows.Count ; i++ )
  369. {
  370. node = nlRows[i];
  371. int nEmptyColumns = 0;
  372. for ( int j = 0; j < node.ChildNodes.Count; j++ )
  373. {
  374. string sText = node.ChildNodes[j].InnerText;
  375. if ( sText == String.Empty )
  376. nEmptyColumns++;
  377. }
  378. // 09/04/2006 Paul. If all columns are empty, then skip the row.
  379. if ( nEmptyColumns == node.ChildNodes.Count )
  380. continue;
  381. DataRow row = dtProcessed.NewRow();
  382. row["Import_Row_Number"] = iRowNumber ;
  383. iRowNumber++;
  384. dtProcessed.Rows.Add(row);
  385. try
  386. {
  387. if ( !Response.IsClientConnected )
  388. {
  389. break;
  390. }
  391. foreach(IDataParameter par in cmdImport.Parameters)
  392. {
  393. par.Value = DBNull.Value;
  394. }
  395. for ( int j = 0; j < node.ChildNodes.Count; j++ )
  396. {
  397. string sText = node.ChildNodes[j].InnerText;
  398. string sName = String.Empty;
  399. // 08/22/2006 Paul. We should always use the header mappings instead of an index as nodes may move around.
  400. //if ( radXML.Checked )
  401. sName = Sql.ToString(hashHeaderMappings[node.ChildNodes[j].Name]);
  402. //else
  403. // sName = Sql.ToString(hashFieldMappings[j]); // node.ChildNodes[j].Name
  404. // 09/08/2006 Paul. There is no need to set the field if the value is empty.
  405. if ( sName.Length > 0 && sText.Length > 0 )
  406. {
  407. sName = sName.ToUpper();
  408. // 08/20/2006 Paul. Fix IDs.
  409. if ( ( sName == "ID" || sName.EndsWith("_ID") ) && sName.Length < 36 && sText.Length > 0 )
  410. {
  411. sText = "00000000-0000-0000-0000-000000000000".Substring(0, 36 - sText.Length) + sText;
  412. switch ( sText )
  413. {
  414. case "00000000-0000-0000-0000-000000jim_id": sText = "00000000-0000-0000-0001-000000000000"; break;
  415. case "00000000-0000-0000-0000-000000max_id": sText = "00000000-0000-0000-0002-000000000000"; break;
  416. case "00000000-0000-0000-0000-00000will_id": sText = "00000000-0000-0000-0003-000000000000"; break;
  417. case "00000000-0000-0000-0000-0000chris_id": sText = "00000000-0000-0000-0004-000000000000"; break;
  418. case "00000000-0000-0000-0000-0000sally_id": sText = "00000000-0000-0000-0005-000000000000"; break;
  419. case "00000000-0000-0000-0000-0000sarah_id": sText = "00000000-0000-0000-0006-000000000000"; break;
  420. }
  421. }
  422. if ( !dtProcessed.Columns.Contains(sName) )
  423. {
  424. dtProcessed.Columns.Add(sName);
  425. }
  426. row["Import_Row_Status" ] = true ;
  427. row["Import_Last_Column"] = sName;
  428. row[sName] = sText;
  429. Sql.SetParameter(cmdImport, sName, sText);
  430. }
  431. }
  432. sbImport.Append(Sql.ExpandParameters(cmdImport));
  433. sbImport.Append(";");
  434. sbImport.Append(ControlChars.CrLf);
  435. cmdImport.ExecuteNonQuery();
  436. nImported++;
  437. row["Import_Last_Column"] = DBNull.Value;
  438. Response.Write(" ");
  439. }
  440. catch(Exception ex)
  441. {
  442. row["Import_Row_Status"] = false;
  443. row["Import_Row_Error" ] = "Error: " + Sql.ToString(row["Import_Last_Column"]) + ". " + ex.Message;
  444. nFailed++;
  445. }
  446. }
  447. }
  448. if ( nFailed == 0 )
  449. lblStatus.Text = L10n.Term("Import.LBL_SUCCESS" );
  450. lblSuccessCount.Text = nImported.ToString() + " " + L10n.Term("Import.LBL_SUCCESSFULLY" );
  451. lblFailedCount.Text = nFailed.ToString() + " " + L10n.Term("Import.LBL_FAILED_IMPORT");
  452. DataView vwColumns = ModuleColumns();
  453. Hashtable hashColumns = new Hashtable();
  454. foreach ( DataRowView row in vwColumns )
  455. hashColumns.Add(row["NAME"], row["DISPLAY_NAME"]);
  456. BoundColumn bnd = new BoundColumn();
  457. bnd.DataField = "Import_Row_Number";
  458. bnd.HeaderText = "Row";
  459. grdMain.Columns.Add(bnd);
  460. for ( int i = 4; i < dtProcessed.Columns.Count; i++ )
  461. {
  462. bnd = new BoundColumn();
  463. bnd.DataField = dtProcessed.Columns[i].ColumnName;
  464. if ( hashColumns.ContainsKey(bnd.DataField) )
  465. bnd.HeaderText = hashColumns[bnd.DataField] as string;
  466. else
  467. bnd.HeaderText = bnd.DataField;
  468. grdMain.Columns.Add(bnd);
  469. }
  470. bnd = new BoundColumn();
  471. bnd.DataField = "Import_Row_Error";
  472. bnd.HeaderText = "Status";
  473. grdMain.Columns.Add(bnd);
  474. DataView vwProcessed = new DataView(dtProcessed);
  475. vwProcessed.Sort = "Import_Row_Status, Import_Row_Number";
  476. grdMain.DataSource = vwProcessed;
  477. grdMain.DataBind();
  478. }
  479. catch ( Exception ex )
  480. {
  481. lblError.Text += ex.Message;
  482. }
  483. }
  484. protected XmlDocument ConvertTableToXml(DataTable dt, string sRecordName)
  485. {
  486. XmlDocument xml = new XmlDocument();
  487. xml.AppendChild(xml.CreateProcessingInstruction("xml" , "version=\"1.0\" encoding=\"UTF-8\""));
  488. xml.AppendChild(xml.CreateElement("xml"));
  489. foreach ( DataRow row in dt.Rows )
  490. {
  491. XmlNode xRecord = xml.CreateElement(sRecordName);
  492. xml.DocumentElement.AppendChild(xRecord);
  493. for ( int nField = 0; nField < dt.Columns.Count; nField++ )
  494. {
  495. XmlNode xField = xml.CreateElement("ImportField" + nField.ToString("000"));
  496. xRecord.AppendChild(xField);
  497. if ( row[nField] != DBNull.Value )
  498. {
  499. xField.InnerText = row[nField].ToString();
  500. }
  501. }
  502. }
  503. return xml;
  504. }
  505. protected static void ConvertTextToXml(ref XmlDocument xml, string sRecordName, Stream stm, char chFieldSeparator)
  506. {
  507. int nMaxField = 0;
  508. xml = new XmlDocument();
  509. xml.AppendChild(xml.CreateProcessingInstruction("xml" , "version=\"1.0\" encoding=\"UTF-8\""));
  510. xml.AppendChild(xml.CreateElement("xml"));
  511. using ( TextReader reader = new StreamReader(stm) )
  512. {
  513. string sLine = null;
  514. while ( (sLine = reader.ReadLine()) != null )
  515. {
  516. if ( sLine.Length == 0 )
  517. continue;
  518. XmlNode xRecord = xml.CreateElement(sRecordName);
  519. xml.DocumentElement.AppendChild(xRecord);
  520. int i = 0;
  521. int nMode = 0;
  522. int nField = 0;
  523. bool bContinueParsing = true;
  524. while ( bContinueParsing )
  525. {
  526. switch ( nMode )
  527. {
  528. case 0: // Search for next entry.
  529. {
  530. if ( chFieldSeparator == ControlChars.Tab )
  531. {
  532. // Don't skip the tab when it is used as a separator.
  533. while ( Char.IsWhiteSpace(sLine[i]) && sLine[i] != ControlChars.Tab )
  534. i++;
  535. }
  536. else
  537. {
  538. while ( Char.IsWhiteSpace(sLine[i]) )
  539. i++;
  540. }
  541. nMode = 1;
  542. break;
  543. }
  544. case 1: // Determine if field is quoted or unquoted.
  545. {
  546. // first check if field is empty.
  547. char chPunctuation = sLine[i];
  548. if ( chPunctuation == chFieldSeparator )
  549. {
  550. i++;
  551. XmlNode xField = xml.CreateElement("ImportField" + nField.ToString("000"));
  552. xRecord.AppendChild(xField);
  553. nField++;
  554. nMode = 0;
  555. }
  556. if ( chPunctuation == '\"' )
  557. {
  558. i++;
  559. // Field is quoted, so start reading until next quote.
  560. nMode = 3;
  561. }
  562. else
  563. {
  564. // Field is unquoted, so start reading until next separator or end-of-line.
  565. nMode = 2;
  566. }
  567. break;
  568. }
  569. case 2: // Extract unquoted field.
  570. {
  571. XmlNode xField = xml.CreateElement("ImportField" + nField.ToString("000"));
  572. xRecord.AppendChild(xField);
  573. nField++;
  574. int nFieldStart = i;
  575. // Field is unquoted, so start reading until next separator or end-of-line.
  576. while ( i < sLine.Length && sLine[i] != chFieldSeparator )
  577. i++;
  578. int nFieldEnd = i;
  579. string sField = sLine.Substring(nFieldStart, nFieldEnd-nFieldStart);
  580. xField.InnerText = sField;
  581. nMode = 0;
  582. i++;
  583. break;
  584. }
  585. case 3: // Extract quoted field.
  586. {
  587. XmlNode xField = xml.CreateElement("ImportField" + nField.ToString("000"));
  588. xRecord.AppendChild(xField);
  589. nField++;
  590. int nFieldStart = i;
  591. // Field is quoted, so start reading until next quote. Watch out for an escaped quote (two double quotes).
  592. while ( ( i < sLine.Length && sLine[i] != '\"' ) || ( i + 1 < sLine.Length && sLine[i] == '\"' && sLine[i+1] == '\"' ) )
  593. {
  594. if ( i + 1 < sLine.Length && sLine[i] == '\"' && sLine[i+1] == '\"' )
  595. i++;
  596. i++;
  597. }
  598. int nFieldEnd = i;
  599. // Skip all characters until we reach the separator or end-of-line.
  600. while ( i < sLine.Length && sLine[i] != chFieldSeparator )
  601. i++;
  602. string sField = sLine.Substring(nFieldStart, nFieldEnd-nFieldStart);
  603. sField = sField.Replace("\"\"", "\"");
  604. xField.InnerText = sField;
  605. nMode = 0;
  606. i++;
  607. break;
  608. }
  609. default:
  610. bContinueParsing = false;
  611. break;
  612. }
  613. if ( i >= sLine.Length )
  614. break;
  615. }
  616. nMaxField = Math.Max(nField, nMaxField);
  617. }
  618. }
  619. XmlNodeList nlRows = xml.DocumentElement.SelectNodes(sRecordName);
  620. if ( nlRows.Count > 0 )
  621. {
  622. // If the first record does not have all the fields, then add the missing fields.
  623. XmlNode xNode = nlRows[0];
  624. while ( xNode.ChildNodes.Count < nMaxField )
  625. {
  626. XmlNode xField = xml.CreateElement("ImportField" + xNode.ChildNodes.Count.ToString("000"));
  627. xNode.AppendChild(xField);
  628. }
  629. }
  630. }
  631. protected void ConvertXmlSpreadsheetToXml(ref XmlDocument xml, string sRecordName)
  632. {
  633. XmlDocument xmlImport = new XmlDocument();
  634. xmlImport.AppendChild(xmlImport.CreateProcessingInstruction("xml" , "version=\"1.0\" encoding=\"UTF-8\""));
  635. xmlImport.AppendChild(xmlImport.CreateElement("xml"));
  636. XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
  637. string sSpreadsheetNamespace = "urn:schemas-microsoft-com:office:spreadsheet";
  638. nsmgr.AddNamespace("ss", sSpreadsheetNamespace);
  639. // 08/22/2006 Paul. The Spreadsheet namespace is also the default namespace, so make sure to prefix nodes with ss.
  640. XmlNode xWorksheet = xml.DocumentElement.SelectSingleNode("ss:Worksheet", nsmgr);
  641. if ( xWorksheet != null )
  642. {
  643. XmlNode xTable = xWorksheet.SelectSingleNode("ss:Table", nsmgr);
  644. if ( xTable != null )
  645. {
  646. int nColumnCount = 0;
  647. XmlNode xColumnCount = xTable.Attributes.GetNamedItem("ss:ExpandedColumnCount");
  648. if ( xColumnCount != null )
  649. nColumnCount = Sql.ToInteger(xColumnCount.Value);
  650. XmlNodeList nlRows = xTable.SelectNodes("ss:Row", nsmgr);
  651. if ( nlRows.Count > 0 )
  652. {
  653. // 08/22/2006 Paul. The first row is special in that we must make sure that all nodes exist.
  654. XmlNode xRow = nlRows[0];
  655. if ( nColumnCount == 0 )
  656. nColumnCount = xRow.ChildNodes.Count;
  657. for ( int i = 0; i < nlRows.Count; i++ )
  658. {
  659. XmlNode xRecord = xmlImport.CreateElement(sRecordName);
  660. xmlImport.DocumentElement.AppendChild(xRecord);
  661. xRow = nlRows[i];
  662. for ( int j = 0, nField = 0; j < xRow.ChildNodes.Count; j++, nField++ )
  663. {
  664. XmlNode xField = xmlImport.CreateElement("ImportField" + nField.ToString("000"));
  665. xRecord.AppendChild(xField);
  666. XmlNode xCell = xRow.ChildNodes[j];
  667. int nCellIndex = 0;
  668. XmlNode xCellIndex = xCell.Attributes.GetNamedItem("ss:Index");
  669. if ( xCellIndex != null )
  670. nCellIndex = Sql.ToInteger(xCellIndex.Value);
  671. // 08/22/2006 Paul. If there are any missing cells, then add them.
  672. while ( (nField + 1) < nCellIndex )
  673. {
  674. nField++;
  675. xField = xmlImport.CreateElement("ImportField" + nField.ToString("000"));
  676. xRecord.AppendChild(xField);
  677. }
  678. if ( xCell.ChildNodes.Count > 0 )
  679. {
  680. if ( xCell.ChildNodes[0].Name == "Data" )
  681. {
  682. xField.InnerText = xCell.ChildNodes[0].InnerText;
  683. }
  684. }
  685. }
  686. }
  687. }
  688. }
  689. }
  690. xml = xmlImport;
  691. }
  692. protected void Page_Command(Object sender, CommandEventArgs e)
  693. {
  694. try
  695. {
  696. if ( e.CommandName == "Next" )
  697. {
  698. switch ( nImportStep )
  699. {
  700. case 1:
  701. {
  702. nImportStep++;
  703. ShowStep();
  704. ViewState["ImportStep"] = nImportStep;
  705. break;
  706. }
  707. case 2:
  708. {
  709. if ( Page.IsValid )
  710. {
  711. HttpPostedFile pstIMPORT = fileIMPORT.PostedFile;
  712. if ( pstIMPORT != null )
  713. {
  714. if ( pstIMPORT.FileName.Length > 0 )
  715. {
  716. string sFILENAME = Path.GetFileName (pstIMPORT.FileName);
  717. string sFILE_EXT = Path.GetExtension(sFILENAME);
  718. string sFILE_MIME_TYPE = pstIMPORT.ContentType;
  719. if ( radXML_SPREADSHEET.Checked )
  720. {
  721. xml.Load(pstIMPORT.InputStream);
  722. ConvertXmlSpreadsheetToXml(ref xml, sImportModule.ToLower());
  723. }
  724. else if ( sFILE_MIME_TYPE == "text/xml" || radXML.Checked )
  725. {
  726. using ( MemoryStream mstm = new MemoryStream() )
  727. {
  728. using ( BinaryWriter mwtr = new BinaryWriter(mstm) )
  729. {
  730. using ( BinaryReader reader = new BinaryReader(pstIMPORT.InputStream) )
  731. {
  732. byte[] binBYTES = reader.ReadBytes(8 * 1024);
  733. while ( binBYTES.Length > 0 )
  734. {
  735. for ( int i = 0; i < binBYTES.Length; i++ )
  736. {
  737. // MySQL dump seems to dump binary 0 & 1 for byte values.
  738. if ( binBYTES[i] == 0 )
  739. mstm.WriteByte(Convert.ToByte('0'));
  740. else if ( binBYTES[i] == 1 )
  741. mstm.WriteByte(Convert.ToByte('1'));
  742. else
  743. mstm.WriteByte(binBYTES[i]);
  744. }
  745. binBYTES = reader.ReadBytes(8 * 1024);
  746. }
  747. }
  748. mwtr.Flush();
  749. mstm.Seek(0, SeekOrigin.Begin);
  750. xml.Load(mstm);
  751. bool bExcelSheet = false;
  752. foreach ( XmlNode xNode in xml )
  753. {
  754. if ( xNode.NodeType == XmlNodeType.ProcessingInstruction )
  755. {
  756. if ( xNode.Name == "mso-application" && xNode.InnerText == "progid=\"Excel.Sheet\"" )
  757. {
  758. bExcelSheet = true;
  759. break;
  760. }
  761. }
  762. }
  763. if ( bExcelSheet )
  764. ConvertXmlSpreadsheetToXml(ref xml, sImportModule.ToLower());
  765. }
  766. }
  767. }
  768. else if ( radEXCEL.Checked )
  769. {
  770. ExcelDataReader.ExcelDataReader spreadsheet = new ExcelDataReader.ExcelDataReader(pstIMPORT.InputStream);
  771. if ( spreadsheet.WorkbookData.Tables.Count > 0 )
  772. {
  773. xml = ConvertTableToXml(spreadsheet.WorkbookData.Tables[0], sImportModule.ToLower());
  774. }
  775. }
  776. else if ( radCUSTOM_TAB.Checked )
  777. {
  778. CsvDataReader spreadsheet = new CsvDataReader(pstIMPORT.InputStream, ControlChars.Tab);
  779. if ( spreadsheet.Table != null )
  780. {
  781. xml = ConvertTableToXml(spreadsheet.Table, sImportModule.ToLower());
  782. }
  783. }
  784. else
  785. {
  786. // 08/21/2006 Paul. Everything else is comma separated. Convert to XML.
  787. CsvDataReader spreadsheet = new CsvDataReader(pstIMPORT.InputStream, ',');
  788. if ( spreadsheet.Table != null )
  789. {
  790. xml = ConvertTableToXml(spreadsheet.Table, sImportModule.ToLower());
  791. }
  792. }
  793. }
  794. }
  795. }
  796. if ( xml.DocumentElement == null )
  797. throw(new Exception(L10n.Term("Import.LBL_NOTHING")));
  798. // 08/21/2006 Paul. Don't move to next step if there is no data.
  799. XmlNodeList nlRows = xml.DocumentElement.SelectNodes(sImportModule.ToLower());
  800. if ( nlRows.Count == 0 )
  801. throw(new Exception(L10n.Term("Import.LBL_NOTHING")));
  802. ViewState["xml"] = xml.OuterXml;
  803. UpdateImportMappings(true);
  804. nImportStep++ ;
  805. ShowStep();
  806. ViewState["ImportStep"] = nImportStep;
  807. break;
  808. }
  809. case 3:
  810. {
  811. UpdateImportMappings(false);
  812. GenerateImport();
  813. nImportStep++ ;
  814. ShowStep();
  815. ViewState["ImportStep"] = nImportStep;
  816. break;
  817. }
  818. }
  819. }
  820. else if ( e.CommandName == "Back" )
  821. {
  822. if ( nImportStep > 1 )
  823. {
  824. nImportStep--;
  825. ShowStep();
  826. ViewState["ImportStep"] = nImportStep;
  827. }
  828. }
  829. else if ( e.CommandName == "ImportMore" )
  830. {
  831. //radEXCEL.Checked = true;
  832. //chkHasHeader.Checked = true;
  833. //nImportStep = 1;
  834. //ShowStep();
  835. //ViewState["ImportStep"] = nImportStep;
  836. // 08/20/2006 Paul. Redirecting is a safer way to reset all variables.
  837. Response.Redirect(Request.Path);
  838. }
  839. else if ( e.CommandName == "Finish" )
  840. {
  841. Response.Redirect("~/" + sImportModule);
  842. }
  843. }
  844. catch(Exception ex)
  845. {
  846. //SplendidError.SystemError(new StackTrace(true).GetFrame(0), ex.Message);
  847. lblError.Text = ex.Message;
  848. return;
  849. }
  850. }
  851. private string TableColumnName(string sModule, string sDISPLAY_NAME)
  852. {
  853. // 07/04/2006 Paul. Some columns have global terms.
  854. if ( sDISPLAY_NAME == "DATE_ENTERED"
  855. || sDISPLAY_NAME == "DATE_MODIFIED"
  856. || sDISPLAY_NAME == "ASSIGNED_TO"
  857. || sDISPLAY_NAME == "CREATED_BY"
  858. || sDISPLAY_NAME == "MODIFIED_BY" )
  859. {
  860. sDISPLAY_NAME = L10n.Term(".LBL_" + sDISPLAY_NAME).Replace(":", "");
  861. }
  862. else
  863. {
  864. // 07/04/2006 Paul. Column names are aliased so that we don't have to redefine terms.
  865. sDISPLAY_NAME = L10n.AliasedTerm(sModule + ".LBL_" + sDISPLAY_NAME).Replace(":", "");
  866. }
  867. return sDISPLAY_NAME;
  868. }
  869. private void Page_Load(object sender, System.EventArgs e)
  870. {
  871. Utils.SetPageTitle(Page, L10n.Term("Import.LBL_MODULE_NAME"));
  872. // 06/04/2006 Paul. Visibility is already controlled by the ASPX page, but it is probably a good idea to skip the load.
  873. this.Visible = (SplendidCRM.Security.GetUserAccess(m_sMODULE, "import") >= 0);
  874. if ( !this.Visible )
  875. return;
  876. #if DEBUG
  877. bDebug = true;
  878. #endif
  879. xml = new XmlDocument();
  880. sbImport = new StringBuilder();
  881. try
  882. {
  883. // 07/02/2006 Paul. The required fields need to be bound manually.
  884. reqFILENAME.DataBind();
  885. // 12/17/2005 Paul. Don't buffer so that the connection can be kept alive.
  886. Response.BufferOutput = false;
  887. if ( !IsPostBack )
  888. {
  889. radEXCEL.Checked = true;
  890. chkHasHeader.Checked = true;
  891. nImportStep = 1;
  892. ShowStep();
  893. ViewState["ImportStep"] = nImportStep;
  894. radSALESFORCE.DataBind();
  895. radACT_2005.DataBind();
  896. radCUSTOM_CSV.DataBind();
  897. radCUSTOM_TAB.DataBind();
  898. ctlListHeader.Title = L10n.Term("Import.LBL_LAST_IMPORTED") + " " + L10n.Term(".moduleList.", sImportModule);
  899. tblNotesAccounts .Visible = (sImportModule == "Accounts" );
  900. tblNotesContacts .Visible = (sImportModule == "Contacts" );
  901. tblNotesOpportunities.Visible = (sImportModule == "Opportunities");
  902. }
  903. else
  904. {
  905. nImportStep = Sql.ToInteger(ViewState["ImportStep"]);
  906. if ( nImportStep < 1 )
  907. nImportStep = 1;
  908. ShowStep();
  909. }
  910. }
  911. catch ( Exception ex )
  912. {
  913. lblError.Text = ex.Message;
  914. }
  915. }
  916. #region Web Form Designer generated code
  917. override protected void OnInit(EventArgs e)
  918. {
  919. //
  920. // CODEGEN: This call is required by the ASP.NET Web Form Designer.
  921. //
  922. InitializeComponent();
  923. base.OnInit(e);
  924. }
  925. /// <summary>
  926. /// Required method for Designer support - do not modify
  927. /// the contents of this method with the code editor.
  928. /// </summary>
  929. private void InitializeComponent()
  930. {
  931. this.Load += new System.EventHandler(this.Page_Load);
  932. this.m_sMODULE = "Import";
  933. }
  934. #endregion
  935. }
  936. }