Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 33 additions & 37 deletions src/handlers/list-xero-profit-and-loss.handler.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
import { xeroClient } from "../clients/xero-client.js";
import { XeroClientResponse } from "../types/tool-response.js";
import { ListProfitAndLossParams } from "../types/list-profit-and-loss-params.js";
import { formatError } from "../helpers/format-error.js";
import { getClientHeaders } from "../helpers/get-client-headers.js";
import { ReportWithRow } from "xero-node";

// Define the valid timeframe options
type TimeframeType = "MONTH" | "QUARTER" | "YEAR" | undefined;

/**
* Internal function to fetch profit and loss data from Xero
*/
async function fetchProfitAndLoss(
fromDate?: string,
toDate?: string,
periods?: number,
timeframe?: TimeframeType,
standardLayout?: boolean,
paymentsOnly?: boolean,
params: ListProfitAndLossParams,
): Promise<ReportWithRow | null> {
await xeroClient.authenticate();

const {
fromDate,
toDate,
periods,
timeframe,
trackingCategoryID,
trackingOptionID,
trackingCategoryID2,
trackingOptionID2,
standardLayout,
paymentsOnly,
} = params;

const response = await xeroClient.accountingApi.getReportProfitAndLoss(
xeroClient.tenantId,
fromDate,
toDate,
periods,
timeframe,
undefined, // trackingCategoryID
undefined, // trackingOptionID
undefined, // trackingCategoryID2
undefined, // trackingOptionID2
trackingCategoryID,
trackingCategoryID2,
trackingOptionID,
trackingOptionID2,
standardLayout,
paymentsOnly,
getClientHeaders(),
Expand All @@ -40,33 +46,23 @@ async function fetchProfitAndLoss(

/**
* List profit and loss report from Xero
* @param fromDate Optional start date for the report (YYYY-MM-DD)
* @param toDate Optional end date for the report (YYYY-MM-DD)
* @param periods Optional number of periods for the report
* @param timeframe Optional timeframe for the report (MONTH, QUARTER, YEAR)
* @param trackingCategoryID Optional tracking category ID
* @param trackingOptionID Optional tracking option ID
* @param trackingCategoryID2 Optional second tracking category ID
* @param trackingOptionID2 Optional second tracking option ID
* @param standardLayout Optional boolean to use standard layout
* @param paymentsOnly Optional boolean to include only accounts with payments
* @param params Optional parameters for the report:
* - fromDate: Optional start date for the report (YYYY-MM-DD)
* - toDate: Optional end date for the report (YYYY-MM-DD)
* - periods: Optional number of periods for the report
* - timeframe: Optional timeframe for the report (MONTH, QUARTER, YEAR)
* - trackingCategoryID: Optional tracking category ID
* - trackingOptionID: Optional tracking option ID
* - trackingCategoryID2: Optional second tracking category ID
* - trackingOptionID2: Optional second tracking option ID
* - standardLayout: Optional boolean to use standard layout
* - paymentsOnly: Optional boolean to include only accounts with payments
*/
export async function listXeroProfitAndLoss(
fromDate?: string,
toDate?: string,
periods?: number,
timeframe?: TimeframeType,
standardLayout?: boolean,
paymentsOnly?: boolean,
params: ListProfitAndLossParams,
): Promise<XeroClientResponse<ReportWithRow>> {
try {
const profitAndLoss = await fetchProfitAndLoss(
fromDate,
toDate,
periods,
timeframe,
paymentsOnly,
);
const profitAndLoss = await fetchProfitAndLoss(params);

if (!profitAndLoss) {
return {
Expand All @@ -88,4 +84,4 @@ export async function listXeroProfitAndLoss(
error: formatError(error),
};
}
}
}
24 changes: 16 additions & 8 deletions src/tools/list/list-profit-and-loss.tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ const ListProfitAndLossTool = CreateXeroTool(
toDate: z.string().optional().describe("Optional end date in YYYY-MM-DD format"),
periods: z.number().optional().describe("Optional number of periods to compare"),
timeframe: z.enum(["MONTH", "QUARTER", "YEAR"]).optional().describe("Optional timeframe for the report (MONTH, QUARTER, YEAR)"),
trackingCategoryID: z.string().optional().describe("Optional tracking category ID to scope the report to a tracking dimension. Obtain IDs from the list-tracking-categories tool. Supply this alone for a per-option breakdown (one column per option in the category); supply it together with trackingOptionID to filter the whole P&L to that single option."),
trackingOptionID: z.string().optional().describe("Optional tracking option ID. Obtain IDs from the list-tracking-categories tool. Must be supplied together with trackingCategoryID; it filters the whole P&L to that single option of that category."),
trackingCategoryID2: z.string().optional().describe("Optional SECOND tracking category ID for a cross-tab against a different category. Obtain IDs from the list-tracking-categories tool. This targets a second category (cross-tab), NOT a second option of the same category."),
trackingOptionID2: z.string().optional().describe("Optional second tracking option ID. Obtain IDs from the list-tracking-categories tool. Must be supplied together with trackingCategoryID2; it filters to that single option of the second category."),
standardLayout: z.boolean().optional().describe("Optional flag to use standard layout"),
paymentsOnly: z.boolean().optional().describe("Optional flag to include only accounts with payments"),
},
async (args) => {
const response = await listXeroProfitAndLoss(
args?.fromDate,
args?.toDate,
args?.periods,
args?.timeframe,
args?.standardLayout,
args?.paymentsOnly,
);
const response = await listXeroProfitAndLoss({
fromDate: args?.fromDate,
toDate: args?.toDate,
periods: args?.periods,
timeframe: args?.timeframe,
trackingCategoryID: args?.trackingCategoryID,
trackingOptionID: args?.trackingOptionID,
trackingCategoryID2: args?.trackingCategoryID2,
trackingOptionID2: args?.trackingOptionID2,
standardLayout: args?.standardLayout,
paymentsOnly: args?.paymentsOnly,
});

if (response.error !== null) {
return {
Expand Down
15 changes: 15 additions & 0 deletions src/types/list-profit-and-loss-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { timeframeType } from "./timeframeType.js";

// Define an interface for the profit and loss parameters
export interface ListProfitAndLossParams {
fromDate?: string;
toDate?: string;
periods?: number;
timeframe?: timeframeType;
trackingCategoryID?: string;
trackingOptionID?: string;
trackingCategoryID2?: string;
trackingOptionID2?: string;
standardLayout?: boolean;
paymentsOnly?: boolean;
}