Reopening cases logic
This commit is contained in:
+192
-66
@@ -26,6 +26,7 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
trayMenu = new ContextMenuStrip();
|
trayMenu = new ContextMenuStrip();
|
||||||
trayMenu.Items.Add("Create Rule (Selected Email)", null, ProcessEmail_Click);
|
trayMenu.Items.Add("Create Rule (Selected Email)", null, ProcessEmail_Click);
|
||||||
|
trayMenu.Items.Add("Create Rule (Manual ID)", null, CreateRuleManual_Click);
|
||||||
trayMenu.Items.Add("Remove Rule (Selected Email)", null, RemoveRuleFromSelected_Click);
|
trayMenu.Items.Add("Remove Rule (Selected Email)", null, RemoveRuleFromSelected_Click);
|
||||||
trayMenu.Items.Add("Remove Rule (Manual ID)", null, RemoveRule_Click);
|
trayMenu.Items.Add("Remove Rule (Manual ID)", null, RemoveRule_Click);
|
||||||
trayMenu.Items.Add("-");
|
trayMenu.Items.Add("-");
|
||||||
@@ -42,17 +43,14 @@ namespace OutlookCaseHelper
|
|||||||
private void InitializeTimer()
|
private void InitializeTimer()
|
||||||
{
|
{
|
||||||
monitorTimer = new System.Windows.Forms.Timer();
|
monitorTimer = new System.Windows.Forms.Timer();
|
||||||
monitorTimer.Interval = 60000; // verifica a cada 60 segundos
|
monitorTimer.Interval = 60000;
|
||||||
monitorTimer.Tick += MonitorTimer_Tick;
|
monitorTimer.Tick += MonitorTimer_Tick;
|
||||||
monitorTimer.Start();
|
monitorTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MonitorTimer_Tick(object? sender, EventArgs e)
|
private void MonitorTimer_Tick(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try { outlookHelper.ProcessActiveRules(); }
|
||||||
{
|
|
||||||
outlookHelper.ProcessActiveRules();
|
|
||||||
}
|
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,30 +63,93 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
"No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111",
|
"No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111",
|
||||||
"Warning",
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Warning);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId);
|
// Verifica se já existe regra ativa
|
||||||
|
if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!",
|
||||||
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica se existe em Closed — reabre sem pedir nome
|
||||||
|
if (outlookHelper.ExistsInClosed(trackingId))
|
||||||
|
{
|
||||||
|
var triggerEmail = outlookHelper.GetSelectedEmail();
|
||||||
|
bool reopened = outlookHelper.ReopenFromClosed(trackingId, triggerEmail);
|
||||||
|
if (reopened)
|
||||||
|
MessageBox.Show(
|
||||||
|
$"Case reopened! Folder moved from Closed to Active.\n\nTrackingID: {trackingId}",
|
||||||
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
else
|
||||||
|
MessageBox.Show("Error reopening case.",
|
||||||
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caso novo — pede nome
|
||||||
|
var ruleForm = new CreateRuleForm(trackingId, readonlyId: true);
|
||||||
|
if (ruleForm.ShowDialog() != DialogResult.OK) return;
|
||||||
|
|
||||||
|
string folderName = ruleForm.FolderName;
|
||||||
|
|
||||||
|
bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
|
||||||
var activeCount = outlookHelper.GetActiveRules().Count;
|
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
$"Rule created! Emails moved and monitoring started.\n\nTrackingID: {trackingId}\nActive rules: {activeCount}",
|
$"Rule created! Emails moved and monitoring started.\n\nFolder: {folderName}\nActive rules: {outlookHelper.GetActiveRules().Count}",
|
||||||
"Success",
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Information);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
MessageBox.Show("Error processing email. Make sure Outlook is open.",
|
||||||
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateRuleManual_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ruleForm = new CreateRuleForm("", readonlyId: false);
|
||||||
|
if (ruleForm.ShowDialog() != DialogResult.OK) return;
|
||||||
|
|
||||||
|
string trackingId = ruleForm.TrackingId;
|
||||||
|
string folderName = ruleForm.FolderName;
|
||||||
|
|
||||||
|
if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!",
|
||||||
"Error processing email. Make sure Outlook is open.",
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
"Error",
|
return;
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifica se existe em Closed — reabre sem pedir nome
|
||||||
|
if (outlookHelper.ExistsInClosed(trackingId))
|
||||||
|
{
|
||||||
|
bool reopened = outlookHelper.ReopenFromClosed(trackingId);
|
||||||
|
if (reopened)
|
||||||
|
MessageBox.Show(
|
||||||
|
$"Case reopened! Folder moved from Closed to Active.\n\nTrackingID: {trackingId}",
|
||||||
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
else
|
||||||
|
MessageBox.Show("Error reopening case.",
|
||||||
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName);
|
||||||
|
if (success)
|
||||||
|
MessageBox.Show(
|
||||||
|
$"Rule created! Emails moved and monitoring started.\n\nFolder: {folderName}\nActive rules: {outlookHelper.GetActiveRules().Count}",
|
||||||
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
else
|
||||||
|
MessageBox.Show("Error creating rule. Make sure Outlook is open.",
|
||||||
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -101,25 +162,24 @@ namespace OutlookCaseHelper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var form = new InputForm("Enter TrackingID to remove:", "Remove Rule");
|
var form = new InputForm("Enter TrackingID to remove:", "Remove Rule");
|
||||||
if (form.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(form.TrackingId))
|
if (form.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(form.Value))
|
||||||
{
|
{
|
||||||
bool success = outlookHelper.RemoveRuleAndMoveToClosed(form.TrackingId);
|
string? folderName = outlookHelper.FindRuleByTrackingId(form.Value.Trim());
|
||||||
|
if (folderName == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"No active rule found for TrackingID#{form.Value}.",
|
||||||
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = outlookHelper.RemoveRuleAndMoveToClosed(folderName);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nMonitoring stopped.",
|
$"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.",
|
||||||
"Success",
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Information);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
MessageBox.Show("Error removing rule. Check if folder exists.",
|
||||||
MessageBox.Show(
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
"Error removing rule. Check if folder exists.",
|
|
||||||
"Error",
|
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -137,29 +197,26 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
"No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111",
|
"No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111",
|
||||||
"Warning",
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Warning);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = outlookHelper.RemoveRuleAndMoveToClosed(trackingId);
|
string? folderName = outlookHelper.FindRuleByTrackingId(trackingId);
|
||||||
|
if (folderName == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show($"No active rule found for TrackingID#{trackingId}.",
|
||||||
|
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = outlookHelper.RemoveRuleAndMoveToClosed(folderName);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
$"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nTrackingID: {trackingId}\nMonitoring stopped.",
|
$"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.",
|
||||||
"Success",
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Information);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
MessageBox.Show("Error removing rule. Check if folder exists and Outlook is open.",
|
||||||
MessageBox.Show(
|
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
"Error removing rule. Check if folder exists and Outlook is open.",
|
|
||||||
"Error",
|
|
||||||
MessageBoxButtons.OK,
|
|
||||||
MessageBoxIcon.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -179,36 +236,105 @@ namespace OutlookCaseHelper
|
|||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class CreateRuleForm : Form
|
||||||
|
{
|
||||||
|
private TextBox txtId;
|
||||||
|
private TextBox txtName;
|
||||||
|
private Label lblPreview;
|
||||||
|
public string TrackingId { get; private set; } = "";
|
||||||
|
public string FolderName { get; private set; } = "";
|
||||||
|
|
||||||
|
public CreateRuleForm(string trackingId, bool readonlyId)
|
||||||
|
{
|
||||||
|
this.Text = "Create Rule";
|
||||||
|
this.Size = new Size(420, 230);
|
||||||
|
this.MinimumSize = new Size(420, 230);
|
||||||
|
this.MaximumSize = new Size(420, 230);
|
||||||
|
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
|
||||||
|
var lblId = new Label { Text = "TrackingID (required):", Left = 20, Top = 15, Width = 370, Height = 20 };
|
||||||
|
txtId = new TextBox { Left = 20, Top = 38, Width = 370, Height = 24, Text = trackingId, ReadOnly = readonlyId };
|
||||||
|
if (readonlyId) txtId.BackColor = System.Drawing.SystemColors.Control;
|
||||||
|
|
||||||
|
var lblName = new Label { Text = "Additional name (optional):", Left = 20, Top = 72, Width = 370, Height = 20 };
|
||||||
|
txtName = new TextBox { Left = 20, Top = 95, Width = 370, Height = 24 };
|
||||||
|
|
||||||
|
lblPreview = new Label { Left = 20, Top = 128, Width = 370, Height = 20, ForeColor = System.Drawing.Color.Gray };
|
||||||
|
UpdatePreview(trackingId);
|
||||||
|
|
||||||
|
var btnOk = new Button { Text = "OK", Left = 220, Top = 158, Width = 80, DialogResult = DialogResult.OK };
|
||||||
|
var btnCancel = new Button { Text = "Cancel", Left = 310, Top = 158, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
|
||||||
|
txtId.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
||||||
|
txtName.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
||||||
|
|
||||||
|
this.Controls.AddRange(new Control[] { lblId, txtId, lblName, txtName, lblPreview, btnOk, btnCancel });
|
||||||
|
this.AcceptButton = btnOk;
|
||||||
|
this.CancelButton = btnCancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePreview(string id)
|
||||||
|
{
|
||||||
|
string name = txtName?.Text.Trim() ?? "";
|
||||||
|
string preview = string.IsNullOrEmpty(name) ? id : $"{id} | {name}";
|
||||||
|
if (lblPreview != null)
|
||||||
|
lblPreview.Text = $"Folder: {preview}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||||
|
{
|
||||||
|
if (this.DialogResult == DialogResult.OK)
|
||||||
|
{
|
||||||
|
TrackingId = txtId.Text.Trim();
|
||||||
|
string name = txtName.Text.Trim();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(TrackingId))
|
||||||
|
{
|
||||||
|
MessageBox.Show("TrackingID is required!", "Validation",
|
||||||
|
MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
|
e.Cancel = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FolderName = string.IsNullOrEmpty(name) ? TrackingId : $"{TrackingId} | {name}";
|
||||||
|
}
|
||||||
|
base.OnFormClosing(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class InputForm : Form
|
private class InputForm : Form
|
||||||
{
|
{
|
||||||
private TextBox txtInput;
|
private TextBox txtInput;
|
||||||
public string TrackingId { get; private set; } = "";
|
public string Value { get; private set; } = "";
|
||||||
|
|
||||||
public InputForm(string prompt, string title)
|
public InputForm(string prompt, string title)
|
||||||
{
|
{
|
||||||
this.Text = title;
|
this.Text = title;
|
||||||
this.Width = 400;
|
this.Size = new Size(380, 150);
|
||||||
this.Height = 150;
|
this.MinimumSize = new Size(380, 150);
|
||||||
|
this.MaximumSize = new Size(380, 150);
|
||||||
|
this.FormBorderStyle = FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
this.StartPosition = FormStartPosition.CenterScreen;
|
this.StartPosition = FormStartPosition.CenterScreen;
|
||||||
|
|
||||||
var label = new Label { Text = prompt, Left = 20, Top = 20, Width = 360, Height = 30 };
|
var label = new Label { Text = prompt, Left = 20, Top = 15, Width = 330, Height = 25 };
|
||||||
txtInput = new TextBox { Left = 20, Top = 60, Width = 340, Height = 30 };
|
txtInput = new TextBox { Left = 20, Top = 45, Width = 330, Height = 24 };
|
||||||
|
|
||||||
var btnOk = new Button { Text = "OK", Left = 200, Top = 100, Width = 80, DialogResult = DialogResult.OK };
|
var btnOk = new Button { Text = "OK", Left = 155, Top = 80, Width = 80, DialogResult = DialogResult.OK };
|
||||||
var btnCancel = new Button { Text = "Cancel", Left = 290, Top = 100, Width = 80, DialogResult = DialogResult.Cancel };
|
var btnCancel = new Button { Text = "Cancel", Left = 245, Top = 80, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
|
||||||
this.Controls.Add(label);
|
|
||||||
this.Controls.Add(txtInput);
|
|
||||||
this.Controls.Add(btnOk);
|
|
||||||
this.Controls.Add(btnCancel);
|
|
||||||
|
|
||||||
|
this.Controls.AddRange(new Control[] { label, txtInput, btnOk, btnCancel });
|
||||||
this.AcceptButton = btnOk;
|
this.AcceptButton = btnOk;
|
||||||
this.CancelButton = btnCancel;
|
this.CancelButton = btnCancel;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||||
{
|
{
|
||||||
TrackingId = txtInput.Text;
|
Value = txtInput.Text;
|
||||||
base.OnFormClosing(e);
|
base.OnFormClosing(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ namespace OutlookCaseHelper
|
|||||||
inboxItems = inboxFolder.Items;
|
inboxItems = inboxFolder.Items;
|
||||||
inboxItems.ItemAdd += OnEmailReceived;
|
inboxItems.ItemAdd += OnEmailReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sentFolder != null)
|
if (sentFolder != null)
|
||||||
{
|
{
|
||||||
sentItems = sentFolder.Items;
|
sentItems = sentFolder.Items;
|
||||||
@@ -62,8 +61,9 @@ namespace OutlookCaseHelper
|
|||||||
if (item is not Outlook.MailItem mail) return;
|
if (item is not Outlook.MailItem mail) return;
|
||||||
if (mail.Subject == null) return;
|
if (mail.Subject == null) return;
|
||||||
|
|
||||||
foreach (var trackingId in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
|
string trackingId = ExtractTrackingId(folderName);
|
||||||
if (mail.Subject.Contains($"TrackingID#{trackingId}"))
|
if (mail.Subject.Contains($"TrackingID#{trackingId}"))
|
||||||
{
|
{
|
||||||
Outlook.Folder? inboxFolder =
|
Outlook.Folder? inboxFolder =
|
||||||
@@ -72,7 +72,7 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
||||||
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
||||||
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, trackingId);
|
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName);
|
||||||
|
|
||||||
mail.Move(trackingFolder);
|
mail.Move(trackingFolder);
|
||||||
break;
|
break;
|
||||||
@@ -90,8 +90,9 @@ namespace OutlookCaseHelper
|
|||||||
if (item is not Outlook.MailItem mail) return;
|
if (item is not Outlook.MailItem mail) return;
|
||||||
if (mail.Subject == null) return;
|
if (mail.Subject == null) return;
|
||||||
|
|
||||||
foreach (var trackingId in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
|
string trackingId = ExtractTrackingId(folderName);
|
||||||
if (mail.Subject.Contains($"TrackingID#{trackingId}"))
|
if (mail.Subject.Contains($"TrackingID#{trackingId}"))
|
||||||
{
|
{
|
||||||
Outlook.Folder? inboxFolder =
|
Outlook.Folder? inboxFolder =
|
||||||
@@ -100,7 +101,7 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
||||||
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
||||||
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, trackingId);
|
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName);
|
||||||
|
|
||||||
mail.Move(trackingFolder);
|
mail.Move(trackingFolder);
|
||||||
break;
|
break;
|
||||||
@@ -110,6 +111,42 @@ namespace OutlookCaseHelper
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ExtractTrackingId(string folderName)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(folderName, @"^(\d+)");
|
||||||
|
return match.Success ? match.Groups[1].Value : folderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? FindRuleByTrackingId(string trackingId)
|
||||||
|
{
|
||||||
|
foreach (var rule in activeRules)
|
||||||
|
{
|
||||||
|
if (ExtractTrackingId(rule) == trackingId)
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifica se existe pasta em Closed com este trackingId
|
||||||
|
public bool ExistsInClosed(string trackingId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Outlook.Folder? inboxFolder =
|
||||||
|
outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
|
||||||
|
if (inboxFolder == null) return false;
|
||||||
|
|
||||||
|
Outlook.Folder? casesFolder = GetFolder(inboxFolder, "Cases");
|
||||||
|
if (casesFolder == null) return false;
|
||||||
|
|
||||||
|
Outlook.Folder? closedFolder = GetFolder(casesFolder, "Closed");
|
||||||
|
if (closedFolder == null) return false;
|
||||||
|
|
||||||
|
return GetFolderStartingWith(closedFolder, trackingId) != null;
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadRules()
|
private void LoadRules()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -159,7 +196,8 @@ namespace OutlookCaseHelper
|
|||||||
catch { return null; }
|
catch { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CreateFolderAndMoveEmails(string trackingId)
|
// Reabre caso existente em Closed e move o email trigger para lá
|
||||||
|
public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -169,17 +207,48 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
||||||
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
||||||
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, trackingId);
|
Outlook.Folder? closedFolder = GetFolder(casesFolder, "Closed");
|
||||||
|
if (closedFolder == null) return false;
|
||||||
|
|
||||||
|
Outlook.Folder? closedTracking = GetFolderStartingWith(closedFolder, trackingId);
|
||||||
|
if (closedTracking == null) return false;
|
||||||
|
|
||||||
|
string existingName = closedTracking.Name;
|
||||||
|
closedTracking.MoveTo(activeFolder);
|
||||||
|
|
||||||
|
// Move o email que originou a reabertura para a pasta
|
||||||
|
if (triggerEmail != null)
|
||||||
|
{
|
||||||
|
Outlook.Folder? movedFolder = GetFolder(activeFolder, existingName);
|
||||||
|
if (movedFolder != null)
|
||||||
|
triggerEmail.Move(movedFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeRules.Add(existingName);
|
||||||
|
SaveRules();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CreateFolderAndMoveEmails(string trackingId, string folderName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Outlook.Folder? inboxFolder =
|
||||||
|
outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
|
||||||
|
if (inboxFolder == null) return false;
|
||||||
|
|
||||||
|
Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases");
|
||||||
|
Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active");
|
||||||
|
Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName);
|
||||||
|
|
||||||
// Usa Restrict para mover apenas emails com o TrackingID
|
|
||||||
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
||||||
|
|
||||||
Outlook.Items restricted = inboxFolder.Items.Restrict(filter);
|
Outlook.Items restricted = inboxFolder.Items.Restrict(filter);
|
||||||
var toMove = new List<Outlook.MailItem>();
|
var toMove = new List<Outlook.MailItem>();
|
||||||
foreach (object item in restricted)
|
foreach (object item in restricted)
|
||||||
{
|
if (item is Outlook.MailItem mail) toMove.Add(mail);
|
||||||
if (item is Outlook.MailItem mail)
|
|
||||||
toMove.Add(mail);
|
|
||||||
}
|
|
||||||
foreach (var mail in toMove)
|
foreach (var mail in toMove)
|
||||||
mail.Move(trackingFolder);
|
mail.Move(trackingFolder);
|
||||||
|
|
||||||
@@ -190,15 +259,12 @@ namespace OutlookCaseHelper
|
|||||||
Outlook.Items restrictedSent = sentFolder.Items.Restrict(filter);
|
Outlook.Items restrictedSent = sentFolder.Items.Restrict(filter);
|
||||||
var toMoveSent = new List<Outlook.MailItem>();
|
var toMoveSent = new List<Outlook.MailItem>();
|
||||||
foreach (object item in restrictedSent)
|
foreach (object item in restrictedSent)
|
||||||
{
|
if (item is Outlook.MailItem mail) toMoveSent.Add(mail);
|
||||||
if (item is Outlook.MailItem mail)
|
|
||||||
toMoveSent.Add(mail);
|
|
||||||
}
|
|
||||||
foreach (var mail in toMoveSent)
|
foreach (var mail in toMoveSent)
|
||||||
mail.Move(trackingFolder);
|
mail.Move(trackingFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
activeRules.Add(trackingId);
|
activeRules.Add(folderName);
|
||||||
SaveRules();
|
SaveRules();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -210,7 +276,7 @@ namespace OutlookCaseHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveRuleAndMoveToClosed(string trackingId)
|
public bool RemoveRuleAndMoveToClosed(string folderName)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -224,13 +290,13 @@ namespace OutlookCaseHelper
|
|||||||
Outlook.Folder? activeFolder = GetFolder(casesFolder, "Active");
|
Outlook.Folder? activeFolder = GetFolder(casesFolder, "Active");
|
||||||
if (activeFolder == null) return false;
|
if (activeFolder == null) return false;
|
||||||
|
|
||||||
Outlook.Folder? trackingFolder = GetFolder(activeFolder, trackingId);
|
Outlook.Folder? trackingFolder = GetFolder(activeFolder, folderName);
|
||||||
if (trackingFolder == null) return false;
|
if (trackingFolder == null) return false;
|
||||||
|
|
||||||
Outlook.Folder closedFolder = GetOrCreateFolder(casesFolder, "Closed");
|
Outlook.Folder closedFolder = GetOrCreateFolder(casesFolder, "Closed");
|
||||||
trackingFolder.MoveTo(closedFolder);
|
trackingFolder.MoveTo(closedFolder);
|
||||||
|
|
||||||
activeRules.Remove(trackingId);
|
activeRules.Remove(folderName);
|
||||||
SaveRules();
|
SaveRules();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -238,29 +304,47 @@ namespace OutlookCaseHelper
|
|||||||
catch { return false; }
|
catch { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessActiveRules()
|
public void ProcessActiveRules() { }
|
||||||
{
|
|
||||||
// Mantido para compatibilidade mas os eventos tratam tudo em tempo real
|
|
||||||
}
|
|
||||||
|
|
||||||
private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name)
|
private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name)
|
||||||
{
|
{
|
||||||
foreach (Outlook.Folder folder in parent.Folders)
|
foreach (Outlook.Folder folder in parent.Folders)
|
||||||
{
|
if (folder.Name == name) return folder;
|
||||||
if (folder.Name == name)
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
return (Outlook.Folder)parent.Folders.Add(name);
|
return (Outlook.Folder)parent.Folders.Add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Outlook.Folder? GetFolder(Outlook.Folder parent, string name)
|
private Outlook.Folder? GetFolder(Outlook.Folder parent, string name)
|
||||||
|
{
|
||||||
|
foreach (Outlook.Folder folder in parent.Folders)
|
||||||
|
if (folder.Name == name) return folder;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Outlook.Folder? GetFolderStartingWith(Outlook.Folder parent, string trackingId)
|
||||||
{
|
{
|
||||||
foreach (Outlook.Folder folder in parent.Folders)
|
foreach (Outlook.Folder folder in parent.Folders)
|
||||||
{
|
{
|
||||||
if (folder.Name == name)
|
string name = folder.Name;
|
||||||
|
if (name == trackingId ||
|
||||||
|
name.StartsWith(trackingId + " ") ||
|
||||||
|
name.StartsWith(trackingId + "|"))
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expõe o email selecionado para ser usado no reopen
|
||||||
|
public Outlook.MailItem? GetSelectedEmail()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Outlook.Explorer activeExplorer = outlookApp.ActiveExplorer();
|
||||||
|
if (activeExplorer == null) return null;
|
||||||
|
Outlook.Selection selection = activeExplorer.Selection;
|
||||||
|
if (selection.Count == 0) return null;
|
||||||
|
return selection[1] as Outlook.MailItem;
|
||||||
|
}
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
Reference in New Issue
Block a user