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
JavaScript
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 };