フッターコンテンツにスキップ
IRONPDFの使用

ASP.NET用PDFビューア:.NET 10でPDFを表示する方法

手動での見積もり作成の問題点

IronPDF ホームページ 営業担当者がCRMからWordテンプレートに行アイテムをコピーするのに費やす時間は、販売を行っていない時間です。 10人の担当者チームのそれぞれが20のアクティブな機会を追っている中、その時間は積み重なりますが、結果は信頼できるものではありません。 価格レベルが誤って適用され、割引フィールドが前四半期のレートのままとなり、古いテンプレートバージョンからの契約条件の文言が、レビューされずに顧客に送られる文書に紛れ込みます。

タイムラインの問題は、精度の問題を悪化させます。 火曜日の午後に見積もりを依頼し、水曜日の夜に受け取る見込み客は、一日中その取引が本物かどうかを考えてしまいます。 PDFファイルが届く頃には、彼らの注意はより迅速に対応した競合他社に移っているかもしれません。

既存のCPQツールはこの一部を解決しますが、クリーンなPDFファイルを既存の機会データから生成するだけのチームにとっては、Enterprise価格や実装のタイムラインが合いません。 フォーマットされた提案ではなく、スプレッドシートやプレーンテキストの価格表を送信することは、見込み客に対してその会社の販売プロセスが即興であることを示唆します。 見込み客が修正を依頼すると、バージョンの混乱が倍増し、複数のバージョンがCRMレコードに紐付けられずにメールの添付ファイルとして浮遊します。

シナリオはさまざまです。Salesforceからライセンス見積もりを取得するB2Bソフトウェア会社、ERPのラインアイテムから部品と価格の提案を生成する製造業者、内部見積もりからプロジェクト範囲文書を作成する代理店、小売購買者向けにボリュームディスカウントオファーを作成する卸売業者などです。 根本的な対立はどの場合でも同じです。

ソリューション: 機会データから直接見積を生成

IronPDFは、強力な.NET PDFライブラリであり、.NETアプリケーションがCRMの機会データから直接、ブランド化されたPDF見積書や提案書を生成することができます。 担当者が商談を見積もり準備完了にマークしたり、内部ツールでボタンをクリックしたりすると、アプリケーションはCRMまたはデータベースから品目、価格、顧客情報、条件を取得し、HTMLテンプレートまたはHTMLコンテンツ文字列に入力します。そして、ChromePdfRendererがそのHTMLからC# PDFを生成します

見込み客に見積もりがメールで送信され、送信されたドキュメントは自動的にCRMレコードに記録されます。手動のフォーマットは不要で、Wordテンプレートも必要なく、1ドキュメントごとのSaaS料金もかかりません。 レンダリングは、単一のNuGetパッケージとして既存 for .NETアプリケーション内で実行されます。 テンプレートはチームが所有し、バージョン管理されています。一箇所で更新されると、ファイルを営業チームに配布することなく、すべての今後の見積もりに反映されます。

実際の使用方法

1. トリガーが見積もりを開始します

パイプラインは、営業担当者がCRM UIで"見積を生成"をクリックするか、商談が特定のパイプラインステージに自動的に入るか、外部の自動化プラットフォームが見積エンドポイントにAPI呼び出しを行うと開始されます。 すべての3つのエントリーポイントが同じ生成フローにフィードされ、トリガーメカニズムはその後に起こることを変更しません。

アプリケーションはCRMまたはデータベースに対して、見積もりに必要なすべてを照会します:見込み会社名、連絡先名およびメール、SKUを含む項目、説明、数量、単価、適用された割引率、およびライン合計。 小計、税の計算、総合計; 支払条件、見積有効期間、および担当者が商機に追加したカスタムメモ。

2. HTMLテンプレートは引用のレイアウトを定義します

このテンプレートは、見積書の全体的な視覚構造を処理します:会社のロゴとヘッダー、"Prepared for"ブロックには見込み客の詳細、項目ごとのテーブルには説明、数量、単価、割引、合計金額の列、小計と総合計の概要、利用規約セクション、担当者の名前、役職、直接連絡先を含むフッターがあります。

C#ハンドラーで機会のラインアイテムを繰り返し処理し、HTML行を構築してから、完全なテンプレートをIronPDFに渡してラインアイテムのテーブルを作成します。 これにより、テンプレート自体ではなくアプリケーション層でロジックを保持します。

HTMLファイルテンプレートの例

例のHTMLテンプレート

3. ChromePdfRenderer が見積もりPDFドキュメントを生成します

IronPDFの強力なレンダリングエンジンにより、HTMLからPDFへの変換が簡単になり、多くの場合、わずか数行のコードで実行できます。

using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;

renderer.RenderingOptions.MarginTop = 20;

renderer.RenderingOptions.MarginBottom = 20;

var lineItemRows = string.Concat(opportunity.LineItems.Select(item => $@"
    <tr>
        <td>{item.Description}</td>
        <td style='text-align:center'>{item.Quantity}</td>
        <td style='text-align:right'>{item.UnitPrice:C}</td>
        <td style='text-align:center'>{item.DiscountPct}%</td>
        <td style='text-align:right'>{item.LineTotal:C}</td>
    </tr>"));

string html = $@"
    <h1>Quote — {opportunity.ProspectCompany}</h1>
    <p>Prepared for: {opportunity.ContactName} &lt;{opportunity.ContactEmail}&gt;</p>
    <p>Valid until: {opportunity.QuoteExpiry:MMMM d, yyyy} &nbsp;|&nbsp; Terms: {opportunity.PaymentTerms}</p>
    <table border='1' cellpadding='6' width='100%'>
        <thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Discount</th><th>Total</th></tr></thead>
        <tbody>{lineItemRows}</tbody>
    </table>
    <p style='text-align:right'><strong>Subtotal:</strong> {opportunity.Subtotal:C}</p>
    <p style='text-align:right'><strong>Tax ({opportunity.TaxRatePct}%):</strong> {opportunity.TaxAmount:C}</p>
    <p style='text-align:right'><strong>Grand Total:</strong> {opportunity.GrandTotal:C}</p>
    <hr/><p style='font-size:11px'>{opportunity.TermsAndConditions}</p>";

PdfDocument quote = renderer.RenderHtmlAsPdf(html);
using IronPdf;

var renderer = new ChromePdfRenderer();

renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter;

renderer.RenderingOptions.MarginTop = 20;

renderer.RenderingOptions.MarginBottom = 20;

var lineItemRows = string.Concat(opportunity.LineItems.Select(item => $@"
    <tr>
        <td>{item.Description}</td>
        <td style='text-align:center'>{item.Quantity}</td>
        <td style='text-align:right'>{item.UnitPrice:C}</td>
        <td style='text-align:center'>{item.DiscountPct}%</td>
        <td style='text-align:right'>{item.LineTotal:C}</td>
    </tr>"));

string html = $@"
    <h1>Quote — {opportunity.ProspectCompany}</h1>
    <p>Prepared for: {opportunity.ContactName} &lt;{opportunity.ContactEmail}&gt;</p>
    <p>Valid until: {opportunity.QuoteExpiry:MMMM d, yyyy} &nbsp;|&nbsp; Terms: {opportunity.PaymentTerms}</p>
    <table border='1' cellpadding='6' width='100%'>
        <thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Discount</th><th>Total</th></tr></thead>
        <tbody>{lineItemRows}</tbody>
    </table>
    <p style='text-align:right'><strong>Subtotal:</strong> {opportunity.Subtotal:C}</p>
    <p style='text-align:right'><strong>Tax ({opportunity.TaxRatePct}%):</strong> {opportunity.TaxAmount:C}</p>
    <p style='text-align:right'><strong>Grand Total:</strong> {opportunity.GrandTotal:C}</p>
    <hr/><p style='font-size:11px'>{opportunity.TermsAndConditions}</p>";

PdfDocument quote = renderer.RenderHtmlAsPdf(html);
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.Letter

renderer.RenderingOptions.MarginTop = 20

renderer.RenderingOptions.MarginBottom = 20

Dim lineItemRows As String = String.Concat(opportunity.LineItems.Select(Function(item) $"
    <tr>
        <td>{item.Description}</td>
        <td style='text-align:center'>{item.Quantity}</td>
        <td style='text-align:right'>{item.UnitPrice:C}</td>
        <td style='text-align:center'>{item.DiscountPct}%</td>
        <td style='text-align:right'>{item.LineTotal:C}</td>
    </tr>"))

Dim html As String = $"
    <h1>Quote — {opportunity.ProspectCompany}</h1>
    <p>Prepared for: {opportunity.ContactName} &lt;{opportunity.ContactEmail}&gt;</p>
    <p>Valid until: {opportunity.QuoteExpiry:MMMM d, yyyy} &nbsp;|&nbsp; Terms: {opportunity.PaymentTerms}</p>
    <table border='1' cellpadding='6' width='100%'>
        <thead><tr><th>Description</th><th>Qty</th><th>Unit Price</th><th>Discount</th><th>Total</th></tr></thead>
        <tbody>{lineItemRows}</tbody>
    </table>
    <p style='text-align:right'><strong>Subtotal:</strong> {opportunity.Subtotal:C}</p>
    <p style='text-align:right'><strong>Tax ({opportunity.TaxRatePct}%):</strong> {opportunity.TaxAmount:C}</p>
    <p style='text-align:right'><strong>Grand Total:</strong> {opportunity.GrandTotal:C}</p>
    <hr/><p style='font-size:11px'>{opportunity.TermsAndConditions}</p>"

Dim quote As PdfDocument = renderer.RenderHtmlAsPdf(html)
$vbLabelText   $csharpLabel

生成されたPDFドキュメント

IronPDF 例の出力

ヒント会社のロゴやフォントファイルをtemplateにbase64データURIとして埋め込むか、RenderHtmlAsPdf()の二番目のパラメーターとしてBaseUrlPathを設定してください。これにより、IronPDFはアプリケーションがどこに配置されても相対アセットパスを解決します。

4. 見積もりの配信と記録

using System.Net.Mail;
using System.IO;

// Save versioned copy to document storage
string outputPath = $"quotes/{opportunity.Id}/v{opportunity.QuoteVersion}.pdf";

quote.SaveAs(outputPath);

// Email to prospect
using var stream = new MemoryStream(quote.BinaryData);
using var attachment = new Attachment(stream,
    $"Quote-{opportunity.ProspectCompany}-v{opportunity.QuoteVersion}.pdf",
    "application/pdf");

var message = new MailMessage("sales@yourcompany.com", opportunity.ContactEmail)
{
    Subject = $"Your Quote from {opportunity.RepName} — {opportunity.ProspectCompany}",
    Body = $"Hi {opportunity.ContactName},\n\nPlease find your quote attached. It is valid until {opportunity.QuoteExpiry:MMMM d, yyyy}.\n\n{opportunity.RepName}"
};

message.Attachments.Add(attachment);

using var smtp = new SmtpClient("smtp.yourprovider.com");

await smtp.SendMailAsync(message);

// Log reference back to CRM
await _crmService.LogQuoteSentAsync(opportunity.Id, outputPath, DateTime.UtcNow);
using System.Net.Mail;
using System.IO;

// Save versioned copy to document storage
string outputPath = $"quotes/{opportunity.Id}/v{opportunity.QuoteVersion}.pdf";

quote.SaveAs(outputPath);

// Email to prospect
using var stream = new MemoryStream(quote.BinaryData);
using var attachment = new Attachment(stream,
    $"Quote-{opportunity.ProspectCompany}-v{opportunity.QuoteVersion}.pdf",
    "application/pdf");

var message = new MailMessage("sales@yourcompany.com", opportunity.ContactEmail)
{
    Subject = $"Your Quote from {opportunity.RepName} — {opportunity.ProspectCompany}",
    Body = $"Hi {opportunity.ContactName},\n\nPlease find your quote attached. It is valid until {opportunity.QuoteExpiry:MMMM d, yyyy}.\n\n{opportunity.RepName}"
};

message.Attachments.Add(attachment);

using var smtp = new SmtpClient("smtp.yourprovider.com");

await smtp.SendMailAsync(message);

// Log reference back to CRM
await _crmService.LogQuoteSentAsync(opportunity.Id, outputPath, DateTime.UtcNow);
Imports System.Net.Mail
Imports System.IO

' Save versioned copy to document storage
Dim outputPath As String = $"quotes/{opportunity.Id}/v{opportunity.QuoteVersion}.pdf"

quote.SaveAs(outputPath)

' Email to prospect
Using stream As New MemoryStream(quote.BinaryData)
    Using attachment As New Attachment(stream, $"Quote-{opportunity.ProspectCompany}-v{opportunity.QuoteVersion}.pdf", "application/pdf")
        Dim message As New MailMessage("sales@yourcompany.com", opportunity.ContactEmail) With {
            .Subject = $"Your Quote from {opportunity.RepName} — {opportunity.ProspectCompany}",
            .Body = $"Hi {opportunity.ContactName}," & vbCrLf & vbCrLf & $"Please find your quote attached. It is valid until {opportunity.QuoteExpiry:MMMM d, yyyy}." & vbCrLf & vbCrLf & $"{opportunity.RepName}"
        }

        message.Attachments.Add(attachment)

        Using smtp As New SmtpClient("smtp.yourprovider.com")
            Await smtp.SendMailAsync(message)
        End Using
    End Using
End Using

' Log reference back to CRM
Await _crmService.LogQuoteSentAsync(opportunity.Id, outputPath, DateTime.UtcNow)
$vbLabelText   $csharpLabel

PDFを添付した送信メールの例

添付されたPDF見積もりのある電子メール ファイルパスとファイル名の両方にバージョン番号が含まれることで、すべてのリビジョンに固有の永続的な記録が提供されます。 見込み客が変更を要求すると、営業担当者はCRMで機会を更新し、アプリケーションはバージョンを増加させて再生成し、新しい見積もりが送信され、完全な履歴がドキュメントストレージに保持され、CRMレコードに記録されます。

実世界の利点

見込み客への迅速な対応。 営業担当者が開始してから数秒で見積もりが生成され、メールで送信されます。 フォーマット遅延はなく、ドラフトフォルダに置かれるドキュメントもなく、担当者の見積もり決定と見込み客がそれを受け取る間の遅延もありません。

価格の正確性。 明細項目、割引階層、および合計金額はCRM機会から直接取得されます。 手動の転記ステップはなく、担当者が前四半期の価格設定や間違った割引スケジュールを適用するリスクもありません。

ブランドの一貫性。 会社が送信するすべての見積書は、生成した担当者やパイプラインの段階に関係なく、同じロゴ、レイアウト、条件の言語、フッターを持っています。 個々のノートパソコン上に不正なWordテンプレートは存在していません。

バージョン追跡。 各生成された見積もりは、その機会ID、バージョン番号、および送信された日時と共に保存されます。 CRMログにより、営業マネージャーは、誰にいつ何を見積もったかを、メールスレッドを探さずに完全に把握できます。

テンプレートの再利用。 法務チームが契約条件の文言を更新したり、ブランドチームがロゴを刷新したりする際に、HTMLファイルを1つ変更することで、以降のすべての見積もりにそれが反映されます。 セールスチームへのWordテンプレートの再配布はありません。

ドキュメントごとのコストはありません。 レンダリングは .NET アプリケーション内でインプロセスで実行されます。 CPQのサブスクリプションはありませんし、文書生成APIに対するメータリングもなく、取引量に応じてスケールするコストモデルもありません。

結び

CRMの機会データと見込み客のインボックスに送られるプロフェッショナルなPDFの間のギャップは、見た目よりも小さく、テンプレート、レンダリングコール、メール送信が、セールスワークフローの単一のアクションによってすべてトリガーされます。 手動のフォーマット設定を削除することで、単に時間を節約するだけでなく、取引に悪影響を及ぼしかねないエラーのカテゴリを排除することができます。

そのパイプラインは、既存 for .NETアプリケーション内で簡単に構築および維持できます。 IronPDFは、C#でのPDF生成のライフサイクル全体を、ironpdf.comで処理し、HTMLテンプレートのレンダリングからドキュメントの保存、ストリーミング、操作までを行います。 無料の30日間トライアルを利用することで、ご自身のCRMデータと営業ワークフローに対して完全な見積もり生成パイプラインを構築し、テストするのに十分な時間があります。

Curtis Chau
テクニカルライター

Curtis Chauは、カールトン大学でコンピュータサイエンスの学士号を取得し、Node.js、TypeScript、JavaScript、およびReactに精通したフロントエンド開発を専門としています。直感的で美しいユーザーインターフェースを作成することに情熱を持ち、Curtisは現代のフレームワークを用いた開発や、構造の良い視覚的に魅力的なマニュアルの作成を楽しんでいます。

開発以外にも、CurtisはIoT(Internet of Things)への強い関心を持ち、ハードウェアとソフトウェアの統合方法を模索しています。余暇には、ゲームをしたりDiscordボットを作成したりして、技術に対する愛情と創造性を組み合わせています。

アイアンサポートチーム

私たちは週5日、24時間オンラインで対応しています。
チャット
メール
電話してね