7. Reporting
One page per grant with a period selector, KPI tiles, the contract summary, and an EU donor XLSX export.
Period selector
Dropdown of generated periods: Cumulative + Year 1/2/3 + (mid-term) + Final + calendar/fiscal years. Periods come from the cycle's reporting cadence (chapter 12.5) when one is configured, otherwise from the default generator.
Switching periods filters every number on the page to that date window. The export uses the same selection.
KPI strip
- Budget — total committed in the selected period.
- Actuals — sum of postings (Odoo + manual sub-grant) in the period.
- Spent — % of budget consumed.
- Remaining — budget − actuals.
Per-category table
One row per cycle category. Direct subtotal + indirect rows separated for clarity. The Difference column highlights overspend. On a multi-year grant the categories are summed across all fiscal years, so each category appears once (not once per year).
Open in Odoo
Next to the Refresh button on the Budget vs actuals card sits a blue Open in Odoo link — one per project that is synced to Odoo. It opens that project's Analytic Items list in Odoo in a new tab, already grouped by budget category, so you can drill from a reported figure straight into the underlying postings.
Detail breakdown card
Expandable card showing every detail row with its budget, actual, and variance — populated from budget_detail_lines after a Refresh actuals.
Reporting currency & exchange rates
The grant's currency is its reporting currency: the budget is authored in it, all actuals are converted into it, and the export is denominated in it. That works out of the box while every posting is booked in the same currency (the common case). It matters the moment a grant spans multiple country offices whose Odoo companies keep their books in different currencies — Odoo stores each analytic line in the booking company's own currency, so summing them raw would silently mix currencies.
A Reporting currency & exchange rates card on the grant page (finance/admin only) handles this. togrant auto-detects every foreign currency that appears in the grant's postings and lists one row per currency:
- Fixed — one donor-agreed rate for the whole grant, entered by hand. This is the donor default: EU INTPA, the Dutch MFA and most institutional donors require the report at an agreed rate, not the daily market rate. The card states the direction explicitly (1 UGX = 0.00024 EUR) and shows the inverse read-only so the rate can't be entered upside-down. Store the donor agreement reference in the note field.
- Odoo — convert at Odoo's own dated rate per posting (via
res.currency), for grants whose donor accepts Odoo's rates. No rate to type.
Conversion happens per line, then sums — each posting is converted and rounded to the reporting currency before it's added up, so the category total always equals the sum of its converted transactions (see the Transactions sheet below). What togrant caches in the actuals is therefore already in the reporting currency, keeping budget-vs-actual apples-to-apples.
What it looks like
The budget and all actuals are reported in EUR. Postings booked in another currency are converted using the rates below.
| Currency | Mode | Rate (1 unit = ? EUR) | Note |
|---|---|---|---|
| ETB | Fixed rate | 0.016 | Donor agreement §7 |
| UGX | Fixed rate | 0.00024 | EU FED/2022 Art. 4.2 |
Above: an Ethiopia office booking in ETB and a Uganda office in UGX, both fixed at the donor-agreed rate. A currency with an empty rate would instead show the amber "rate required" banner and be held out of the actuals.
The budget itself is always in the reporting currency — foreign-currency budgets (as opposed to actuals) are out of scope; only the actuals coming back from Odoo are converted.
EU donor XLSX export
Generates the EU consolidated financial report layout (multi-sheet workbook):
- Budget vs Actual main sheet — categories + detail rows, populated.
- Year YYYY sheets (only when the grant has Budget years > 1; see chapter 5 Multi-year budgets). One sheet per fiscal year between the main sheet and Partners, filtered to that year's
budget_linesrows. Same layout as the main sheet so reviewers don't have to relearn the columns. - Partners sheet — split of actuals per sub-grant partner (from manual actuals on not-in-Odoo projects).
- All Report sheet — wide layout with calendar/fiscal year columns.
- Transactions sheet — every individual Odoo posting line behind the report (only when there are Odoo-synced projects). Columns: Date · Description · Project · Category · Detail · Currency · Amount · Amount (reporting). It gives the donor a line-by-line audit trail, and it reconciles: the sum of the Amount (reporting) column equals the category actuals on the main sheet. When a foreign currency is in play (see Reporting currency & exchange rates), each line shows its original currency and amount next to the converted figure.
The selected period drives the date filter. Cumulative gives the standard donor-format export; pick Year 1/2/3 for annual reports. On a multi-year grant the per-year sheets give you the same split without re-running the export.
Transactions sheet — what it looks like
| Date | Description | Project | Category | Detail | Currency | Amount | Amount (reporting) |
|---|---|---|---|---|---|---|---|
| 2025-03-14 | Field coordinator salary | Ethiopia office | HR | HR-01 Staff | ETB | 45.000,00 | € 720,00 |
| 2025-04-02 | Kampala workshop venue | Uganda office | SVC | SVC-02 Events | UGX | 3.800.000,00 | € 912,00 |
| 2025-04-20 | Consultant fee | HQ | SVC | SVC-01 Consultancy | EUR | 3.314,00 | € 3.314,00 |
| Total (reporting) | € 4.946,00 | ||||||
Each line keeps its original currency and amount next to the converted figure. The Amount (reporting) column sums to the category actuals on the main sheet — here ETB 45.000 × 0.016 and UGX 3.800.000 × 0.00024 land as € 720 and € 912, the EUR line passes through unchanged.