{
  "name": "見積の依頼メールから freee の見積書を下書き（AI は値段を決めない）",
  "nodes": [
    {
      "id": "c7000000-0000-4000-8000-000000000001",
      "name": "見積の依頼メール",
      "type": "n8n-nodes-base.gmailTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "simple": false,
        "filters": {
          "q": "subject:(見積 OR 見積もり OR お見積り) -subject:\"[n8n 見積]\""
        },
        "options": {}
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000002",
      "name": "メールを読む",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "jsCode": "// Sender, subject and the plain text of the mail.\nconst m = $json;\nconst from = (m.from && m.from.value && m.from.value[0]) || {};\nconst text = String(m.text || m.textAsHtml || m.snippet || '').replace(/\\r/g, '').trim();\nreturn [{ json: { source: 'gmail', from_email: String(from.address || '').toLowerCase(), from_name: from.name || '', subject: m.subject || '', text } }];"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000003",
      "name": "依頼を貼るフォーム",
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.6,
      "position": [
        0,
        300
      ],
      "parameters": {
        "formTitle": "依頼から freee の見積書を作る",
        "formDescription": "見積の依頼（メールの本文など）を貼ってください。freee に見積書が「送付待ち」で作られます。freee から送るまで、お客様には何も届きません。",
        "formFields": {
          "values": [
            {
              "fieldLabel": "お客様のメールアドレス",
              "fieldName": "Email",
              "fieldType": "email",
              "requiredField": false,
              "placeholder": "buyer@example.com"
            },
            {
              "fieldLabel": "依頼の内容",
              "fieldName": "Request",
              "fieldType": "textarea",
              "requiredField": true,
              "placeholder": "パンフレット（A4）を500部と、当日のスタッフ2名のお見積りをお願いします。\n\n株式会社サンプル商事 佐藤"
            }
          ]
        },
        "responseMode": "lastNode",
        "options": {
          "path": "request-to-freee-quote"
        }
      },
      "webhookId": "3c8e1f52-7a4d-4b96-8e21-5d0f9b7c6a13"
    },
    {
      "id": "c7000000-0000-4000-8000-000000000004",
      "name": "フォームを読む",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        300
      ],
      "parameters": {
        "jsCode": "return [{ json: { source: 'form', from_email: String($json.Email || '').trim().toLowerCase(), from_name: '', subject: 'フォームからの依頼', text: String($json.Request || '').replace(/\\r/g, '').trim() } }];"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000005",
      "name": "設定",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        440,
        150
      ],
      "parameters": {
        "mode": "manual",
        "includeOtherFields": true,
        "assignments": {
          "assignments": [
            {
              "id": "c01",
              "name": "freee_company_id",
              "value": "PASTE_YOUR_FREEE_COMPANY_ID",
              "type": "string"
            },
            {
              "id": "c02",
              "name": "price_sheet_id",
              "value": "PASTE_YOUR_SPREADSHEET_ID",
              "type": "string"
            },
            {
              "id": "c03",
              "name": "price_sheet_tab",
              "value": "価格表",
              "type": "string"
            },
            {
              "id": "c04",
              "name": "staff_email",
              "value": "staff@example.com",
              "type": "string"
            },
            {
              "id": "c05",
              "name": "default_partner_title",
              "value": "御中",
              "type": "string"
            },
            {
              "id": "c06",
              "name": "tax_entry_method",
              "value": "out",
              "type": "string"
            },
            {
              "id": "c07",
              "name": "tax_fraction",
              "value": "omit",
              "type": "string"
            },
            {
              "id": "c08",
              "name": "expiration_days",
              "value": 30,
              "type": "number"
            },
            {
              "id": "c09",
              "name": "timezone",
              "value": "Asia/Tokyo",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000006",
      "name": "価格表を読む",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        660,
        150
      ],
      "parameters": {
        "url": "=https://sheets.googleapis.com/v4/spreadsheets/{{ $json.price_sheet_id }}/values/{{ encodeURIComponent($json.price_sheet_tab) }}!A1:F500",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSheetsOAuth2Api",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000007",
      "name": "freee の取引先を読む",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        150
      ],
      "parameters": {
        "url": "=https://api.freee.co.jp/api/1/partners?company_id={{ $('設定').first().json.freee_company_id }}&limit=3000",
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000008",
      "name": "AI に渡す内容を作る",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        150
      ],
      "parameters": {
        "jsCode": "// The price list becomes a catalog for Claude (codes, names, other names, units; no prices).\nconst c = $('設定').first().json;\nconst sheet = $('価格表を読む').first().json;\nconst freee = $json;\nif (sheet.statusCode !== 200) return [{ json: { ok: false, problem: '価格表のシートを読めませんでした（HTTP ' + sheet.statusCode + '）。設定の price_sheet_id と price_sheet_tab を確かめてください。' } }];\nif (freee.statusCode !== 200) return [{ json: { ok: false, problem: 'freee の取引先を読めませんでした（HTTP ' + freee.statusCode + '）。freee の認証情報、アプリの権限、freee_company_id を確かめてください。' } }];\nconst rows = (sheet.body.values || []);\nconst head = (rows[0] || []).map((h) => String(h).trim().toLowerCase());\nconst col = (k) => head.indexOf(k);\nfor (const k of ['code', 'name', 'unit', 'unit_price', 'tax_rate']) if (col(k) < 0) return [{ json: { ok: false, problem: '価格表の1行目に code, name, aliases, unit, unit_price, tax_rate が要ります（ないもの：' + k + '）。' } }];\nconst catalog = rows.slice(1).filter((r) => r[col('code')]).map((r) => ({\n  code: String(r[col('code')]).trim(), name: String(r[col('name')] || '').trim(),\n  aliases: col('aliases') >= 0 ? String(r[col('aliases')] || '').trim() : '',\n  unit: String(r[col('unit')] || '').trim(), unit_price: String(r[col('unit_price')] ?? '').replace(/[,\\s]/g, ''),\n  tax_rate: Number(String(r[col('tax_rate')] ?? '').replace('%', '')),\n}));\nif (!catalog.length) return [{ json: { ok: false, problem: '価格表が空です。' } }];\nif (!c.text) return [{ json: { ok: false, problem: '依頼の内容が空です。' } }];\nconst list = catalog.map((x) => x.code + ' | ' + x.name + (x.aliases ? ' | 別名: ' + x.aliases : '') + ' | unit: ' + x.unit).join('\\n');\nreturn [{ json: { ok: true, catalog, partners: freee.body.partners || [], list, text: c.text.slice(0, 8000) } }];"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000009",
      "name": "準備できた？",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1320,
        150
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "ok",
              "leftValue": "={{ $json.ok }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000010",
      "name": "Claude Haiku 4.5",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.5,
      "position": [
        1540,
        370
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-haiku-4-5-20251001",
          "cachedResultName": "Claude Haiku 4.5"
        },
        "options": {}
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000011",
      "name": "品目と数量を読む（AI）",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.9,
      "position": [
        1540,
        150
      ],
      "parameters": {
        "promptType": "define",
        "text": "={{ 'Catalog (code | name | other names | unit):\\n' + $json.list + '\\n\\nRequest:\\n' + $json.text }}",
        "messages": {
          "messageValues": [
            {
              "type": "SystemMessagePromptTemplate",
              "message": "You read a customer's request for a quotation and list what they ask for. You never set or mention prices.\nFor each requested item:\n- \"code\": the catalog code only if the request clearly means that catalog item; otherwise null. Do not pick the nearest item when it is a different thing.\n- \"requested\": the item as the customer wrote it.\n- \"quantity\": the number the customer wrote for it, or null if no number is written. Do not guess. \"一式\" or \"a set\" counts as 1.\n- \"unit\": the unit as written (部, 枚, sets, people...), or null.\n- \"quote\": the exact words from the request, copied character by character, that contain the item and its quantity.\nAlso return \"customer_company\": the customer's company name as written in the request (often in the signature), or null; and \"subject\": a short title for the quotation in the language of the request (topic only, no prices).\nReturn only JSON: {\"customer_company\": \"...\", \"subject\": \"...\", \"items\": [{\"code\": \"...\", \"requested\": \"...\", \"quantity\": 1, \"unit\": \"...\", \"quote\": \"...\"}]}"
            }
          ]
        }
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000012",
      "name": "確かめて値段を入れる",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1760,
        150
      ],
      "parameters": {
        "jsCode": "// Code decides what goes into the quotation. Prices come only from the price list.\nconst p = $('AI に渡す内容を作る').first().json;\nconst c = $('設定').first().json;\nconst norm = (s) => String(s ?? '').normalize('NFKC').toLowerCase().replace(/[\\s,、。「」\"'“”]/g, '');\nconst numIn = (text, q) => {\n  const t = String(text).normalize('NFKC').replace(/,/g, '');\n  return new RegExp('(^|[^\\\\d.])' + String(q).replace('.', '\\\\.') + '([^\\\\d.]|$)').test(t);\n};\nlet a;\ntry { a = JSON.parse(String($json.text ?? '').match(/\\{[\\s\\S]*\\}/)[0]); }\ncatch (e) { return [{ json: { ok: false, problem: 'AI の答えを JSON として読めませんでした。もう一度試してください。' } }]; }\nconst byCode = new Map(p.catalog.map((x) => [x.code, x]));\nconst text = norm(p.text);\nconst priced = [], check = [], dropped = [];\nfor (const it of Array.isArray(a.items) ? a.items : []) {\n  const label = it.requested || it.code || '（品目）';\n  const q = norm(it.quote);\n  if (q.length < 2 || !text.includes(q)) { dropped.push('「' + label + '」：引用した言葉が依頼文にない'); continue; }\n  const qty = it.quantity === null || it.quantity === undefined || it.quantity === '' ? null : Number(it.quantity);\n  const qtyOk = qty !== null && Number.isFinite(qty) && qty > 0 && (numIn(it.quote, qty) || (qty === 1 && /一式|1式|a set|one set/i.test(String(it.quote).normalize('NFKC'))));\n  const item = it.code ? byCode.get(String(it.code)) : null;\n  const unitOk = !item || !it.unit || norm(it.unit) === norm(item.unit) || norm(item.aliases).includes(norm(it.unit));\n  if (item && qtyOk && unitOk && /^\\d+(\\.\\d{1,3})?$/.test(item.unit_price) && [0, 8, 10].includes(item.tax_rate)) {\n    priced.push({ code: item.code, name: item.name, quantity: qty, unit: item.unit, unit_price: item.unit_price, tax_rate: item.tax_rate, quote: it.quote });\n  } else {\n    const why = !item ? (it.code ? 'コード ' + it.code + ' は価格表にない' : '価格表にない') : !qtyOk ? (qty === null || !Number.isFinite(qty) ? '数量が書かれていない' : '数量 ' + qty + ' は依頼文に書かれていない（AI が計算したかもしれない）') : !unitOk ? '単位「' + it.unit + '」が価格表（' + item.unit + '）と違う' : '価格表の行が使えない';\n    check.push({ requested: label, quantity: qty, unit: it.unit || '', why, quote: it.quote });\n  }\n}\n// The customer: the sender's e-mail first, then the company name written in the request (must match exactly one partner)\nconst from = String($('設定').first().json.from_email || '').toLowerCase();\nconst partners = p.partners.filter((x) => x.available !== false);\nlet partner = from ? partners.find((x) => String(x.email || '').toLowerCase() === from) : null;\nlet partnerBy = partner ? 'メールアドレス ' + from : '';\nif (!partner && a.customer_company) {\n  const want = norm(a.customer_company);\n  const hits = partners.filter((x) => [x.name, x.long_name].some((v) => v && norm(v) === want));\n  if (hits.length === 1 && text.includes(want)) { partner = hits[0]; partnerBy = '会社名「' + a.customer_company + '」'; }\n}\nconst base = { priced, check, dropped, customer_company: a.customer_company || null };\nif (!partner) return [{ json: { ok: false, ...base, problem: 'お客様が freee の取引先に見つかりませんでした' + (a.customer_company ? '（依頼文の会社名：「' + a.customer_company + '」）' : '') + (from ? '（メールアドレス：' + from + '）' : '') + '。freee に取引先（このメールアドレス）を足してから、もう一度動かしてください。見積書は作っていません。' } }];\nif (!priced.length) return [{ json: { ok: false, ...base, problem: '価格表で値段の付けられる品目がなかったので、見積書は作っていません。' } }];\n// Our own total, to compare with what freee calculates (tax rounded down per rate, as tax_fraction \"omit\")\nconst sub = {}; let net = 0;\nfor (const x of priced) { const v = Math.round(x.quantity * Number(x.unit_price)); net += v; sub[x.tax_rate] = (sub[x.tax_rate] || 0) + v; }\nconst tax = Object.entries(sub).reduce((s, [r, v]) => s + Math.floor(v * Number(r) / 100), 0);\nconst today = DateTime.now().setZone(c.timezone);\nconst lines = priced.map((x) => ({ type: 'item', description: x.name, quantity: x.quantity, unit: x.unit, unit_price: x.unit_price, tax_rate: x.tax_rate }))\n  .concat(check.map((x) => ({ type: 'text', description: ('※要確認：' + x.requested + (x.quantity !== null ? ' ' + x.quantity + (x.unit || '') : '') + ' (' + x.why + ')').slice(0, 255) })));\nconst body = {\n  company_id: Number(c.freee_company_id), quotation_date: today.toFormat('yyyy-MM-dd'), expiration_date: today.plus({ days: Number(c.expiration_days) }).toFormat('yyyy-MM-dd'),\n  subject: String(a.subject || 'お見積り').slice(0, 100), tax_entry_method: c.tax_entry_method, tax_fraction: c.tax_fraction, withholding_tax_entry_method: 'out',\n  partner_id: partner.id, partner_title: partner.default_title && ['御中', '様', '(空白)'].includes(partner.default_title) ? partner.default_title : c.default_partner_title,\n  memo: ('n8n が作成（依頼：' + (c.from_email || c.source) + ' / ' + c.subject + '）').slice(0, 2000), lines,\n};\nreturn [{ json: { ok: true, ...base, partner: { id: partner.id, name: partner.name, by: partnerBy }, expected: { net, tax, total: net + tax }, body } }];"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000013",
      "name": "見積書を作れる？",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1980,
        150
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "ok",
              "leftValue": "={{ $json.ok }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000014",
      "name": "freee に見積書を作る",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2200,
        50
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.freee.co.jp/iv/quotations",
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000015",
      "name": "お知らせを書く",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2420,
        150
      ],
      "parameters": {
        "jsCode": "// One notice for every outcome: made (with the link), freee refused, or nothing made and why.\nconst c = $('設定').first().json;\nconst chk = $('確かめて値段を入れる').isExecuted ? $('確かめて値段を入れる').all(0)[0].json : null;\nconst yen = (v) => Number(v).toLocaleString('ja-JP') + '円';\nconst lines = [];\nlet title, ok = false;\nconst created = $('freee に見積書を作る').isExecuted ? $('freee に見積書を作る').all(0)[0].json : null;\nif (created && created.statusCode === 201) {\n  const q = created.body.quotation;\n  ok = true;\n  title = '[n8n 見積] freee に見積書の下書き：' + q.partner_name + ' ' + yen(q.total_amount);\n  lines.push('freee に見積書を「送付待ち」で作りました。中身を確かめて、freee から送ってください。', q.report_url || '', '');\n  lines.push(q.quotation_number + ' / ' + q.subject + ' / ' + q.partner_name + '（' + chk.partner.by + '）');\n  chk.priced.forEach((x) => lines.push('- ' + x.name + ' ' + x.quantity + x.unit + ' × ' + yen(x.unit_price) + '（依頼文：「' + x.quote + '」）'));\n  lines.push('税抜 ' + yen(q.amount_excluding_tax) + '、消費税 ' + yen(q.amount_tax) + '、合計 ' + yen(q.total_amount));\n  if (q.amount_excluding_tax !== chk.expected.net || q.amount_tax !== chk.expected.tax) lines.push('!! freee の計算した金額が、このワークフローの計算（税抜 ' + yen(chk.expected.net) + '、消費税 ' + yen(chk.expected.tax) + '）と違います。見積書を確かめてください。');\n} else {\n  title = '[n8n 見積] 見積書は作っていません';\n  if (created) lines.push('freee が見積書を受け付けませんでした（HTTP ' + created.statusCode + '）：' + JSON.stringify(created.body && (created.body.errors || created.body)).slice(0, 400));\n  else lines.push($json.problem || '原因の分からない問題です。');\n}\nif (chk && chk.check.length) { lines.push('', '要確認（見積書に、値段なしの「※要確認」の行で入れています）：'); chk.check.forEach((x) => lines.push('- ' + x.requested + (x.quantity !== null ? ' ' + x.quantity + (x.unit || '') : '') + '：' + x.why)); }\nif (chk && chk.dropped.length) { lines.push('', '入れなかったもの（依頼文に見つからなかった）：'); chk.dropped.forEach((d) => lines.push('- ' + d)); }\nlines.push('', '依頼元：' + (c.from_email || c.source) + '／' + c.subject);\nreturn [{ json: { ok, title, message: lines.join('\\n'), source: c.source, to: c.staff_email } }];"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000016",
      "name": "依頼元に返す",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.4,
      "position": [
        2640,
        150
      ],
      "parameters": {
        "mode": "expression",
        "numberOutputs": 2,
        "output": "={{ $json.source === 'form' ? 0 : 1 }}"
      }
    },
    {
      "id": "c7000000-0000-4000-8000-000000000017",
      "name": "結果を表示",
      "type": "n8n-nodes-base.form",
      "typeVersion": 2.5,
      "position": [
        2860,
        50
      ],
      "parameters": {
        "operation": "completion",
        "respondWith": "text",
        "completionTitle": "={{ $json.title }}",
        "completionMessage": "={{ $json.message }}"
      },
      "webhookId": "6a2d9e4c-1b7f-4c38-9e05-8f3b2a7d1c64"
    },
    {
      "id": "c7000000-0000-4000-8000-000000000018",
      "name": "担当者に知らせる",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        2860,
        250
      ],
      "parameters": {
        "resource": "message",
        "operation": "send",
        "sendTo": "={{ $json.to }}",
        "subject": "={{ $json.title }}",
        "emailType": "text",
        "message": "={{ $json.message }}",
        "options": {
          "appendAttribution": false
        }
      }
    },
    {
      "parameters": {
        "content": "## 見積の依頼メールから、freee の見積書を下書き\nお客様から「パンフレット500部と、当日のスタッフ2名のお見積りを」とメールが届くと、**freee請求書に見積書が「送付待ち」でできます。** 担当者は中身を確かめて、freee から送ります。\n\n**AI（Claude）は値段を決めません。** 依頼文から、品目・数量・単位と、そう読んだ言葉を返すだけです。**コード**が、言葉が依頼文にあるか、数量が書かれているか、単位が合うかを確かめ、単価と税率は**価格表のスプレッドシート**から入れます。価格表にない品目や、書かれていない数量（「2名×2日」を AI が4人日と計算したなど）は、値段なしの「※要確認」の行になります。\n\n### 準備\n1. freee Developers のアプリ：取引先（参照）と、[請求書] 全帳票種別（参照・更新）の権限。freee請求書を一度ブラウザで開いておく\n2. n8n の認証情報：freee は「OAuth2 API」（認可の URL https://accounts.secure.freee.co.jp/public_api/authorize 、トークンの URL .../public_api/token 、Authentication は Body）。Gmail、Google スプレッドシート、Anthropic も\n3. 価格表のシートの1行目：code, name, aliases, unit, unit_price, tax_rate\n4. **設定** と、**見積の依頼メール** の Gmail の検索を埋める。まずフォームで試す",
        "height": 1060,
        "width": 600,
        "color": 1
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -660,
        -300
      ],
      "id": "c7000000-0000-4000-9000-000000000018",
      "name": "Overview"
    },
    {
      "parameters": {
        "content": "## 1. 依頼が届く\nGmail（どのメールを依頼とみなすかは、トリガーの検索で決める）か、フォーム。",
        "height": 620,
        "width": 400,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -20,
        -120
      ],
      "id": "c7000000-0000-4000-9000-000000000019",
      "name": "Section 1"
    },
    {
      "parameters": {
        "content": "## 2. 価格表と取引先\nシートを、AI に渡す品目の一覧にする（コード・名前・別の呼び方・単位。値段は渡さない）。freee から取引先を読む。",
        "height": 620,
        "width": 840,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        420,
        -120
      ],
      "id": "c7000000-0000-4000-9000-000000000020",
      "name": "Section 2"
    },
    {
      "parameters": {
        "content": "## 3. AI が読み、コードが値段を入れる\nAI は品目ごとに、コード・数量・単位と、依頼文の言葉を返す。コードは、言葉が依頼文にあり、数量がその中に書かれ、単位が合うときだけ受け入れ、値段は必ずシートから入れる。お客様は、送り主のメールアドレス、次に依頼文の会社名（1件だけ一致）で探す。",
        "height": 620,
        "width": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1300,
        -120
      ],
      "id": "c7000000-0000-4000-9000-000000000021",
      "name": "Section 3"
    },
    {
      "parameters": {
        "content": "## 4. freee に見積書（送付待ち）\nfreee請求書に作る。お客様には何も届かない。",
        "height": 620,
        "width": 400,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1980,
        -120
      ],
      "id": "c7000000-0000-4000-9000-000000000022",
      "name": "Section 4"
    },
    {
      "parameters": {
        "content": "## 5. 担当者に知らせる\nメール（フォームのときは結果の画面）で、見積書へのリンク、各行とその元の言葉、要確認の品目、入れなかったものを知らせる。freee の合計が、このワークフローの計算と違えば警告する。",
        "height": 620,
        "width": 680,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2400,
        -120
      ],
      "id": "c7000000-0000-4000-9000-000000000023",
      "name": "Section 5"
    }
  ],
  "connections": {
    "見積の依頼メール": {
      "main": [
        [
          {
            "node": "メールを読む",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "依頼を貼るフォーム": {
      "main": [
        [
          {
            "node": "フォームを読む",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "メールを読む": {
      "main": [
        [
          {
            "node": "設定",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "フォームを読む": {
      "main": [
        [
          {
            "node": "設定",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "設定": {
      "main": [
        [
          {
            "node": "価格表を読む",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "価格表を読む": {
      "main": [
        [
          {
            "node": "freee の取引先を読む",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "freee の取引先を読む": {
      "main": [
        [
          {
            "node": "AI に渡す内容を作る",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI に渡す内容を作る": {
      "main": [
        [
          {
            "node": "準備できた？",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "準備できた？": {
      "main": [
        [
          {
            "node": "品目と数量を読む（AI）",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "お知らせを書く",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Haiku 4.5": {
      "ai_languageModel": [
        [
          {
            "node": "品目と数量を読む（AI）",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "品目と数量を読む（AI）": {
      "main": [
        [
          {
            "node": "確かめて値段を入れる",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "確かめて値段を入れる": {
      "main": [
        [
          {
            "node": "見積書を作れる？",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "見積書を作れる？": {
      "main": [
        [
          {
            "node": "freee に見積書を作る",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "お知らせを書く",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "freee に見積書を作る": {
      "main": [
        [
          {
            "node": "お知らせを書く",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "お知らせを書く": {
      "main": [
        [
          {
            "node": "依頼元に返す",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "依頼元に返す": {
      "main": [
        [
          {
            "node": "結果を表示",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "担当者に知らせる",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}