Skip to content

Commit b84de41

Browse files
author
Karl Rankla
committed
Update ERP toolkit documentation: Reading Matching Strategies
1 parent 43d89d3 commit b84de41

1 file changed

Lines changed: 122 additions & 1 deletion

File tree

docs/integrations/erp-toolkit-mapping.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ The ERP Integration Mapping v2.0 provides a powerful and flexible way to transfo
3232
- [Example 3: Combined Entity and Meter Readings](#example-3-combined-entity-and-meter-readings)
3333
- [Validation](#validation)
3434
- [Best Practices](#best-practices-1)
35+
- [Reading Matching Strategies](#reading-matching-strategies)
3536
- [Array Attribute Operations](#array-attribute-operations)
3637
- [Complete Examples](#complete-examples)
3738
- [Best Practices](#best-practices)
@@ -2173,14 +2174,134 @@ The error message includes the item index to help identify which specific meter_
21732174
}
21742175
```
21752176

2176-
4**Validate Data Quality**: Use JSONata expressions to ensure data quality
2177+
4. **Validate Data Quality**: Use JSONata expressions to ensure data quality
21772178
```json
21782179
{
21792180
"attribute": "value",
21802181
"jsonataExpression": "$number(reading_value) >= 0 ? $number(reading_value) : 0"
21812182
}
21822183
```
21832184

2185+
### Reading Matching Strategies
2186+
2187+
By default, meter readings use `external_id` for upsert matching. However, when readings originate from ECP (End Customer Portal) and are later echoed back by the ERP system, duplicates can occur because:
2188+
- ECP readings don't have an `external_id` initially
2189+
- ERP often truncates timestamps to date precision, causing timestamp mismatches
2190+
2191+
The `reading_matching` option allows you to configure how incoming readings are matched against existing readings.
2192+
2193+
**Available Strategies:**
2194+
2195+
| Strategy | Description |
2196+
|----------|-----------------------------------------------------------------------|
2197+
| `external_id` | Default. Match readings by `external_id` attribute (default behavior) |
2198+
| `strict-date` | Match by meter_id + counter_id + direction + date (German timezone) |
2199+
2200+
**Configuration:**
2201+
```json
2202+
{
2203+
"meter_readings": [
2204+
{
2205+
"reading_matching": "strict-date",
2206+
"meter": { ... },
2207+
"fields": [ ... ]
2208+
}
2209+
]
2210+
}
2211+
```
2212+
2213+
**`strict-date` Strategy Details:**
2214+
2215+
When using `strict-date`:
2216+
1. Before creating a reading, the system looks up existing readings for the same meter_id + counter_id + direction on the same **German calendar day** (Europe/Berlin timezone)
2217+
2. If a **single match** is found: The existing reading is updated with ERP data (including setting `external_id` for future syncs)
2218+
3. If **multiple matches** are found: An error is logged and the operation is skipped (to avoid creating duplicates)
2219+
4. If **no match** is found: A new reading is created normally
2220+
2221+
**Why German Timezone?**
2222+
2223+
ECP users in Germany submit readings that are stored with full timestamp precision. When the ERP echoes the reading back, it often truncates to date-only (e.g., `2025-01-15T00:00:00Z`). By comparing dates in German timezone:
2224+
- A reading submitted at 23:30 CET on Jan 15 will match an ERP echo dated Jan 15
2225+
- Timestamps across the UTC midnight boundary are handled correctly
2226+
2227+
**Example: ECP → ERP Roundtrip**
2228+
2229+
1. Customer submits reading via ECP at `2025-01-15T14:30:45.123Z` (15:30 German time)
2230+
2. Reading is saved in metering-api without `external_id`
2231+
3. ERP receives the reading and echoes it back with `timestamp: "2025-01-15T00:00:00Z"` and `external_id: "ERP-12345"`
2232+
4. With `reading_matching: "strict-date"`:
2233+
- System finds existing reading on Jan 15 (German date)
2234+
- Updates it with ERP's `external_id`, `timestamp`, and `value`
2235+
- Future ERP updates will match by `external_id`
2236+
2237+
**Expected Behavior Matrix:**
2238+
2239+
| Scenario | Result |
2240+
|----------|--------|
2241+
| ECP submission → ERP echo | Update existing ECP reading, set `external_id` |
2242+
| ERP sends same reading multiple times | All updates hit the same record |
2243+
| ERP modifies value | Overwrites ECP value (ERP is source of truth) |
2244+
| Reading only from ERP (no prior ECP) | Creates new reading normally |
2245+
| Multiple readings on same date | Log error, skip to avoid duplicate |
2246+
2247+
**Complete Example:**
2248+
2249+
```json
2250+
{
2251+
"version": "2.0",
2252+
"mapping": {
2253+
"events": {
2254+
"MeterReadingsChanged": {
2255+
"meter_readings": [
2256+
{
2257+
"reading_matching": "strict-date",
2258+
"jsonataExpression": "$.readings",
2259+
"meter": {
2260+
"unique_ids": [
2261+
{
2262+
"attribute": "external_id",
2263+
"field": "meter_id"
2264+
}
2265+
]
2266+
},
2267+
"meter_counter": {
2268+
"unique_ids": [
2269+
{
2270+
"attribute": "external_id",
2271+
"field": "counter_id"
2272+
}
2273+
]
2274+
},
2275+
"fields": [
2276+
{
2277+
"attribute": "external_id",
2278+
"field": "reading_id"
2279+
},
2280+
{
2281+
"attribute": "timestamp",
2282+
"field": "read_at"
2283+
},
2284+
{
2285+
"attribute": "source",
2286+
"constant": "ERP"
2287+
},
2288+
{
2289+
"attribute": "value",
2290+
"field": "reading_value"
2291+
},
2292+
{
2293+
"attribute": "direction",
2294+
"field": "direction"
2295+
}
2296+
]
2297+
}
2298+
]
2299+
}
2300+
}
2301+
}
2302+
}
2303+
```
2304+
21842305
## Array Attribute Operations
21852306

21862307
Regular array attributes (like `_tags`, custom array fields, etc.) support `_set`, `_append`, and `_append_all` operations. These work similarly to relation operations but for simple array values.

0 commit comments

Comments
 (0)