Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/432.added
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added KPN Provider, Parser and Tests
2 changes: 2 additions & 0 deletions circuit_maintenance_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
FLAG,
GTT,
HGC,
KPN,
NTT,
PCCW,
RETN,
Expand Down Expand Up @@ -68,6 +69,7 @@
GTT,
Hawaiki,
HGC,
KPN,
Lumen,
Megaport,
Momentum,
Expand Down
116 changes: 116 additions & 0 deletions circuit_maintenance_parser/parsers/kpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""KPN parser."""

import logging
from datetime import datetime, timezone
from typing import Dict, List

from circuit_maintenance_parser.errors import ParserError
from circuit_maintenance_parser.output import CircuitImpact, Impact, Status
from circuit_maintenance_parser.parser import Xlsx

logger = logging.getLogger(__name__)

# KPN spreadsheet column names (bilingual Dutch | English headers)
COL_CIRCUIT_ID = "V/G/A-nummer | V/G/A number"
COL_MAINTENANCE_ID = "Astrid/IDA"
COL_START_DATE = "Startdatum | Start date"
COL_START_TIME = "Starttijd | Start time"
COL_END_DATE = "Einddatum | End date"
COL_END_TIME = "Eindtijd | End time"
COL_DOWNTIME = "Onderbrekingsduur | Downtime"
COL_LINE_ID = "Lijnbenaming | Line ID"
COL_STATUS = "Aankondiging"
COL_ACCOUNT = "Bedrijfsnaam A-locatie | Company A-location"

# Dutch status values in the Aankondiging column
_STATUS_MAP = {
"aankondiging": Status.CONFIRMED, # announcement
"wijziging": Status.CONFIRMED, # change/reschedule — new times supersede old
"annulering": Status.CANCELLED, # cancellation
"afsluiting": Status.COMPLETED, # closure/completed
}


class XlsxParserKPN1(Xlsx):
"""Parse KPN XLSX maintenance notification spreadsheets."""

@staticmethod
def parse_xlsx(records: List[Dict]) -> List[Dict]:
"""Extract maintenance data from KPN Trans_*.xlsx attachment."""
if not records:
raise ParserError("Empty KPN spreadsheet.")

first = records[0]
_check_required_columns(first)

maintenance_id = str(first[COL_MAINTENANCE_ID]).strip()
status = _parse_status(first)
start = _parse_datetime(first[COL_START_DATE], first[COL_START_TIME])
end = _parse_datetime(first[COL_END_DATE], first[COL_END_TIME])
account = str(first.get(COL_ACCOUNT, "")).strip() or "Customer info unavailable"

circuits = []
for row in records:
circuit_id = str(row[COL_CIRCUIT_ID]).strip()
if not circuit_id:
continue
impact = _parse_impact(row)
circuits.append(CircuitImpact(circuit_id=circuit_id, impact=impact))

line_id = str(first.get(COL_LINE_ID, "")).strip()
summary = f"KPN maintenance {maintenance_id}" + (f" ({line_id})" if line_id else "")

return [
{
"maintenance_id": maintenance_id,
"status": status,
"start": int(start.timestamp()),
"end": int(end.timestamp()),
"circuits": circuits,
"summary": summary,
"account": account,
}
]


def _check_required_columns(row: Dict) -> None:
required = [COL_CIRCUIT_ID, COL_MAINTENANCE_ID, COL_START_DATE, COL_START_TIME, COL_END_DATE, COL_END_TIME]
missing = [c for c in required if c not in row]
if missing:
raise ParserError(f"KPN spreadsheet missing required columns: {missing}")


def _parse_datetime(date_str: str, time_str: str) -> datetime:
"""Combine KPN date (DD-MM-YYYY) and time (HH:MM) into a UTC-aware datetime."""
try:
dt = datetime.strptime(f"{date_str} {time_str}", "%d-%m-%Y %H:%M")
return dt.replace(tzinfo=timezone.utc)
except (ValueError, TypeError) as exc:
raise ParserError(f"KPN could not parse date/time '{date_str} {time_str}': {exc}") from exc


def _parse_status(row: Dict) -> Status:
"""Map the Dutch status column value to a Status enum."""
raw = str(row.get(COL_STATUS, "")).strip().lower()
status = _STATUS_MAP.get(raw)
if status is None:
logger.warning("Unrecognized KPN status %r, defaulting to CONFIRMED.", raw)
return Status.CONFIRMED
return status


def _parse_impact(row: Dict) -> Impact:
"""Derive impact from the downtime-minutes column.

KPN's 'Onderbrekingsduur | Downtime' field is an integer number of minutes.
Zero minutes means no service disruption; any positive value is an outage.
"""
raw = row.get(COL_DOWNTIME)
try:
minutes = int(raw)
except (TypeError, ValueError):
logger.warning("KPN could not parse downtime %r, defaulting to OUTAGE.", raw)
return Impact.OUTAGE
if minutes == 0:
return Impact.NO_IMPACT
return Impact.OUTAGE
10 changes: 10 additions & 0 deletions circuit_maintenance_parser/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from circuit_maintenance_parser.parsers.gtt import HtmlParserGTT1
from circuit_maintenance_parser.parsers.hawaiki import SubjectParserHawaiki1, TextParserHawaiki1
from circuit_maintenance_parser.parsers.hgc import HtmlParserHGC1, HtmlParserHGC2, SubjectParserHGC1
from circuit_maintenance_parser.parsers.kpn import XlsxParserKPN1
from circuit_maintenance_parser.parsers.lumen import HtmlParserLumen1
from circuit_maintenance_parser.parsers.megaport import HtmlParserMegaport1
from circuit_maintenance_parser.parsers.momentum import HtmlParserMomentum1, SubjectParserMomentum1
Expand Down Expand Up @@ -659,6 +660,15 @@ class Hawaiki(GenericProvider):
_default_organizer = PrivateAttr("support@bw-digital.com")


class KPN(GenericProvider):
"""KPN provider custom class."""

_processors: List[GenericProcessor] = PrivateAttr(
[CombinedProcessor(data_parsers=[EmailDateParser, XlsxParserKPN1])]
)
_default_organizer = PrivateAttr("gwc-noreply@kpn.com")


class Zayo(GenericProvider):
"""Zayo provider custom class."""

Expand Down
115 changes: 115 additions & 0 deletions tests/unit/data/kpn/kpn1.eml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
Content-Type: multipart/mixed; boundary="===============7215816408978557903=="
MIME-Version: 1.0
From: KPN gepland werk <gwc-noreply@kpn.com>
Reply-To: gwc-noreply@kpn.com
To: test@example.com
Subject: Aankondiging geplande werkzaamheden KPN
Date: Tue, 15 Sep 2026 08:00:00 +0000

--===============7215816408978557903==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

KPN maintenance notification. See attached spreadsheet.
--===============7215816408978557903==
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="kpn1.xlsx"

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
LnhtbFBLBQYAAAAACQAJAD4CAABCEgAAAAA=

--===============7215816408978557903==--
Binary file added tests/unit/data/kpn/kpn1.xlsx
Binary file not shown.
25 changes: 25 additions & 0 deletions tests/unit/data/kpn/kpn1_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[
{
"account": "Dummy Corp A",
"circuits": [
{
"circuit_id": "A000001",
"impact": "OUTAGE"
},
{
"circuit_id": "B000002",
"impact": "OUTAGE"
}
],
"end": 1789452000,
"maintenance_id": "CT00000000001",
"organizer": "gwc-noreply@kpn.com",
"provider": "kpn",
"sequence": 1,
"stamp": 1789459200,
"start": 1789437600,
"status": "CONFIRMED",
"summary": "KPN maintenance CT00000000001 (DUMMY-LINE-01)",
"uid": "0"
}
]
20 changes: 20 additions & 0 deletions tests/unit/data/kpn/kpn1_xlsx_parser_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[
{
"account": "Dummy Corp A",
"circuits": [
{
"circuit_id": "A000001",
"impact": "OUTAGE"
},
{
"circuit_id": "B000002",
"impact": "OUTAGE"
}
],
"end": 1789452000,
"maintenance_id": "CT00000000001",
"start": 1789437600,
"status": "CONFIRMED",
"summary": "KPN maintenance CT00000000001 (DUMMY-LINE-01)"
}
]
Loading
Loading