---
source: https://carbone.io/examples/bank-statement-expert/
title: "Generate Professional Bank Statements | Carbone Sample"
description: "Learn how to generate professional bank statements automatically. Create dynamic PDF reports from JSON data using templates in DOCX, PPTX, or XLSX formats with our powerful document generator."
generated_at: "2026-07-13"
---

# Bank statement (expert)

Generate a complete bank statement with Carbone

[![bank-statement-expert thumbnail](/examples/bank-statement-expert/thumb-result.webp)](/examples/bank-statement-expert/result.pdf)

[Download Template](/examples/bank-statement-expert/template.docx)

[Download data sample](/examples/bank-statement-expert/data.json)

-   Template type document docx expert
-   Carbone min. v5.0.0+
-   Features loop set count aggregator pagination subtotal
-   Target bank insurance quote

## Overview

This example shows how to generate a professional bank statement that includes:

-   Multiple transactions spread across multiple pages
-   Automatic calculation of intermediate balance per page
-   Dynamic handling of varying transaction lengths

## Step-by-Step Guide

The main challenge is to handle transactions of different lengths and display them correctly across multiple pages. Here's how to implement this using Carbone:

### 1\. Organizing Data by Page

-   First, define your layout constraints:
    
    -   Characters per line (example: `45`)
    -   Lines per page (example: `35`)
-   Calculate how many lines each transaction needs by following these steps:
    
    -   Measure the transaction text length with the [:len](/documentation/design/formatters/text.md#len) formatter
        
    -   Divide it by characters per line (45) with the [:div](/documentation/design/formatters/number.md#div-value) formatter
        
    -   Round up to the next whole number with the [:ceil](/documentation/design/formatters/number.md#ceil) formatter
        
    -   Add 1 for line spacing with the [:add](/documentation/design/formatters/number.md#add-value) formatter
        
    -   Calculate running total with the [:cumSum](/documentation/design/computation/aggregation.md#cumsum-partitionby) formatter
        
    -   Store result in `nbLine` new variable with the [:set](/documentation/design/computation/store-and-transform.md#store-values-set-absolutepath) formatter ([v5 feature](/documentation/design/overview/version-lifecycle.md#pre-release-features))
        
        Formula:
        
        ```text
        {d.operations[].transaction:len:div(45):ceil:add(1):cumSum:set(.nbLine)}
        ```
        

-   Calculate which page each transaction belongs to by following these steps:
    
    -   Take the line count
        
    -   Divide by maximum lines per page (35) with the [:div](/documentation/design/formatters/number.md#div-value) formatter
        
    -   Round up to get the page number with the [:ceil](/documentation/design/formatters/number.md#ceil) formatter
        
    -   Store result in `numPage` new variable with the [:set](/documentation/design/computation/store-and-transform.md#store-values-set-absolutepath) formatter ([v5 feature](/documentation/design/overview/version-lifecycle.md#pre-release-features))
        
        Formula:
        
        ```text
        {d.operations[].nbLine:div(35):ceil:set(.numPage)}
        ```
        

-   Group transactions by page number with the [:set](/documentation/design/computation/store-and-transform.md#join-two-arrays-set-absolutepath) formatter ([v5 feature](/documentation/design/overview/version-lifecycle.md#pre-release-features)):
    
    ```text
     {d.operations[]:set(d.group[id=.numPage].data[])}
    ```
    
-   Use the new structure in your template:
    
    ```text
     {d.group[i].data[i].transaction}
    ```
    

**Data Structure Example**

````text
Before processing:
```json
{
  "operations": [
    {
      "transaction": "School fees payment - Sunshine High School for March tuition",
      "amount": -300
    },
    {...},
    {
      "transaction": "Doctor's consultation fee - CARDIO HOSPITAL - AVENUE DES CHAMPS ELYSEES - 85000 PARIS - SS284591478D21784512",
      "amount": -80
    }
  ]
}
```

After processing:
```json
{
  "operations": [
    ...
  ],
  "group":[
    {
      "data": [
      {
        "transaction": "School fees payment - Sunshine High School for March tuition",
        "amount": -300,
        "nbLine": 3,
        "numPage": 1
      },
      {...}
      ]
    },
    {
      "data": [
      {
        "transaction": "Doctor's consultation fee - CARDIO HOSPITAL - AVENUE DES CHAMPS ELYSEES - 85000 PARIS - SS284591478D21784512",
        "amount": -80,
        "nbLine": 41,
        "numPage": 2
      },
      {...}
      ]
    }
  ]
}
```
````

### 2\. Calculating Financial Totals

-   For each page, calculate separate **subtotals** for debits and credits:
    
    -   For debits (negative amounts):
        
        -   consider positive amounts to 0 with [:ifGTE()](/documentation/design/conditions/overview.md#ifgte-value) and [:show](/documentation/design/conditions/inline-conditions.md#show-text-elseshow-text) formatters,
        -   then compute [:aggSum](/documentation/design/computation/aggregation.md#learn-with-aggsum-partitionby) and apply currency formatting with [:formatC](/documentation/design/formatters/currency.md#formatc-precisionorformat-targetcurrency) formatter
            
            ```text
            {d.group[i].data[].amount:ifGTE(0):show(0):aggSum:formatC}
            ```
            
    -   For credits (positive amounts):
        
        -   consider negative amounts to 0 with [:ifLT()](/documentation/design/conditions/overview.md#iflt-value) and [:show()](/documentation/design/conditions/inline-conditions.md#show-text-elseshow-text) formatters,
        -   then compute [:aggSum](/documentation/design/computation/aggregation.md#learn-with-aggsum-partitionby) and apply currency formatting with [:formatC](/documentation/design/formatters/currency.md#formatc-precisionorformat-targetcurrency) formatter
            
            ```text
            {d.group[i].data[].amount:ifLT(0):show(0):aggSum:formatC}
            ```
            
-   Calculate the **running balance** for each page:
    
    ```text
    {d.group[i].data[].amount:aggSum:cumSum:add(...open_bal):formatC}
    ```
    

### Layout Tips

To ensure proper page breaks:

-   Start each new page section with `{d.group[i]}`
-   Configure **Page Break** settings in your template's **Paragraph** options

## More Examples

[![planification-simple thumbnail example](/examples/planification-simple/thumb-result.webp)](/examples/planification-simple/index.md)

## Trusted by 800+ paid customers in 40+ countries

## Related topics

- [Transport ticket](/examples/ticket/index.md)
- [Summary](/examples/summary/index.md)
- [Stock inventory spreadsheet](/examples/stock-inventory-spreadsheet/index.md)
- [Store Inventory](/examples/shoes/index.md)
- [Sensor readings](/examples/sensor-readings/index.md)
- [Real estate property document](/examples/real-estate-property-description/index.md)
