@get-asset/sdk
ProfitLossReport
Headless compound that fetches a profit and loss report for a single fiscal year and breaks it down by the chosen breakdown. The API returns one bucket per period; the compound zips those buckets into a single tree where each line carries an amounts array (one entry per period column). Iterate Periods for column headers and again inside each Line for per-period amounts. Breakdown is user-controlled state, exposed via useProfitLossReport().setBreakdown: year → 1 column, quarter → 4 columns (Q1-Q4), month → 12 columns (Jan-Dec). When the business has tags, the compound also fetches its tag fields and exposes a tag filter: selected tags narrow the report to amounts allocated to those tags (multiple tags are OR'd).
Anatomy
Import the primitive and compose the parts you need.
<ProfitLossReport.Root defaultBreakdown="year"><ProfitLossReport.Success><ProfitLossReport.Periods><ProfitLossReport.PeriodLabel /></ProfitLossReport.Periods><ProfitLossReport.Sections hide={["Gross Profit", "Total Operating Profit"]}><ProfitLossReport.Lines><ProfitLossReport.Line><ProfitLossReport.LineName /><ProfitLossReport.Periods><ProfitLossReport.LineAmount /></ProfitLossReport.Periods></ProfitLossReport.Line></ProfitLossReport.Lines></ProfitLossReport.Sections></ProfitLossReport.Success><ProfitLossReport.Loading>…</ProfitLossReport.Loading><ProfitLossReport.Empty>No data yet.</ProfitLossReport.Empty></ProfitLossReport.Root>
Required scopes
The access token used by AssetProvider must include these scopes for this primitive to fetch data successfully:
report:readtag:read
API reference
Root props
| Prop | Type | Default | Description |
|---|---|---|---|
year | number | — | Override the AssetProvider's year. The report is always scoped to a single fiscal year. |
month | number | null | — | Override the AssetProvider's month (1-12). When set, the report locks to that single month — breakdown is forced to "month" and consumers should disable other breakdowns in their UI. null / omit to inherit. |
defaultBreakdown | "month" | "quarter" | "year" | — | Initial period breakdown. Defaults to "year". year → 1 column, quarter → 4 columns, month → 12 columns. Ignored when month is locked. Consumers can update at runtime via setBreakdown from the hook. |
records | ReportLine[] | — | Override fetched data with a single snapshot — primarily for testing/storybook. |
tagOptions | ProfitLossTagOption[] | — | Override the fetched tag filter options ({ label, value }[], value in field:value format) — primarily for testing/storybook. Pass [] to hide the tag filter. Prefer tagFields for new code. |
tagFields | TagFilterField[] | — | Override the fetched tag fields ({ name, values }[]) — preferred over tagOptions for testing/storybook. Pass [] to hide the tag filter. |
state | "loading" | "error" | "empty" | — | Force a specific state for testing. |
childrenrequired | ReactNode | — | Compound parts. |
Parts
Container
Always rendered. Provides data and context to its children.
| Part | Description |
|---|---|
ProfitLossReport.Root | Fetches the multi-period profit and loss report and provides context. |
Breakdown selector
Headless primitives that wire a Select-shaped UI to the report's breakdown state — no hook plumbing required.
| Part | Description |
|---|---|
ProfitLossReport.BreakdownSelect | Wraps a single Select-Root-shaped child (e.g. Radix Select.Root) and merges value + onValueChange via React.cloneElement. The consumer keeps full control over trigger, content, and styling. |
ProfitLossReport.BreakdownItems | Iterates the three breakdown options (Month / Quarter / Year), setting a per-option context that BreakdownItem reads. When the report is monthLocked, Quarter and Year carry disabled: true. |
ProfitLossReport.BreakdownItemasChild? | Renders one option. Pair with asChild and a SelectItem-like child — the SDK injects value, disabled, and the option's label as the child's text. |
ProfitLossReport.BREAKDOWN_OPTIONS | The raw [{value, label}, …] list, exported for consumers that want to render their own iteration. |
Tag filter
Headless primitives that wire a checkbox-menu UI to the report's tag filter. Options are fetched from the business's tag fields (one per field/value pair, requires the tag:read scope); selecting tags refetches the report filtered to the selected set.
| Part | Description |
|---|---|
ProfitLossReport.TagItemsquery? | Iterates the tag filter options, optionally filtering their labels case-insensitively with query, and sets a per-option context that TagItem reads. Renders nothing while the options load or when the business has no tags — check useProfitLossReport().tagOptions.length to hide the surrounding trigger too. |
ProfitLossReport.TagItemasChild? | Renders one tag option. Pair with asChild and a CheckboxItem-like child (e.g. Radix DropdownMenu.CheckboxItem) — the SDK injects checked, onCheckedChange, and the option's label as the child's text. |
Periods
Header / per-row period iteration.
| Part | Description |
|---|---|
ProfitLossReport.Periods | Iterates each period column. Sets a period context that PeriodLabel / LineAmount read from. Use it once for the column headers and once inside each row for amounts. |
ProfitLossReport.PeriodLabelasChild? | Renders the current period's label (e.g. "Apr" for month, "Q2" for quarter, "2026" for year). |
Success
Renders when records are available.
| Part | Description |
|---|---|
ProfitLossReport.Success | State wrapper. Compose the table inside. |
ProfitLossReport.Sectionshide?: string[] | Iterates each top-level row as a section. Empty sections (groups whose descendants have no entries / non-zero amounts, or calc leaves with no entries / zero amount) are filtered out. `hide` further filters top-level lines by name — typically ["Gross Profit", "Total Operating Profit"] to drop the API's running-total leaves that would otherwise duplicate the per-section subtotals. |
ProfitLossReport.Lines | Iterates the current section's lines. Must be used inside <Sections> (throws otherwise — use the useProfitLossReport().lines hook for raw flat access). Group sections expand into heading → descendants → total; calc-leaf sections yield a single row. Each iteration sets the line context plus a role so <Line> emits the right data attribute. |
ProfitLossReport.LineasChild? | Wrapper that adds data-depth, data-leaf, data-group, data-section, data-section-heading and data-section-total attributes based on the current line and (when inside Sections) its role. The same template renders headings, descendants and totals — CSS differentiates them by attribute. |
ProfitLossReport.LineNameasChild? | Renders the line name. On a section's total row this is auto-prefixed with "Total " (skipped if the section name already starts with "Total "). |
ProfitLossReport.LineAmountasChild?, format? | Renders the line's amount for the current period (when used inside Periods) or the most recent period (when used outside). On group section heading rows, the rolled-up amount is hidden by default in the styled drop-in's CSS. |
Loading
Renders while the fetch is in flight.
| Part | Description |
|---|---|
ProfitLossReport.Loading | State wrapper. Render any skeleton or placeholder UI inside. |
Empty
Renders when the fetch returned no records.
| Part | Description |
|---|---|
ProfitLossReport.Empty | State wrapper. Render an empty-state message inside. |
Error
Renders on fetch error.
| Part | Description |
|---|---|
ProfitLossReport.Error | State wrapper. Compose the error UI inside. |
ProfitLossReport.ErrorMessageasChild? | Renders the error message string. |
ProfitLossReport.RetryasChild? | Button that re-runs the fetch. |
Download
Triggers an XLSX export of the report using the same query parameters that produced the on-screen view.
| Part | Description |
|---|---|
ProfitLossReport.DownloadasChild? | Button that calls the SDK's download action when clicked. Hits /reports/profit-and-loss with start_datetime, end_datetime, period (= breakdown) and tags (when a tag filter is selected) and saves the response as profit-and-loss-{year}-{breakdown}.xlsx. No-op when records / state overrides are active. |
Hooks
| Part | Description |
|---|---|
useProfitLossReport() | Hook returning breakdown, setBreakdown, monthLocked, periods, lines, hasData, loading, error, retry, download, tagOptions, tagFields, selectedTags, setSelectedTags, toggleTag. monthLocked is true when a specific month is selected — setBreakdown is a no-op while it is, and consumers should disable Quarter / Year in their UI. download() is a Promise<void> that triggers the XLSX export (filtered to the selected tags). |
useProfitLossReportLine() | Hook used inside a Lines iteration; returns the current line node (with amounts: number[]). |
useProfitLossReportPeriod() | Hook used inside a Periods iteration; returns the current period info. |
useProfitLossSection() | Hook used inside a Sections iteration; returns the current section ({ row, descendants }). |