SharePoint 2010の受信処理機能を使用する方法-ケーススタディ

多くの場合、企業のビジネスプロセスには、バーコードを含むドキュメントを処理し、それを何らかの会計システムに入力する必要があります。 これは、たとえば、鉄道輸送業界や航空会社に関連しています。チケット番号は、会社のエージェントが電子メールで送信するクーポンのバーコードで保護されています。 オペレーターは、毎日数千のクーポンを処理して内部会計システムに入力することを余儀なくされています。



作業は日常的であり、人的要因がエラーを引き起こします。 プロセスを自動化し、レターとその添付ファイルを手動で処理する必要性からオペレーターを救う方法は? MS SharePointを使用した簡単なソリューションを見つけました。 いつものように、既存のシステム機能、既存のライブラリ、およびプログラミングマジックのいくつかを最大限に活用しようとしました。

交換のセットアップ


ドキュメント読み、すべてを正しく構成したら、数回タップするだけで、ドキュメントライブラリの設定ですべてが完了します。











SharePointを使用するサーバーでは、メールサーバーはレターを受信するように構成されています。 emlファイルの形式の受信トレイの文字は、受信トレイフォルダ内のファイルシステムに表示されます。 SharePointは2分ごとに受信トレイフォルダーをチェックし、そこにファイルがある場合は、それらを処理して削除します。



行内のすべてのファイル(受信者アドレスが正しくない、追加タグが正しくない、またはOutlook Expressを使用して作成された)は処理されないことに注意してください。ファイルはIISからSMTPサーバーによって作成する必要があります。



その結果、このアドレスに到着するすべての文字はドキュメントライブラリに分類されます。







各レターには、jpg、png、tiff、pdf形式の1つ以上の添付ファイルが含まれます。ここには、バーコードでマークされた1つ以上のドキュメントがあります。







バーコード認識には、オープンソースのzxingライブラリを使用しました。これを使用して、さまざまなタイプのバーコードをスキャンおよび処理できます。 ここでは、ライブラリの機能、またはむしろ終端シンボルのアルゴリズムをわずかに改良する必要がありました。 顧客は独自の特定のエンコーディングを使用しますが、これはzxingではサポートされていません(codabarに似ています)。



次に、15分ごとにzxingを使用して、Exchangeを介して自動的にポータルに到達する電子メールの添付ファイル内のドキュメントを識別するイベントハンドラーを実装しました。 次に、彼はライブラリからそれらを取り出し、添付ファイル、送信者アドレス、および送信者コード(会社のエージェントの個人識別子)を引き出します。



ご注意 次に、CDOを介して電子メールデータを取得し、そのStream-sを操作する方法に関する多くのルーチンコードがあります。

コード
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using ADODB; using CDO; using ETR.REBT.BarcodeReader; using Stream = System.IO.Stream; namespace ETR.BusinessLogic.EBTBlanks { internal class EBTMailParser { private static readonly string[] SupportedExtensions = { "application/pdf" , "image/jpeg" , "image/bmp" , "image/png" , "image/tiff" }; private static readonly Regex AgencyCodePattern = new Regex(@"{\w*}"); public static EBTMailParseResult ParseEmail(Stream emlStream) { var result = new EBTMailParseResult { Success = true }; Message msg = new MessageClass(); ADODB.Stream stream = new StreamClass(); try { CopyStream(emlStream, stream); msg.DataSource.OpenObject(stream, "_Stream"); result.FromAddress = msg.From; result.SendDate = msg.SentOn; result.ReceivedDate = msg.ReceivedTime; string agentCode; if (TryParseAgencyCode(msg.Subject, out agentCode)) { result.AgencyCode = agentCode; } else { result.Status = "    .      ,        . , {12345}"; return result; } if (msg.Attachments.Count == 0) { result.Status = "      "; return result; } result.Attachments = ParseAttachments(msg.Attachments).ToList(); return result; } catch (Exception ex) { //If we get unknown error - we don't mark letter as parsed an try next time result.Success = false; result.Status = " ."; result.ExceptionMessage = ex.Message; return result; } finally { stream.Close(); } } private static bool TryParseAgencyCode(string subject, out string result) { var allMatchResults = AgencyCodePattern.Matches(subject); if (allMatchResults.Count != 1 || false == allMatchResults[0].Success) { result = null; return false; } result = allMatchResults[0].Value.Substring(1, allMatchResults[0].Value.Length - 2); return true; } private static void CopyStream(Stream netStream, ADODB.Stream adoStream) { //adoStream.Open(Type.Missing, ADODB.ConnectModeEnum.adModeUnknown, ADODB.StreamOpenOptionsEnum.adOpenStreamUnspecified, String.Empty, String.Empty); adoStream.Type = StreamTypeEnum.adTypeBinary; adoStream.Open(); netStream.Position = 0; var buffer = new byte[1024]; while (netStream.Read(buffer, 0, buffer.Length) != 0) { adoStream.Write(buffer); } adoStream.Flush(); } private static void CopyStream(ADODB.Stream adoStream, Stream netStream) { while (!adoStream.EOS) { var bytes = (byte[])adoStream.Read(1024); netStream.Write(bytes, 0, bytes.Length); } netStream.Flush(); } private static IEnumerable<EBTAttachmentParseResult> ParseAttachments(IBodyParts attachments) { var barcodeReader = new BarcodeReader(true); for (var i = 1; i <= attachments.Count; i++) { var attachment = attachments[i]; var fileResult = new EBTAttachmentParseResult { FileName = attachment.FileName }; if (false == SupportedExtensions.Any(ct => ct == attachment.ContentMediaType)) { fileResult.Status = String.Format(" {0}  ", attachment.ContentMediaType); yield return fileResult; } var stream = attachment.GetDecodedContentStream(); try { var memoryStream = new MemoryStream(); CopyStream(stream, memoryStream); memoryStream.Position = 0; var parseResult = barcodeReader.Decode(memoryStream, attachment.FileName); fileResult.Status = parseResult.AllPages > parseResult.RecognizedPages ? String.Format(" {0}  {1} ", parseResult.RecognizedPages, parseResult.AllPages) : fileResult.Status; fileResult.Stream = memoryStream; if (parseResult.ResultList != null && parseResult.ResultList.Count > 0) { fileResult.BarcodeNumbers = parseResult.ResultList.Select(b => ParseBarcode(b.Text)).ToList(); } } catch (Exception ex) { fileResult.Status = " ."; fileResult.ExceptionMessage = ex.Message; } finally { stream.Close(); } yield return fileResult; } } private static EBTBarcodeParseResult ParseBarcode(string barCode) { if (barCode.Length != 15) return new EBTBarcodeParseResult { BarcodeNumber = barCode, Status = "    " }; return new EBTBarcodeParseResult { BarcodeNumber = barCode, CouponNumber = barCode.Substring(1, 13).Insert(3, " ") }; } } }
      
      







ハンドラーが何らかのエラー(不適切なファイル拡張子、エージェントコードが認識されないなど)を検出した場合、その説明を含むイベントがEventBusに記録されます。



エラーがない場合、添付ファイルはライブラリを介して解析され、情報が読み取られるバーコードはそれらから「プルアウト」されます。 特定のバーコードごとに、SharePointでフォームが作成されます。これは、オペレーターが元のドキュメントを受け取ったときに既に処理されています。







結論として、イベントがEventBusに送信され、レターが解析されたというメッセージ、ファイル内で見つかったファイルの数、添付ファイルにあるクーポンの数、クーポンにあるチケットの数が通知されます。 すべての関係者はプッシュ通知を受け取ります。







このビジネスプロセスは、大規模な運送会社の大規模なオフィス業務のごく一部です。 また、受信ドキュメントを頻繁に処理する必要がある他の領域、およびSharePointとExchangeが使用される他の領域に簡単に変換できます。



そのような状況での私たちの仮定は、既存のシステムの改善を止めず、利用可能な手段、工夫、プログラミングスキルを使用してすべてのルーチンを自動化することです。



All Articles