# JasperReports to Capacit Report Converter

Converts JasperReports XML (.jrxml) files to Capacit web page JSON format.

## Usage

```bash
cd /Volumes/nc/nc-server/tool/report-convert
lj jasper-convert.lua
```

## Configuration

Edit the configuration at the top of `jasper-convert.lua`:

```lua
local fileToConvertPath = "report-example/"
local fileToConvert = {"invoice-mac", "production_order-va-poland"}
local exportName = {
    ["invoice-mac"] = {
        table = "order",           -- main table name
        row_table = "order_row",   -- row/detail table name
        savePath = "form/nc/report/form/invoice/",
        column = "form/nc/report/form/column/order-invoice.json"
    },
    ["production_order-va-poland"] = {
        table = "production_order",
        row_table = "product_work",
        savePath = "form/nc/report/form/production_order/",
        column = "form/nc/report/form/column/production_order.json"
    }
}
```

## Row Detection Configuration

```lua
local rowDetectionConfig = {
    topTolerance = 5,           -- fields within 5px top are considered same row
    bottomTolerance = 8,        -- fields within 8px bottom are considered same row
    createGridLayout = true,    -- create grid component in layout
    createLayoutFields = true   -- keep fields in detail section alongside grid
}
```

## Conversion Process

1. **Parse JRXML** - Convert XML to JSON tree structure
2. **Convert Components** - Map Jasper components to Capacit components:
   - `jasperReport` → `nc-form`
   - `pageHeader` → `nc-report-header`
   - `detail` → `nc-detail`
   - `pageFooter` → `nc-report-footer`
   - `textField` → `nc-input` or `nc-textarea`
   - `staticText` → `nc-span`
   - `line` → `nc-line` or `nc-line-v`
   - `image` → `nc-image`

3. **Detect Row Fields** - Analyze detail section for row table fields
   - Groups fields by vertical position (with tolerance)
   - Extracts field names from model paths

4. **Create Grid** - Generates grid components for row data:
   - `grid.json` - Grid definition
   - `query/order_row.json` - Query definition
   - `column/order_row.json` - Column definitions
   - `rec.json` - Record state
   - `hdr.json` - Header translations

## Output Files

| File | Description |
|------|-------------|
| `init.json` | Main initialization file |
| `invoice.json` | Layout definition |
| `invoice-field.json` | Field definitions |
| `invoice-variable.json` | Variable definitions |
| `invoice-css.json` | CSS font classes |
| `grid.json` | Grid definition |
| `rec.json` | Record state |
| `hdr.json` | Header translations |
| `column/order_row.json` | Grid column definitions |
| `query/order_row.json` | Grid query definition |

## Completed Fixes

### 1. Double JSON Encoding Bug (Line 887)

**Problem**: `saveJsonFile("init.json", json.toJsonKeySorted(init), savePath)` was encoding twice.
**Fix**: Changed to `saveJsonFile("init.json", init, savePath)` - the function handles encoding internally.

### 2. Improved Row Field Detection

**Problem**: Original tolerance of 4px was too strict for hand-built reports.
**Fix**:

- Added configurable `topTolerance` (5px) and `bottomTolerance` (8px)
- Fields with similar top OR bottom positions are grouped together
- Handles varying heights (pictures, multi-line fields)

### 3. Field Extraction from nc-col

**Problem**: Detection looked at nc-col position but needed the actual field model inside.
**Fix**: `extractFieldFromCol()` function now looks inside nc-col element for:

- `model` path
- `component` type
- `text-align` attribute
- `format` pattern

### 4. Column Creation from Detail Fields

**Problem**: Columns were only created from external column file.
**Fix**: `createColumnsFromDetail()` now:

- Extracts field names from detected detail fields
- Checks if field uses rowPrefix (is a row field)
- Merges with existing column definitions
- Creates column file automatically

### 5. Directory Creation for Subfolders

**Problem**: Writing to `query/` and `column/` subfolders failed when directories didn't exist.
**Fix**: `saveJsonFile` now creates directories with `fs.createFilePath()` before writing.

## Test Results

Both example files convert successfully:

- `invoice-mac.jrxml` → `form/nc/report/form/invoice/`
- `production_order-va-poland.jrxml` → `form/nc/report/form/production_order/`

## Component Mapping Details

| JasperReports | Capacit | Notes |
|---------------|---------|-------|
| `band` | `nc-row` | Container for row elements |
| `textField` | `nc-input` | Editable field |
| `textField` (text) | `nc-textarea` | Multi-line text |
| `staticText` | `nc-span` | Static label |
| `image` | `nc-image` | Image with src |
| `line` (horizontal) | `nc-line` | Horizontal line |
| `line` (vertical) | `nc-line-v` | Vertical line |
| `rectangle` | `nc-border` | Border container |

## Field Model Mapping

JasperReports field expressions are converted to Capacit model paths:

| JasperReports | Capacit |
|---------------|---------|
| `$F{inr_atExplanation}` | `rec.ordr.description` |
| `$V{in_sOtsikko}` | `rec.in_sOtsikko` |
| `[Invoice]Reference_Number` | `rec.json_data.bank_reference_number` |

The `dschema-4d` module handles the conversion from 4D variable names to database field names.

## Tolerance Handling

Fields are grouped by vertical position with tolerance:

```text
Field A: top=100, height=12  (bottom=112)
Field B: top=103, height=12  (bottom=115)  <- topDiff=3, same row
Field C: top=150, height=50  (bottom=200)  <- different row (picture)
Field D: top=155, height=12  (bottom=167)  <- topDiff=5, same row as C (bottomDiff=33)
```

The algorithm checks:

1. `topDiff <= topTolerance` - same row
2. `bottomDiff <= bottomTolerance` - same row (for tall elements)

Both conditions are checked to handle overlapping and tall elements.
