diff --git a/Marco.Pms.UtilityApplication/App.xaml b/Marco.Pms.UtilityApplication/App.xaml
new file mode 100644
index 0000000..df80282
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Marco.Pms.UtilityApplication/App.xaml.cs b/Marco.Pms.UtilityApplication/App.xaml.cs
new file mode 100644
index 0000000..5794de3
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace Marco.Pms.UtilityApplication
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/Marco.Pms.UtilityApplication/AssemblyInfo.cs b/Marco.Pms.UtilityApplication/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/Marco.Pms.UtilityApplication/CategoryMaster.cs b/Marco.Pms.UtilityApplication/CategoryMaster.cs
new file mode 100644
index 0000000..cfc9f25
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/CategoryMaster.cs
@@ -0,0 +1,9 @@
+namespace Marco.Pms.UtilityApplication
+{
+ public class CategoryMaster
+ {
+ public string CategoryID { get; set; }
+ public string Categories { get; set; }
+ public string Description { get; set; }
+ }
+}
diff --git a/Marco.Pms.UtilityApplication/Contacts.cs b/Marco.Pms.UtilityApplication/Contacts.cs
new file mode 100644
index 0000000..b5a8399
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/Contacts.cs
@@ -0,0 +1,32 @@
+using Marco.Pms.Model.Projects;
+using System.Net;
+using System.Xml.Linq;
+
+namespace Marco.Pms.UtilityApplication
+{
+ public class Contacts
+ {
+ public string BucketId { get; set; }
+ public string Owner { get; set; }
+ public string Name { get; set; }
+ public string Designation { get; set; }
+
+ public string Organization { get; set; }
+ public string Mobile1 { get; set; }
+ public string Mobile2 { get; set; }
+ public string Mobile3 { get; set; }
+ public string Email1 { get; set; }
+
+ public string Email2 { get; set; }
+ public string Location { get; set; }
+ public string Address { get; set; }
+ public string MoreInformation { get; set; }
+
+ public string Category { get; set; }
+ public Guid? CategoryId { get; set; }
+
+ public string Tags { get; set; }
+ public string Project { get; set; }
+
+ }
+}
diff --git a/Marco.Pms.UtilityApplication/DirectoryHelper.cs b/Marco.Pms.UtilityApplication/DirectoryHelper.cs
new file mode 100644
index 0000000..7a02d3b
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/DirectoryHelper.cs
@@ -0,0 +1,347 @@
+using Marco.Pms.Model.Dtos.Directory;
+using OfficeOpenXml;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.Mail;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Marco.Pms.UtilityApplication
+{
+ public class DirectoryHelper
+ {
+
+ public async Task> GenerateCreateContactDto(List contactsData, List categoryMasters, List tagsMaster, List projectMaster)
+ {
+ List lstCreateContactDto = new List();
+
+ CreateContactDto dto = null;
+ foreach (Contacts contact in contactsData)
+ {
+ dto = new CreateContactDto();
+ dto.Name = contact.Name;
+ dto.Organization = contact.Organization;
+ dto.Address = contact.Address;
+ dto.ContactCategoryId = GetContactCategoryID(contact, categoryMasters);
+ dto.Description = contact.MoreInformation;
+ dto.ContactPhones = GetContactPhones(contact);
+ dto.ContactEmails = GetContactEmails(contact);
+ dto.ProjectIds = GetContactProjectIDs(contact, projectMaster);
+ dto.BucketIds = GetContactBucketIDs(contact);
+ dto.Tags = GetContactTags(contact, tagsMaster);
+
+ lstCreateContactDto.Add(dto);
+
+ }
+
+ return lstCreateContactDto;
+ }
+
+ private List? GetContactTags(Contacts contact, List tagsMaster)
+ {
+ List result = new List();
+ ContactTagDto dto = null;
+ foreach (string tag in contact.Tags.Split(","))
+ {
+ dto = new ContactTagDto();
+ dto.Name = tag;
+ var tagObject = tagsMaster.SingleOrDefault(c => c.Tag == tag.Trim());
+ dto.Id = (tagObject != null && tagObject.TagID != "" ? Guid.Parse(tagObject.TagID) : null);
+
+ result.Add(dto);
+ }
+
+ return result;
+ }
+
+ private Guid? GetContactCategoryID(Contacts contact, List categoryMaster)
+ {
+ if (contact.Category != "")
+ {
+ var category = categoryMaster.SingleOrDefault(c => c.Categories == contact.Category.Trim());
+ if (category != null && category.CategoryID != "")
+ {
+ return new Guid(category.CategoryID);
+ }
+ }
+ return null;
+ }
+
+ private List? GetContactBucketIDs(Contacts contact)
+ {
+ List? result = null;
+ if (contact.BucketId != "")
+ {
+ result = new List();
+ result.Add(new Guid(contact.BucketId));
+ }
+
+ return result;
+ }
+
+ private List? GetContactEmails(Contacts contact)
+ {
+ List result = new List();
+
+ if (contact.Email1 != "" && IsValidEmailMailAddress(contact.Email1))
+ {
+ CreateContactEmailDto dto = new CreateContactEmailDto();
+ dto.Label = "Work";
+ dto.EmailAddress = contact.Email1;
+ result.Add(dto);
+ }
+
+ if (contact.Email2 != "" && IsValidEmailMailAddress(contact.Email2))
+ {
+ CreateContactEmailDto dto = new CreateContactEmailDto();
+ dto.Label = "Work";
+ dto.EmailAddress = contact.Email2;
+ result.Add(dto);
+ }
+ return result.Count > 0 ? result : null;
+ }
+
+ private List? GetContactProjectIDs(Contacts contact, List projectMasters)
+ {
+ List? result = null;
+ if (contact.Project != "")
+ {
+ var category = projectMasters.SingleOrDefault(c => c.ProjectName == contact.Project.Trim());
+ if (category != null && category.ProjectID != "")
+ {
+ if (result == null) result = new List();
+ result.Add(new Guid(category.ProjectID));
+ }
+ }
+ return result;
+ }
+
+ private List? GetContactPhones(Contacts contact)
+ {
+ List result = new List();
+
+ if (contact.Mobile1 != "" && IsValidPhoneNumberBasic(contact.Mobile1))
+ {
+ CreateContactPhoneDto dto = new CreateContactPhoneDto();
+ dto.Label = "Office";
+ dto.PhoneNumber = contact.Mobile1;
+ result.Add(dto);
+ }
+
+ if (contact.Mobile2 != "" && IsValidPhoneNumberBasic(contact.Mobile2))
+ {
+ CreateContactPhoneDto dto = new CreateContactPhoneDto();
+ dto.Label = "Office";
+ dto.PhoneNumber = contact.Mobile2;
+ result.Add(dto);
+ }
+
+ if (contact.Mobile3 != "" && IsValidPhoneNumberBasic(contact.Mobile3))
+ {
+ CreateContactPhoneDto dto = new CreateContactPhoneDto();
+ dto.Label = "Office";
+ dto.PhoneNumber = contact.Mobile3;
+ result.Add(dto);
+ }
+ return result.Count > 0 ? result : null;
+ }
+
+ public static bool IsValidPhoneNumberBasic(string phoneNumber)
+ {
+ if (string.IsNullOrWhiteSpace(phoneNumber))
+ {
+ return false;
+ }
+
+ // Remove common non-digit characters for a cleaner check
+ string cleanedNumber = new string(phoneNumber.Where(char.IsDigit).ToArray());
+
+ // Basic check: Assume a typical phone number length (e.g., 7 to 15 digits)
+ // This is highly region-specific. For India, mobile numbers are usually 10 digits.
+ // For US, 10 digits for local, 11 with country code.
+ return cleanedNumber.Length >= 7 && cleanedNumber.Length <= 15;
+ }
+
+ public static bool IsValidEmailMailAddress(string email)
+ {
+ if (string.IsNullOrWhiteSpace(email))
+ {
+ return false;
+ }
+
+ try
+ {
+ // Attempt to create a MailAddress object.
+ // If the format is invalid, it will throw a FormatException.
+ MailAddress m = new MailAddress(email);
+
+ // Optional: You can add more specific checks here if needed,
+ // e.g., checking for specific domain names, but MailAddress itself is very good.
+ return true;
+ }
+ catch (FormatException)
+ {
+ // The email format is invalid.
+ return false;
+ }
+ catch (Exception ex)
+ {
+ // Catch any other unexpected exceptions.
+ Console.WriteLine($"An unexpected error occurred during email validation: {ex.Message}");
+ return false;
+ }
+ }
+
+ public async Task<(List contactsData, List categoryMasters, List tagsMaster, List projectMaster)> ReadExcelData(string filePath)
+ {
+ if (!File.Exists(filePath))
+ {
+ throw new FileNotFoundException($"Excel file not found at: {filePath}");
+ }
+
+ // Set the license context for EPPlus
+ // If you are using EPPlus in a commercial application, you need to acquire a commercial license.
+ // For non-commercial use or development, use the NonCommercial license context.
+
+ ExcelPackage.License.SetNonCommercialPersonal("Vikas");
+
+
+ List contactsData = new List();
+ List categoryMasters = new List();
+ List tagsMaster = new List();
+ List projectMaster = new List();
+
+ using (var package = new ExcelPackage(new FileInfo(filePath)))
+ {
+ // --- Read Transactions Sheet ---
+ ExcelWorksheet transactionsSheet = package.Workbook.Worksheets["CategoryMaster"]; // Assuming sheet name "Transactions"
+ if (transactionsSheet != null)
+ {
+ int rowCount = transactionsSheet.Dimension.Rows;
+ for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
+ {
+ try
+ {
+ categoryMasters.Add(new CategoryMaster
+ {
+ CategoryID = transactionsSheet.Cells[row, 1].Text,
+ Categories = transactionsSheet.Cells[row, 2].Text,
+ Description = transactionsSheet.Cells[row, 3].Text,
+ });
+ }
+ catch (FormatException ex)
+ {
+ Console.WriteLine($"Error parsing transaction data on row {row}: {ex.Message}");
+ // Optionally, skip row or log error more verbosely
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("Transactions sheet not found in the Excel file.");
+ }
+
+ ExcelWorksheet tagsMasterSheet = package.Workbook.Worksheets["TagMaster"]; // Assuming sheet name "Transactions"
+ if (tagsMasterSheet != null)
+ {
+ int rowCount = tagsMasterSheet.Dimension.Rows;
+ for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
+ {
+ try
+ {
+ tagsMaster.Add(new TagsMaster
+ {
+ TagID = tagsMasterSheet.Cells[row, 1].Text,
+ Tag = tagsMasterSheet.Cells[row, 2].Text,
+ });
+ }
+ catch (FormatException ex)
+ {
+ Console.WriteLine($"Error parsing tags data on row {row}: {ex.Message}");
+ // Optionally, skip row or log error more verbosely
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("tags sheet not found in the Excel file.");
+ }
+
+ ExcelWorksheet projectsMasterSheet = package.Workbook.Worksheets["ProjectMaster"]; // Assuming sheet name "Transactions"
+ if (projectsMasterSheet != null)
+ {
+ int rowCount = projectsMasterSheet.Dimension.Rows;
+ for (int row = 2; row <= rowCount; row++) // Assuming header in row 1
+ {
+ try
+ {
+ projectMaster.Add(new ProjectMaster
+ {
+ ProjectID = projectsMasterSheet.Cells[row, 1].Text,
+ ProjectName = projectsMasterSheet.Cells[row, 2].Text,
+ });
+ }
+ catch (FormatException ex)
+ {
+ Console.WriteLine($"Error parsing projects data on row {row}: {ex.Message}");
+ // Optionally, skip row or log error more verbosely
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("projects sheet not found in the Excel file.");
+ }
+
+ // --- Read Master Data Sheet ---
+ ExcelWorksheet masterSheet = package.Workbook.Worksheets["Contacts"]; // Assuming sheet name "MasterData"
+ if (masterSheet != null)
+ {
+ int rowCount = masterSheet.Dimension.Rows;
+ for (int row = 3; row <= rowCount; row++) // Assuming header in row 1
+ {
+ try
+ {
+ contactsData.Add(new Contacts
+ {
+ BucketId = masterSheet.Cells[row, 1].Text,
+ Owner = masterSheet.Cells[row, 2].Text,
+ Name = masterSheet.Cells[row, 3].Text,
+ Designation = masterSheet.Cells[row, 4].Text,
+ Organization = masterSheet.Cells[row, 5].Text,
+
+ Mobile1 = masterSheet.Cells[row, 6].Text,
+ Mobile2 = masterSheet.Cells[row, 7].Text,
+ Mobile3 = masterSheet.Cells[row, 8].Text,
+ Email1 = masterSheet.Cells[row, 9].Text,
+ Email2 = masterSheet.Cells[row, 10].Text,
+ Location = masterSheet.Cells[row, 11].Text,
+ Address = masterSheet.Cells[row, 12].Text,
+ MoreInformation = masterSheet.Cells[row, 13].Text,
+ Category = masterSheet.Cells[row, 14].Text,
+ Tags = masterSheet.Cells[row, 15].Text,
+ Project = masterSheet.Cells[row, 16].Text
+ });
+ }
+ catch (FormatException ex)
+ {
+ Console.WriteLine($"Error parsing master data on row {row}: {ex.Message}");
+ // Optionally, skip row or log error more verbosely
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("MasterData sheet not found in the Excel file.");
+ }
+
+
+ }
+
+ return (contactsData, categoryMasters, tagsMaster, projectMaster);
+ }
+
+ }
+}
diff --git a/Marco.Pms.UtilityApplication/MainWindow.xaml b/Marco.Pms.UtilityApplication/MainWindow.xaml
new file mode 100644
index 0000000..553aecb
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/MainWindow.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/Marco.Pms.UtilityApplication/MainWindow.xaml.cs b/Marco.Pms.UtilityApplication/MainWindow.xaml.cs
new file mode 100644
index 0000000..8618f0c
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/MainWindow.xaml.cs
@@ -0,0 +1,47 @@
+using Marco.Pms.Model.Dtos.Directory;
+using Microsoft.Win32;
+using System.Windows;
+
+namespace Marco.Pms.UtilityApplication
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ DirectoryHelper helper = new DirectoryHelper();
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ private void btnFileUpload_Click(object sender, RoutedEventArgs e)
+ {
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ openFileDialog.Filter = "Excel files (*.xlsx)|*.xlsx|CSV files (*.csv)|*.csv"; // Optional: filter file types
+
+ if (openFileDialog.ShowDialog() == true)
+ {
+ string filePath = openFileDialog.FileName;
+ // Now you can use filePath to read or process the selected file
+ txtFilePath.Text = filePath;
+ //MessageBox.Show($"Selected file: {filePath}");
+
+ }
+ }
+
+
+ private async void btnSubmit_Click(object sender, RoutedEventArgs e)
+ {
+ List contactsData = null;
+ List tagsMaster = null;
+ List projectMaster = null;
+ List categoryMasters = null;
+
+
+ (contactsData, categoryMasters, tagsMaster, projectMaster) = await helper.ReadExcelData(txtFilePath.Text);
+
+ List createContactDto = await helper.GenerateCreateContactDto(contactsData, categoryMasters, tagsMaster, projectMaster);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Marco.Pms.UtilityApplication/Marco.Pms.UtilityApplication.csproj b/Marco.Pms.UtilityApplication/Marco.Pms.UtilityApplication.csproj
new file mode 100644
index 0000000..29064a9
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/Marco.Pms.UtilityApplication.csproj
@@ -0,0 +1,19 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Marco.Pms.UtilityApplication/ProjectMaster.cs b/Marco.Pms.UtilityApplication/ProjectMaster.cs
new file mode 100644
index 0000000..031b637
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/ProjectMaster.cs
@@ -0,0 +1,8 @@
+namespace Marco.Pms.UtilityApplication
+{
+ public class ProjectMaster
+ {
+ public string ProjectID { get; set; }
+ public string ProjectName { get; set; }
+ }
+}
diff --git a/Marco.Pms.UtilityApplication/TagsMaster.cs b/Marco.Pms.UtilityApplication/TagsMaster.cs
new file mode 100644
index 0000000..a6920e8
--- /dev/null
+++ b/Marco.Pms.UtilityApplication/TagsMaster.cs
@@ -0,0 +1,8 @@
+namespace Marco.Pms.UtilityApplication
+{
+ public class TagsMaster
+ {
+ public string TagID { get; set; }
+ public string Tag { get; set; }
+ }
+}
diff --git a/marco.pms.api.sln b/marco.pms.api.sln
index 424b709..adbbd62 100644
--- a/marco.pms.api.sln
+++ b/marco.pms.api.sln
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.Services", "Marco
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.CacheHelper", "Marco.Pms.CacheHelper\Marco.Pms.CacheHelper.csproj", "{1A105C22-4ED7-4F54-8834-6923DDD96852}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Marco.Pms.UtilityApplication", "Marco.Pms.UtilityApplication\Marco.Pms.UtilityApplication.csproj", "{1F67DA6E-C4B4-4D48-8484-713F801772A5}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,10 @@ Global
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A105C22-4ED7-4F54-8834-6923DDD96852}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1F67DA6E-C4B4-4D48-8484-713F801772A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1F67DA6E-C4B4-4D48-8484-713F801772A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1F67DA6E-C4B4-4D48-8484-713F801772A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1F67DA6E-C4B4-4D48-8484-713F801772A5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE