UNPKG

windsurfmcp-aws-mcp-server1

Version:

Claude Desktop用のAWS MCPサーバーパッケージです。WebSocketを通じてAWS上のLambda関数に接続し、ZohoのCRM/Desk/Books APIとの連携機能を提供します。

1,132 lines (989 loc) 44.9 kB
import { logger } from "../utils/logger.mjs"; import { zohoConfig } from "../config/zoho-config.mjs"; import { tokenManager } from "../utils/token-manager.mjs"; /** * Zoho Books APIクライアントクラス */ class ZohoBooksClient { constructor() { this.service = "books"; // 設定から組織IDを取得 this.organizationId = zohoConfig.getServiceConfig(this.service).organizationId; if (!this.organizationId) { logger.warn("Zoho Books組織IDが設定されていません"); } else { logger.info(`Zoho Books組織ID: ${this.organizationId}`); } } /** * 接続状態を確認 * @returns {Promise<boolean>} 接続状態 */ async checkConnection() { try { logger.info("Zoho Books接続状態を確認します"); // アクセストークンを取得(自動更新機能付き) const accessToken = await tokenManager.getAccessToken(this.service); if (!accessToken) { logger.warn("Zoho Booksの有効なアクセストークンがありません"); return false; } // 組織情報を取得して接続テスト const baseUrl = zohoConfig.getApiBaseUrl(this.service); const url = `${baseUrl}/organizations`; const response = await fetch(url, { headers: { "Authorization": `Zoho-oauthtoken ${accessToken}`, "Content-Type": "application/json" } }); const data = await response.json(); if (response.ok && data && data.organizations) { logger.info("Zoho Booksに正常に接続されています"); return true; } else { logger.warn("Zoho Booksから組織情報を取得できませんでした"); return false; } } catch (error) { logger.error("Zoho Books接続確認中にエラーが発生しました", error); return false; } } /** * APIリクエストを実行 * @param {string} endpoint - APIエンドポイント * @param {object} options - リクエストオプション * @returns {Promise<object>} レスポンスデータ */ async makeRequest(endpoint, options = {}) { try { // アクセストークンを取得(自動更新機能付き) const accessToken = await tokenManager.getValidAccessToken(this.service); if (!accessToken) { throw new Error("有効なアクセストークンがありません"); } // APIドメインを取得 const apiBaseUrl = zohoConfig.getApiBaseUrl(this.service); logger.info(`APIドメインを取得: ${apiBaseUrl}`); // 組織IDを取得 const organizationId = String(options.organizationId || this.organizationId); if (!organizationId) { throw new Error("組織IDが指定されていません"); } logger.info(`使用する組織ID: ${organizationId}`); // デフォルトのオプション const defaultOptions = { method: "GET", headers: { "Authorization": `Zoho-oauthtoken ${accessToken}`, "organization_id": organizationId, "Content-Type": "application/json" } }; // オプションをマージ const requestOptions = { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...(options.headers || {}) } }; // リクエストURLを構築 // ベースURLとエンドポイントの結合を正規化 const requestUrl = apiBaseUrl.replace(/\/$/, "") + "/" + endpoint.replace(/^\//, ""); logger.info(`${this.service}リクエスト: ${requestOptions.method} ${requestUrl}`); // リクエストを実行 logger.info(`${this.service}リクエストを実行します...`); const response = await fetch(requestUrl, requestOptions); logger.info(`${this.service}レスポンスステータス: ${response.status} ${response.statusText}`); // レスポンスの処理 let data; try { // レスポンスをクローンしてからJSONとして解析 const responseClone = response.clone(); // レスポンスのテキストを取得して確認 const textResponse = await responseClone.text(); logger.info(`レスポンステキスト(先頭100文字): ${textResponse.substring(0, 100)}...`); // HTMLレスポンスの場合はエラーとして処理 if (textResponse.trim().startsWith("<html>")) { logger.error("APIがHTMLレスポンスを返しました。APIエンドポイントが正しくない可能性があります。"); logger.error(`使用したURL: ${requestUrl}`); return { data: [] }; } // JSONとして解析 data = JSON.parse(textResponse); logger.info(`${this.service}レスポンスデータ: ${JSON.stringify(data).substring(0, 200)}...`); } catch (error) { logger.error(`JSONパースエラー: ${error.message}`); return { data: [] }; } // エラーチェック if (!response.ok) { const errorMessage = data.message || response.statusText; logger.error(`${this.service}APIエラー: ${errorMessage}`, data); return { data: [] }; } return data; } catch (error) { logger.error(`${this.service}リクエスト中にエラーが発生しました: ${error.message}`, error); return { data: [] }; } } /** * 請求書一覧を取得 * @param {object} params - クエリパラメータ * @returns {Promise<object>} 請求書一覧 */ async getInvoices(params = {}) { try { logger.info("請求書一覧を取得します"); // クエリパラメータを構築 const queryParams = new URLSearchParams(params).toString(); const endpoint = `invoices${queryParams ? `?${queryParams}` : ""}`; const response = await this.makeRequest(endpoint); return response; } catch (error) { logger.error("請求書一覧の取得に失敗しました", error); return { code: 0, message: "success", invoices: [] }; } } /** * 特定の請求書を取得 * @param {string} invoiceId - 請求書ID * @returns {Promise<object>} 請求書詳細 */ async getInvoice(invoiceId) { try { logger.info(`請求書(ID: ${invoiceId})を取得します`); const response = await this.makeRequest(`invoices/${invoiceId}`); return response; } catch (error) { logger.error(`請求書(ID: ${invoiceId})の取得に失敗しました: ${error.message}`); return { code: 0, message: "success", invoice: null }; } } /** * 請求書を作成 * @param {string} organizationId - 組織ID * @param {object} data - 請求書データ * @returns {Promise<object>} 作成された請求書 */ async createInvoice(organizationId, data) { try { logger.info("新しい請求書を作成します"); // リクエストデータのログ出力 logger.info(`請求書作成リクエストデータ: ${JSON.stringify(data, null, 2)}`); // 必須フィールドのバリデーション const requiredFields = ['customer_id', 'line_items', 'date']; const missingFields = requiredFields.filter(field => !data[field]); if (missingFields.length > 0) { const errorMessage = `必須フィールドが不足しています: ${missingFields.join(', ')}\n\n必須項目の説明:\n` + `- customer_id: 顧客ID\n` + `- line_items: 明細項目(配列)\n` + `- date: 請求書日付(YYYY-MM-DD形式)`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // line_itemsのバリデーション if (!Array.isArray(data.line_items) || data.line_items.length === 0) { const errorMessage = "line_itemsは少なくとも1つのアイテムを含む配列である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // 各line_itemの必須フィールドをチェック for (const [index, item] of data.line_items.entries()) { const requiredItemFields = ['item_id', 'rate', 'quantity', 'name']; const missingItemFields = requiredItemFields.filter(field => !item[field]); if (missingItemFields.length > 0) { const errorMessage = `line_items[${index}]に必須フィールドが不足しています: ${missingItemFields.join(', ')}\n\n必須項目の説明:\n` + `- item_id: 商品ID\n` + `- rate: 単価\n` + `- quantity: 数量\n` + `- name: 商品名`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } } // 日付フォーマットのバリデーション if (!/^\d{4}-\d{2}-\d{2}$/.test(data.date)) { const errorMessage = "dateはYYYY-MM-DD形式である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // APIリクエストを実行 const response = await this.makeRequest("invoices", { method: "POST", body: JSON.stringify(data), organizationId: organizationId }); // レスポンスのログ出力 logger.info(`請求書作成レスポンス: ${JSON.stringify(response, null, 2)}`); // エラーレスポンスのチェック if (response.code && response.code !== 0) { logger.error(`請求書作成エラー: ${response.message}`); return { code: response.code, message: response.message, data: [] }; } return response; } catch (error) { logger.error(`請求書の作成に失敗しました: ${error.message}`, error); return { code: 1, message: error.message, data: [] }; } } /** * 請求書を更新 * @param {string} invoiceId - 請求書ID * @param {object} data - 更新データ * @returns {Promise<object>} 更新された請求書 */ async updateInvoice(invoiceId, data) { try { logger.info(`請求書(ID: ${invoiceId})を更新します`); const response = await this.makeRequest(`invoices/${invoiceId}`, { method: "PUT", body: JSON.stringify(data) }); return response; } catch (error) { logger.error(`請求書(ID: ${invoiceId})の更新に失敗しました: ${error.message}`); return { code: 0, message: "success", invoice: null }; } } /** * 請求書を削除 * @param {string} invoiceId - 請求書ID * @returns {Promise<object>} 削除結果 */ async deleteInvoice(invoiceId) { try { logger.info(`請求書(ID: ${invoiceId})を削除します`); const response = await this.makeRequest(`invoices/${invoiceId}`, { method: "DELETE" }); return response; } catch (error) { logger.error(`請求書(ID: ${invoiceId})の削除に失敗しました: ${error.message}`); return { code: 0, message: "success", invoice: null }; } } /** * 取引先一覧を取得 * @param {object} params - クエリパラメータ * @returns {Promise<object>} 取引先一覧 */ async getContacts(params = {}) { try { logger.info("取引先一覧を取得します"); const queryParams = new URLSearchParams(params).toString(); const endpoint = `contacts${queryParams ? `?${queryParams}` : ""}`; const response = await this.makeRequest(endpoint); return response; } catch (error) { logger.error("取引先一覧の取得に失敗しました", error); return { code: 0, message: "success", contacts: [] }; } } /** * 商品・サービス一覧を取得 * @param {object} params - クエリパラメータ * @returns {Promise<object>} 商品・サービス一覧 */ async getItems(params = {}) { try { logger.info("商品・サービス一覧を取得します"); const queryParams = new URLSearchParams(params).toString(); const endpoint = `items${queryParams ? `?${queryParams}` : ""}`; const response = await this.makeRequest(endpoint); return response; } catch (error) { logger.error("商品・サービス一覧の取得に失敗しました", error); return { code: 0, message: "success", items: [] }; } } /** * 入金一覧を取得 * @param {object} params - クエリパラメータ * @returns {Promise<object>} 入金一覧 */ async getPayments(params = {}) { try { logger.info("入金一覧を取得します"); const queryParams = new URLSearchParams(params).toString(); const endpoint = `customerpayments${queryParams ? `?${queryParams}` : ""}`; const response = await this.makeRequest(endpoint); return response; } catch (error) { logger.error("入金一覧の取得に失敗しました", error); return { code: 0, message: "success", customerpayments: [] }; } } /** * 入金を記録 * @param {object} data - 入金データ * @returns {Promise<object>} 記録された入金 */ async recordPayment(data) { try { logger.info("新しい入金を記録します"); const response = await this.makeRequest("customerpayments", { method: "POST", body: JSON.stringify(data) }); return response; } catch (error) { logger.error(`入金の記録に失敗しました: ${error.message}`); return { code: 0, message: "success", customerpayment: null }; } } /** * モジュールからデータを取得 * @param {string} module - モジュール名(invoices, customers等) * @param {string} organizationId - 組織ID * @param {object} filters - 検索フィルター * @returns {Promise<object>} データ一覧 */ async getData(module, organizationId, filters = {}) { try { logger.info(`Zoho Books ${module}データを取得します`); // 組織IDを文字列に変換 const orgId = String(organizationId); logger.info(`使用する組織ID: ${orgId}`); // フィルター条件のログ出力 logger.info("フィルター条件:"); Object.keys(filters).forEach(key => { logger.info(` - ${key}: ${filters[key]}`); }); // エンドポイントを構築 let endpoint = ""; // モジュールに応じてエンドポイントを設定 if (module === "invoices") { endpoint = "/invoices"; } else if (module === "customers") { endpoint = "/contacts"; // Zoho Booksではcustomersはcontactsとして扱われる } else if (module === "items") { endpoint = "/items"; } else if (module === "bills") { endpoint = "/bills"; } else if (module === "expenses") { endpoint = "/expenses"; } else { endpoint = `/${module}`; } // クエリパラメータを追加 const queryParams = new URLSearchParams(); // デフォルトのパラメータを設定 queryParams.append("page", filters.page || "1"); queryParams.append("per_page", filters.per_page || "200"); // 日付フィルターの処理 if (filters.date_start) { queryParams.append("date_start", filters.date_start); } if (filters.date_end) { queryParams.append("date_end", filters.date_end); } // その他のフィルターをクエリパラメータに変換 Object.keys(filters).forEach(key => { if (!["page", "per_page", "date_start", "date_end"].includes(key)) { queryParams.append(key, filters[key]); } }); // エンドポイントにクエリパラメータを追加 endpoint += `?${queryParams.toString()}`; logger.debug("クエリパラメータ:"); logger.debug(`最終的なエンドポイント: ${endpoint}`); // リクエストを実行 const response = await this.makeRequest(endpoint, { organizationId: orgId }); return response; } catch (error) { logger.error(`${module}のデータ取得に失敗しました: ${error.message}`, error); return { data: [], page_context: { page: 1, per_page: 200, has_more_page: false, report_name: module } }; } } /** * 見積書を作成 * @param {string} organizationId - 組織ID * @param {object} data - 見積書データ * @returns {Promise<object>} 作成された見積書 */ async createEstimate(organizationId, data) { try { logger.info("新しい見積書を作成します"); // リクエストデータのログ出力 logger.info(`見積書作成リクエストデータ: ${JSON.stringify(data, null, 2)}`); // 必須フィールドのバリデーション const requiredFields = ['customer_id', 'line_items', 'date']; const missingFields = requiredFields.filter(field => !data[field]); if (missingFields.length > 0) { const errorMessage = `必須フィールドが不足しています: ${missingFields.join(', ')}\n\n必須項目の説明:\n` + `- customer_id: 顧客ID\n` + `- line_items: 明細項目(配列)\n` + `- date: 見積書日付(YYYY-MM-DD形式)`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // line_itemsのバリデーション if (!Array.isArray(data.line_items) || data.line_items.length === 0) { const errorMessage = "line_itemsは少なくとも1つのアイテムを含む配列である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // 各line_itemの必須フィールドをチェック for (const [index, item] of data.line_items.entries()) { const requiredItemFields = ['item_id', 'quantity', 'rate']; const missingItemFields = requiredItemFields.filter(field => !item[field]); if (missingItemFields.length > 0) { const errorMessage = `line_items[${index}]に必須フィールドが不足しています: ${missingItemFields.join(', ')}\n\n必須項目の説明:\n` + `- item_id: 商品ID\n` + `- quantity: 数量\n` + `- rate: 単価`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } } // 日付フォーマットのバリデーション if (!/^\d{4}-\d{2}-\d{2}$/.test(data.date)) { const errorMessage = "dateはYYYY-MM-DD形式である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // APIリクエストを実行 const response = await this.makeRequest("estimates", { method: "POST", body: JSON.stringify(data), organizationId: organizationId }); // レスポンスのログ出力 logger.info(`見積書作成レスポンス: ${JSON.stringify(response, null, 2)}`); // エラーレスポンスのチェック if (response.code && response.code !== 0) { logger.error(`見積書作成エラー: ${response.message}`); return { code: response.code, message: response.message, data: [] }; } return response; } catch (error) { logger.error(`見積書の作成に失敗しました: ${error.message}`, error); return { code: 1, message: error.message, data: [] }; } } /** * 受取請求書(Bill)を作成 * @param {string} organizationId - 組織ID * @param {object} data - 受取請求書データ * @returns {Promise<object>} 作成された受取請求書 */ async createBill(organizationId, data) { try { logger.info("新しい受取請求書を作成します"); // リクエストデータのログ出力 logger.info(`受取請求書作成リクエストデータ: ${JSON.stringify(data, null, 2)}`); // 必須フィールドのバリデーション const requiredFields = ['vendor_id', 'bill_number', 'date', 'line_items']; const missingFields = requiredFields.filter(field => !data[field]); if (missingFields.length > 0) { const errorMessage = `必須フィールドが不足しています: ${missingFields.join(', ')}\n\n必須項目の説明:\n` + `- vendor_id: 仕入先ID\n` + `- bill_number: 請求書番号\n` + `- date: 請求書日付(YYYY-MM-DD形式)\n` + `- line_items: 明細項目(配列)`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // line_itemsのバリデーション if (!Array.isArray(data.line_items) || data.line_items.length === 0) { const errorMessage = "line_itemsは少なくとも1つのアイテムを含む配列である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // 各line_itemの必須フィールドをチェック for (const [index, item] of data.line_items.entries()) { const requiredItemFields = ['item_id', 'quantity', 'rate']; const missingItemFields = requiredItemFields.filter(field => !item[field]); if (missingItemFields.length > 0) { const errorMessage = `line_items[${index}]に必須フィールドが不足しています: ${missingItemFields.join(', ')}\n\n必須項目の説明:\n` + `- item_id: 商品ID\n` + `- quantity: 数量\n` + `- rate: 単価`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } } // 日付フォーマットのバリデーション if (!/^\d{4}-\d{2}-\d{2}$/.test(data.date)) { const errorMessage = "dateはYYYY-MM-DD形式である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // APIリクエストを実行 const response = await this.makeRequest("bills", { method: "POST", body: JSON.stringify(data), organizationId: organizationId }); // レスポンスのログ出力 logger.info(`受取請求書作成レスポンス: ${JSON.stringify(response, null, 2)}`); // エラーレスポンスのチェック if (response.code && response.code !== 0) { logger.error(`受取請求書作成エラー: ${response.message}`); return { code: response.code, message: response.message, data: [] }; } return response; } catch (error) { logger.error(`受取請求書の作成に失敗しました: ${error.message}`, error); return { code: 1, message: error.message, data: [] }; } } /** * 請求書に対する支払いを作成 * @param {string} organizationId - 組織ID * @param {object} data - 支払いデータ * @returns {Promise<object>} 作成された支払い */ async createCustomerPayment(organizationId, data) { try { logger.info("新しい請求書支払いを作成します"); // リクエストデータのログ出力 logger.info(`請求書支払い作成リクエストデータ: ${JSON.stringify(data, null, 2)}`); // 必須フィールドのバリデーション const requiredFields = ['customer_id', 'payment_mode', 'amount', 'date', 'invoices']; const missingFields = requiredFields.filter(field => !data[field]); if (missingFields.length > 0) { const errorMessage = `必須フィールドが不足しています: ${missingFields.join(', ')}\n\n必須項目の説明:\n` + `- customer_id: 顧客ID\n` + `- payment_mode: 支払い方法(check, cash, creditcard, banktransfer, bankremittance, autotransaction, others)\n` + `- amount: 支払い金額\n` + `- date: 支払い日付(YYYY-MM-DD形式)\n` + `- invoices: 支払い対象の請求書リスト(配列)`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // invoicesのバリデーション if (!Array.isArray(data.invoices) || data.invoices.length === 0) { const errorMessage = "invoicesは少なくとも1つの請求書を含む配列である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // 各invoiceの必須フィールドをチェック for (const [index, invoice] of data.invoices.entries()) { const requiredInvoiceFields = ['invoice_id', 'amount_applied']; const missingInvoiceFields = requiredInvoiceFields.filter(field => !invoice[field]); if (missingInvoiceFields.length > 0) { const errorMessage = `invoices[${index}]に必須フィールドが不足しています: ${missingInvoiceFields.join(', ')}\n\n必須項目の説明:\n` + `- invoice_id: 請求書ID\n` + `- amount_applied: 支払い金額`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } } // 日付フォーマットのバリデーション if (!/^\d{4}-\d{2}-\d{2}$/.test(data.date)) { const errorMessage = "dateはYYYY-MM-DD形式である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // APIリクエストを実行 const response = await this.makeRequest("customerpayments", { method: "POST", body: JSON.stringify(data), organizationId: organizationId }); // レスポンスのログ出力 logger.info(`請求書支払い作成レスポンス: ${JSON.stringify(response, null, 2)}`); // エラーレスポンスのチェック if (response.code && response.code !== 0) { logger.error(`請求書支払い作成エラー: ${response.message}`); return { code: response.code, message: response.message, data: [] }; } return response; } catch (error) { logger.error(`請求書支払いの作成に失敗しました: ${error.message}`, error); return { code: 1, message: error.message, data: [] }; } } /** * 受取請求書に対する支払いを作成 * @param {string} organizationId - 組織ID * @param {object} data - 支払いデータ * @returns {Promise<object>} 作成された支払い */ async createVendorPayment(organizationId, data) { try { logger.info("新しい受取請求書支払いを作成します"); // リクエストデータのログ出力 logger.info(`受取請求書支払い作成リクエストデータ: ${JSON.stringify(data, null, 2)}`); // 必須フィールドのバリデーション const requiredFields = ['vendor_id', 'amount', 'paid_through_account_id', 'payment_mode', 'bills']; const missingFields = requiredFields.filter(field => !data[field]); if (missingFields.length > 0) { const errorMessage = `必須フィールドが不足しています: ${missingFields.join(', ')}\n\n必須項目の説明:\n` + `- vendor_id: 仕入先ID\n` + `- amount: 支払い金額\n` + `- paid_through_account_id: 支払い元の口座ID\n` + `- payment_mode: 支払い方法\n` + `- bills: 支払い対象の受取請求書リスト(配列)`; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // billsのバリデーション if (!Array.isArray(data.bills) || data.bills.length === 0) { const errorMessage = "billsは少なくとも1つの受取請求書を含む配列である必要があります"; logger.error(errorMessage); return { code: 1, message: errorMessage, data: [] }; } // APIリクエストを実行 const response = await this.makeRequest("vendorpayments", { method: "POST", body: JSON.stringify(data), organizationId: organizationId }); // レスポンスのログ出力 logger.info(`受取請求書支払い作成レスポンス: ${JSON.stringify(response, null, 2)}`); // エラーレスポンスのチェック if (response.code && response.code !== 0) { logger.error(`受取請求書支払い作成エラー: ${response.message}`); return { code: response.code, message: response.message, data: [] }; } return response; } catch (error) { logger.error(`受取請求書支払いの作成に失敗しました: ${error.message}`, error); return { code: 1, message: error.message, data: [] }; } } /** * 銀行口座情報を取得 * @param {string} organizationId - 組織ID * @param {object} filters - 検索フィルター * @returns {Promise<object>} 銀行口座情報 */ async getBankAccounts(organizationId, filters = {}) { try { logger.info("銀行口座情報を取得します"); // 組織IDを文字列に変換 const orgId = String(organizationId); logger.info(`使用する組織ID: ${orgId}`); // フィルター条件のログ出力 logger.info("フィルター条件:"); Object.keys(filters).forEach(key => { logger.info(` - ${key}: ${filters[key]}`); }); // エンドポイントを構築 let endpoint = "/bankaccounts"; // クエリパラメータを追加 const queryParams = new URLSearchParams(); // デフォルトのパラメータを設定 queryParams.append("page", filters.page || "1"); queryParams.append("per_page", filters.per_page || "200"); // 日付フィルターの処理 if (filters.date_start) { queryParams.append("date_start", filters.date_start); } if (filters.date_end) { queryParams.append("date_end", filters.date_end); } // その他のフィルターをクエリパラメータに変換 Object.keys(filters).forEach(key => { if (!["page", "per_page", "date_start", "date_end"].includes(key)) { queryParams.append(key, filters[key]); } }); // エンドポイントにクエリパラメータを追加 endpoint += `?${queryParams.toString()}`; // リクエストを実行 const response = await this.makeRequest(endpoint, { organizationId: orgId }); return response; } catch (error) { logger.error(`銀行口座情報の取得に失敗しました: ${error.message}`, error); return { data: [], page_context: { page: 1, per_page: 200, has_more_page: false, report_name: "bankaccounts" } }; } } /** * 勘定科目情報を取得 * @param {string} organizationId - 組織ID * @param {object} filters - 検索フィルター * @returns {Promise<object>} 勘定科目情報 */ async getChartOfAccounts(organizationId, filters = {}) { try { logger.info("勘定科目情報を取得します"); // 組織IDを文字列に変換 const orgId = String(organizationId); logger.info(`使用する組織ID: ${orgId}`); // フィルター条件のログ出力 logger.info("フィルター条件:"); Object.keys(filters).forEach(key => { logger.info(` - ${key}: ${filters[key]}`); }); // エンドポイントを構築 let endpoint = "/chartofaccounts"; // クエリパラメータを追加 const queryParams = new URLSearchParams(); // デフォルトのパラメータを設定 queryParams.append("page", filters.page || "1"); queryParams.append("per_page", filters.per_page || "200"); // 日付フィルターの処理 if (filters.date_start) { queryParams.append("date_start", filters.date_start); } if (filters.date_end) { queryParams.append("date_end", filters.date_end); } // その他のフィルターをクエリパラメータに変換 Object.keys(filters).forEach(key => { if (!["page", "per_page", "date_start", "date_end"].includes(key)) { queryParams.append(key, filters[key]); } }); // エンドポイントにクエリパラメータを追加 endpoint += `?${queryParams.toString()}`; // リクエストを実行 const response = await this.makeRequest(endpoint, { organizationId: orgId }); return response; } catch (error) { logger.error(`勘定科目情報の取得に失敗しました: ${error.message}`, error); return { data: [], page_context: { page: 1, per_page: 200, has_more_page: false, report_name: "chartofaccounts" } }; } } /** * 為替調整情報を取得 * @param {string} organizationId - 組織ID * @param {object} filters - 検索フィルター * @returns {Promise<object>} 為替調整情報 */ async getBaseCurrencyAdjustments(organizationId, filters = {}) { try { logger.info("為替調整情報を取得します"); // 組織IDを文字列に変換 const orgId = String(organizationId); logger.info(`使用する組織ID: ${orgId}`); // フィルター条件のログ出力 logger.info("フィルター条件:"); Object.keys(filters).forEach(key => { logger.info(` - ${key}: ${filters[key]}`); }); // エンドポイントを構築 let endpoint = "/organizations/${orgId}/settings/currencies/adjustments"; // クエリパラメータを追加 const queryParams = new URLSearchParams(); // デフォルトのパラメータを設定 queryParams.append("page", filters.page || "1"); queryParams.append("per_page", filters.per_page || "200"); // 日付フィルターの処理 if (filters.date_start) { queryParams.append("date_start", filters.date_start); } if (filters.date_end) { queryParams.append("date_end", filters.date_end); } // その他のフィルターをクエリパラメータに変換 Object.keys(filters).forEach(key => { if (!["page", "per_page", "date_start", "date_end"].includes(key)) { queryParams.append(key, filters[key]); } }); // エンドポイントにクエリパラメータを追加 endpoint += `?${queryParams.toString()}`; // リクエストを実行 const response = await this.makeRequest(endpoint, { organizationId: orgId }); return response; } catch (error) { logger.error(`為替調整情報の取得に失敗しました: ${error.message}`, error); return { data: [], page_context: { page: 1, per_page: 200, has_more_page: false, report_name: "basecurrencyadjustments" } }; } } } // シングルトンインスタンスをエクスポート const zohoBooksClient = new ZohoBooksClient(); export { zohoBooksClient }; export default { zohoBooksClient };