dart_action_openingstijdenbordjes_convert_to_csv_and_xml version: 0.0.12

Published 2026-07-03

reinbeumer

sdk | dart
repository | svn
platform | console
status | n/a
  • Readme
  • Changelog
  • Versions

Opening Hours Sign Generator

Generate CSV and XML files for store opening hours signs from JSON input data.

graph

Table of Contents


Overview

This Dart command-line tool processes store opening hours data and generates:

  • CSV files: Bulk data for sign printing (grouped by country/language)
  • XML files: Individual files per store for automated sign generation
  • Processing reports: Detailed logs of what was processed and any issues

Perfect for:

  • Retail chains managing multiple store locations
  • Sign printing services
  • Automated signage systems
  • Multi-country operations

Features

Multi-Country Support: NL, FR, DE, AT, PL, SK, IT, ES
Country-Specific Formatting: Automatic time format adaptation
Comprehensive Validation: Catches data errors before processing
Detailed Error Reporting: Know exactly what went wrong and where
Batch Processing: Handle hundreds of stores efficiently
ISO Week Support: Proper week number calculations
Address Parsing: International address format support
Audit Trail: Complete processing reports with statistics


Installation

Prerequisites

  • Dart SDK 3.10.3 or higher
  • Git (for cloning)

Install Dart SDK

macOS (using Homebrew):

brew tap dart-lang/dart
brew install dart

Linux:

sudo apt-get update
sudo apt-get install apt-transport-https
wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo gpg --dearmor -o /usr/share/keyrings/dart.gpg
echo 'deb [signed-by=/usr/share/keyrings/dart.gpg] https://storage.googleapis.com/download.dartlang.org/linux/debian stable main' | sudo tee /etc/apt/sources.list.d/dart_stable.list
sudo apt-get update
sudo apt-get install dart

Windows (using Chocolatey):

choco install dart-sdk

Clone and Setup

# Clone repository
git clone <repository-url>
cd dart_action_openingstijdenbordjes_convert_to_csv_and_xml

# Get dependencies
dart pub get

Usage

Basic Command

dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart --inputFile /path/to/input.json

Short Form

dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart -i /path/to/input.json

What Happens

  1. Reads your JSON file
  2. Validates all store data
  3. Groups stores by country/language
  4. Generates CSV files (one per country)
  5. Generates XML files (one per store)
  6. Creates a detailed processing report
  7. Shows summary in console

Output Location

All files are created in the same directory as your input file:

/path/to/input/directory/
├── csv_output/
│   ├── Week 49 - nl-NL - A4-poster openingstijden 2025.csv
│   ├── Week 49 - fr-FR - A4-poster openingstijden 2025.csv
│   └── ...
├── xml_output/
│   ├── 1001_Openingstijden week 49.xml
│   ├── 1002_Openingstijden week 49.xml
│   └── ...
└── processing_report_20251209_153045.txt

Input Format

JSON Structure

[
  {
    "store": "1001",
    "name_sm": "John Doe",
    "street": "Main Street",
    "house_no": "123",
    "house_no_suffix": "",
    "postal_code": "1234 AB",
    "city": "Amsterdam",
    "language": "NL",
    "country": "NL",
    "monday": "08:00 - 18:00",
    "tuesday": "08:00 - 18:00",
    "wednesday": "08:00 - 18:00",
    "thursday": "08:00 - 18:00",
    "friday": "08:00 - 18:00",
    "saturday": "08:00 - 17:00",
    "sunday": "12:00 - 17:00",
    "number_of_signs": 2,
    "week": 49,
    "year": 2025
  }
]

Field Descriptions

Field Type Required Description Example
store String ✅ Yes Store identification number "1001", "7169"
name_sm String ❌ Optional Store manager name "John Doe", ""
street String ✅ Yes Street name. If house_no is empty and the street starts with a number, that number is extracted automatically. "Main Street", "52 Rue Emile Zola"
house_no String ❌ Optional House number. Defaults to 0 when empty and no leading street number can be extracted. "123", "", "15-17"
house_no_suffix String ❌ Optional House number suffix or addition. "", "A", "bis"
postal_code String ✅ Yes Postal/ZIP code "1234 AB", "5071"
city String ✅ Yes City name "Amsterdam"
language String ✅ Yes Language code (uppercase) "NL", "FR", "DE"
country String ✅ Yes Country code (uppercase) "NL", "AT", "FR"
monday String ⚠️ Special* Monday hours "08:00 - 18:00", ""
tuesday String ⚠️ Special* Tuesday hours "08:00 - 18:00", ""
wednesday String ⚠️ Special* Wednesday hours "08:00 - 18:00", ""
thursday String ⚠️ Special* Thursday hours "08:00 - 18:00", ""
friday String ⚠️ Special* Friday hours "08:00 - 18:00", ""
saturday String ⚠️ Special* Saturday hours "08:00 - 17:00", ""
sunday String ⚠️ Special* Sunday hours "12:00 - 17:00", ""
number_of_signs Int/String ❌ Optional Number of signs to generate (defaults to 2) 2, "3", ""
week Int/String ✅ Yes ISO week number (1-53) 49, "49"
year Int/String ✅ Yes Year 2025, "2025"

⚠️ Special: Individual days can be empty (= closed), but at least ONE day must have hours

Address normalization:

  • "street": "52 Rue Emile Zola", "house_no": "" becomes street Rue Emile Zola with house number 52
  • "street": "Rue Des Bas Buissons", "house_no": "" defaults house number to 0

Output Files

CSV Files

Location: csv_output/
Naming: Week {week} - {ISO} - A4-poster openingstijden {year}.csv
Purpose: Bulk data for printing systems
Format: UTF-16LE with BOM

Columns:

Filiaal,Naam bedrijfsleider,Straat,Huisnummer,Toevoeging,Postcode,Plaats,Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag,Zaterdag,Zondag,Datum

Example Row:

1001,John Doe,Main Street,123,,1234 AB,Amsterdam,08:00 - 18:00,08:00 - 18:00,08:00 - 18:00,08:00 - 18:00,08:00 - 18:00,08:00 - 17:00,12:00 - 17:00,2025-12-01

Note: Each store generates 2 rows (for number_of_signs)

XML Files

Location: xml_output/
Naming: {store}_Openingstijden week {week}.xml
Purpose: Individual store sign generation
Format: UTF-8 with BOM

Example:

<?xml version="1.0" encoding="UTF-8"?>
<order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml">
  <deliveryDate>2025-12-01</deliveryDate>
  <deliveryAddress>
    <companyNumber>1001</companyNumber>
    <yourReference>1001 - Openingstijden week 49</yourReference>
    <companyName>Action 1001</companyName>
    <countryCode>nl-NL</countryCode>
    <street>Main Street</street>
    <houseNo>123</houseNo>
    <houseNoSuffix></houseNoSuffix>
    <postcode>1234 AB</postcode>
    <city>Amsterdam</city>
    <email>blackhole@huighaverlag.nl</email>
  </deliveryAddress>
  <articles>
    <article>
      <quantity>2</quantity>
      <articleNumber>9700000</articleNumber>
      <articleDescription>(Entreebord  openingstijden A4 oblong) week 49 - nl-NL - entreebord A4 oblong_openingstijden 2025</articleDescription>
      <ignoreMax>true</ignoreMax>
    </article>
  </articles>
</order>

Processing Report

Location: Same as input file
Naming: processing_report_YYYYMMDD_HHMMSS.txt
Purpose: Detailed processing log and audit trail

Sections:

  1. SUMMARY: Status, timing, file paths
  2. STATISTICS: Counts of stores, files, errors, warnings
  3. ISO GROUPS PROCESSED: Details per country/language
  4. WARNINGS: Non-fatal issues (e.g., default values used)
  5. ERRORS: Validation errors with full details
  6. FILE BREAKDOWN: Complete list of generated files

Example Output:

================================================================================
OPENING HOURS PROCESSING REPORT
================================================================================

SUMMARY
--------------------------------------------------------------------------------
Status:              SUCCESS
Input File:          /data/stores.json
Output Directory:    /data
Start Time:          2025-12-09 15:30:45
End Time:            2025-12-09 15:30:46
Processing Time:     27ms

STATISTICS
--------------------------------------------------------------------------------
Total Stores Processed:     21
ISO Groups Processed:       7
CSV Files Generated:        7
XML Files Generated:        21
Warnings:                   2
Errors Encountered:         0
...

Country Support

Country ISO Code Time Format Example Closed Text
Netherlands nl-NL 08:00 - 18:00 Colon, leading zeros Gesloten
France fr-FR 8h00 - 18h00 h separator, no leading zero Fermé
Germany de-DE 08.00 - 18.00 Dot separator, leading zeros Geschlossen
Austria de-AT 08.00 - 18.00 Dot separator, leading zeros Geschlossen
Poland pl-PL 08:00 - 18:00 Colon, leading zeros Zamknięte
Slovakia sk-SK 08:00 - 18:00 Colon, leading zeros Zatvorené
Italy it-IT 08:00 - 18:00 Colon, leading zeros Chiuso
Spain es-ES 08:00 - 18:00 Colon, leading zeros Cerrado

Adding New Countries: See CODE_DOCUMENTATION.md → Extensibility


Validation Rules

Required Fields (Cannot be Empty)

❌ These will cause validation errors if empty or missing:

  • store - Store number
  • street - Street address
  • postal_code - Postal code
  • city - City name
  • language - Language code
  • country - Country code
  • week - Week number
  • year - Year

Optional Fields (Can be Empty)

✅ These are allowed to be empty:

  • name_sm - Store manager name
  • monday through sunday - Opening hours (empty = closed)
  • number_of_signs - Defaults to 2 if empty

Special Rules

⚠️ At least ONE day must have opening hours

  • A store with all 7 days empty will be rejected
  • Error: "Store has no opening hours"

⚠️ Address parsing supports letter suffixes

  • "Main Street 123a" → street="Main Street", number=123, suffix="a"
  • "Oak Street 456B" → street="Oak Street", number=456, suffix="B"

Error Handling

Error Types

Type Description Action
FILE_NOT_FOUND Input file doesn't exist Stop processing
VALIDATION_ERROR Field validation failed Skip store, continue
INVALID_JSON_STRUCTURE JSON format incorrect Stop processing
MISSING_COUNTRY_RULES Unknown ISO code Skip group, continue
CSV_GENERATION_ERROR CSV creation failed Log error, continue
XML_GENERATION_ERROR XML creation failed Log error, continue

What Happens When Errors Occur

  1. Error is logged to console with details
  2. Error is captured in processing report
  3. Processing continues for valid stores (if possible)
  4. Report is generated with complete error details
  5. Summary shows "COMPLETED WITH ERRORS" status

Example Error in Report

ERRORS
--------------------------------------------------------------------------------

Error #1:
  Type:       VALIDATION_ERROR
  Time:       2025-12-09 15:30:45
  Message:    Failed to parse store item at index 3
  Store:      1042
  Details:
    FormatException: Field Street (street) cannot be empty

    Store data: {store: 1042, street: , postal_code: 1234 AB, ...}

Examples

Example 1: Single Store

Input (single_store.json):

[
  {
    "store": "1001",
    "name_sm": "Jane Smith",
    "street": "Main Street",
    "house_no": "123",
    "house_no_suffix": "",
    "postal_code": "1234 AB",
    "city": "Amsterdam",
    "language": "NL",
    "country": "NL",
    "monday": "08:00 - 18:00",
    "tuesday": "08:00 - 18:00",
    "wednesday": "08:00 - 18:00",
    "thursday": "08:00 - 18:00",
    "friday": "08:00 - 18:00",
    "saturday": "08:00 - 17:00",
    "sunday": "",
    "number_of_signs": 2,
    "week": 49,
    "year": 2025
  }
]

Command:

dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart -i single_store.json

Output:

  • csv_output/Week 49 - nl-NL - A4-poster openingstijden 2025.csv
  • xml_output/1001_Openingstijden week 49.xml
  • processing_report_20251209_153045.txt

Example 2: Multiple Countries

Input: 21 stores across 7 countries

Output:

  • 7 CSV files (one per country)
  • 21 XML files (one per store)
  • 1 detailed report

Console Output:

════════════════════════════════════════════════════════════
PROCESSING SUMMARY
════════════════════════════════════════════════════════════
Status:            SUCCESS
Stores Processed:  21
CSV Files:         7
XML Files:         21
Processing Time:   27ms
════════════════════════════════════════════════════════════

Example 3: With Validation Errors

Input: Contains stores with empty required fields

Output:

WARNING: Error parsing store item at index 2 (store: 1003): 
  FormatException: Field Street (street) cannot be empty

════════════════════════════════════════════════════════════
PROCESSING SUMMARY
════════════════════════════════════════════════════════════
Status:            COMPLETED WITH ERRORS
Stores Processed:  20
CSV Files:         7
XML Files:         20
Errors:            1
════════════════════════════════════════════════════════════

Documentation

Document Description
README.md This file - user guide and overview
CODE_DOCUMENTATION.md Complete code documentation with architecture
test/README.md Testing guide and test documentation
VALIDATION_IMPLEMENTATION.md Detailed validation rules
ADDRESS_PARSER_FIX.md Address parsing details
TEST_FIXES.md Test implementation fixes

Testing

Run All Tests

dart test

Run Specific Tests

# Model tests
dart test test/models/store_model_test.dart

# Utility tests
dart test test/utils/time_formatter_test.dart
dart test test/utils/address_parser_test.dart
dart test test/utils/date_utils_test.dart

# Service tests
dart test test/services/report_generator_test.dart

Test Coverage

  • 85+ test cases
  • ✅ All models tested
  • ✅ All utilities tested
  • ✅ All services tested
  • ✅ Edge cases covered

Troubleshooting

Issue: "Input file not found"

Cause: File path is incorrect or file doesn't exist
Solution:

# Use absolute paths
dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart -i /absolute/path/to/file.json

# Or relative from current directory
dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart -i ./relative/path/to/file.json

Issue: "Field cannot be empty"

Cause: Required field has no value
Solution: Add value to the field in your JSON:

{
  "store": "1001",  // ✅ Has value
  "street": "",     // ❌ Empty - will fail
  ...
}

Issue: "Store has no opening hours"

Cause: All 7 days are empty
Solution: Add hours for at least one day:

{
  "monday": "08:00 - 18:00",  // ✅ At least one day
  "tuesday": "",
  ...
  "sunday": "",
  ...
}

Issue: "No rules found for ISO code"

Cause: Country/language combination not supported
Solution: Add rules to lib/config/country_config.dart or contact support

Viewing Detailed Errors

# View full report
cat /path/to/processing_report_*.txt

# View only errors
grep -A 20 "ERRORS" /path/to/processing_report_*.txt

# View only warnings
grep -A 20 "WARNINGS" /path/to/processing_report_*.txt

Performance

Typical Performance:

  • 100 stores: ~100ms
  • 1000 stores: ~1s
  • 10000 stores: ~10s

Memory Usage:

  • Loads entire JSON into memory
  • Suitable for datasets up to 100K stores

Optimization Tips:

  • Group stores by week in separate JSON files
  • Process files in parallel (separate script runs)
  • Use SSD storage for faster I/O

License

See LICENSE file for details.


Support

Issues: Create an issue in the repository
Documentation: See CODE_DOCUMENTATION.md
Tests: Run dart test to verify installation


Version

Current Version: 0.0.4

Changelog:

  • v0.0.4: Comprehensive validation, error reporting, test coverage
  • v0.0.3: AddressParser improvements, letter suffix support
  • v0.0.2: Report generation, warning system
  • v0.0.1: Initial release

Quick Start

# 1. Install Dart
brew install dart

# 2. Get dependencies
dart pub get

# 3. Run with your data
dart run bin/dart_action_openingstijdenbordjes_convert_to_csv_and_xml.dart -i /path/to/your/data.json

# 4. Check outputs
ls -la csv_output/
ls -la xml_output/
cat processing_report_*.txt

Done! Your CSV and XML files are ready to use. 🎉

Changelog

0.0.12 - 2026-07-03

Changed

  • Version bump from 0.0.11 to 0.0.12 (test -> 1.31.2 (was 1.31.1)).

0.0.11 - 2026-06-29

Changed

  • Version bump from 0.0.10 to 0.0.11 (test -> 1.31.1 (was 1.31.2)).

0.0.10 - 2026-06-29

Changed

  • Version bump from 0.0.9 to 0.0.10 (intl -> 0.20.2 (was 0.20.3)).

0.0.9 - 2026-06-29

Changed

  • Version bump from 0.0.8 to 0.0.9 (test -> 1.31.2 (was 1.31.1)).

0.0.8 - 2026-06-29

Changed

  • Version bump from 0.0.7 to 0.0.8 (intl -> 0.20.3 (was 0.20.2)).

0.0.7 - 2026-04-28

Changed

  • Version bump from 0.0.6 to 0.0.7 (test -> 1.31.1 (was 1.31.0)).

0.0.6 - 2026-03-24

Changed

  • Version bump from 0.0.5 to 0.0.6 (csv -> 8.0.0 (was 6.0.0)).

0.0.5 - 2026-03-24

Changed

  • Version bump from 0.0.4 to 0.0.5 (lints -> 6.1.0 (was 6.0.0)).

0.0.1 - 2026-03-24

  • Initial version.

0.0.12

2026-07-03

[exe]

download