-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlexnode_engine.py
More file actions
173 lines (154 loc) · 7.66 KB
/
Copy pathlexnode_engine.py
File metadata and controls
173 lines (154 loc) · 7.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import xml.etree.ElementTree as ET
import re
import calendar
from datetime import datetime, timedelta
class LexNodeEngine:
NS = {'g': 'http://www.gexf.net/1.2draft'}
ATTR = {
'node_type': '0',
'color': '2',
'bron': '10',
'toelichting': '13',
'definitie': '14',
}
ROUTE = [
"begrippen/dagtekening-aanslagbiljet",
"begrippen/zes-weken",
"begrippen/zes-weken-na-dagtekening-aanslagbiljet",
"regels/AR-9-1",
"begrippen/invorderbaarheid",
]
def __init__(self, gexf_path: str):
self.tree = ET.parse(gexf_path)
self.root = self.tree.getroot()
def get_node_attrs(self, node_id: str) -> dict:
node = self.root.find(f".//g:node[@id='{node_id}']", self.NS)
if node is None:
return {}
return {a.get('for'): a.get('value') for a in node.findall(".//g:attvalue", self.NS)}
def get_graph_data(self) -> dict:
nodes, edges = [], []
for node in self.root.findall(".//g:node", self.NS):
attrs = {a.get('for'): a.get('value') for a in node.findall(".//g:attvalue", self.NS)}
nodes.append({
"id": node.get('id'),
"label": node.get('label'),
"color": attrs.get(self.ATTR['color'], "#97C2FC"),
"title": attrs.get(self.ATTR['definitie'], ""),
"node_type": attrs.get(self.ATTR['node_type'], "onbekend"),
})
for edge in self.root.findall(".//g:edge", self.NS):
edges.append({"from": edge.get('source'), "to": edge.get('target'), "arrows": "to"})
return {"nodes": nodes, "edges": edges}
def get_route_nodes(self) -> list:
result = []
for node_id in self.ROUTE:
raw = self.get_node_attrs(node_id)
node_el = self.root.find(f".//g:node[@id='{node_id}']", self.NS)
result.append({
"id": node_id,
"label": node_el.get("label") if node_el is not None else node_id,
"node_type": raw.get("0", ""),
"jas_klasse": raw.get("1", ""),
"begripsnaam": raw.get("8", ""),
"markering": raw.get("9", ""),
"bron": raw.get("10", ""),
"bronnen": raw.get("11", ""),
"interpretatie": raw.get("12", ""),
"toelichting": raw.get("13", ""),
"definitie": raw.get("14", ""),
"soort": raw.get("15", ""),
"herkomst": raw.get("16", ""),
"afleidingsregels": raw.get("23", ""),
"regel_id": raw.get("24", ""),
"naam": raw.get("25", ""),
"operators": raw.get("26", ""),
})
return result
def get_full_justification(self, node_id: str) -> dict:
attrs = self.get_node_attrs(node_id)
definitie = attrs.get(self.ATTR['definitie'], "")
toelichting = attrs.get(self.ATTR['toelichting'], "")
pattern = r'(?P<waarde>zes|6|(\d+))\s+(?:\w+\s+)?(?P<eenheid>weken|dagen)'
match = re.search(pattern, definitie.lower())
dagen = 42
if match:
w = match.group('waarde')
n = 6 if w == 'zes' else int(w)
dagen = n * 7 if match.group('eenheid') == 'weken' else n
atw_uitgesloten = "algemene termijnenwet niet van toepassing" in toelichting.lower()
return {
"termijn_dagen": dagen,
"definitie": definitie,
"interpretatie": toelichting,
"wetsartikel": attrs.get(self.ATTR['bron'], "Art. 9 IW 1990"),
"atw_status": "Uitgesloten (Art. 9 lid 10 IW 1990)" if atw_uitgesloten else "Toepasbaar",
}
def check_invorderbaarheid(self, dagtekening: datetime, peildatum: datetime,
aanslagtype: str = "definitief",
afwijkend_boekjaar: bool = False,
boekjaar_eindmaand: int = 12,
vaststellingsjaar: bool = True) -> dict:
details = self.get_full_justification("begrippen/zes-weken")
basis_dagen = details["termijn_dagen"]
if aanslagtype.startswith("voorlopig") and not vaststellingsjaar:
return {
"invorderbaar": False,
"deadline": dagtekening,
"details": details,
"bron": "Art. 9 lid 7 IW 1990 (buiten vaststellingsjaar)",
"fout": "Dagtekening valt buiten het vaststellingsjaar",
}
if aanslagtype.startswith("voorlopig") and vaststellingsjaar:
# Art 9 lid 5: Meerdere termijnen
maand = dagtekening.month
eind = boekjaar_eindmaand if afwijkend_boekjaar else 12
resterende_maanden = (eind - maand + 12) % 12 if afwijkend_boekjaar else 12 - maand
if resterende_maanden > 1:
termijnen = []
_, last_day_month = calendar.monthrange(dagtekening.year, dagtekening.month)
is_laatste_dag = dagtekening.day == last_day_month
for i in range(1, resterende_maanden + 1):
raw_maand = dagtekening.month + i
doel_jaar = dagtekening.year + (raw_maand - 1) // 12
doel_maand = ((raw_maand - 1) % 12) + 1
_, last_day_doel = calendar.monthrange(doel_jaar, doel_maand)
dag = last_day_doel if is_laatste_dag else min(dagtekening.day, last_day_doel)
termijnen.append(datetime(doel_jaar, doel_maand, dag))
# LI 9.1 Correctie op LAATSTE termijn
if afwijkend_boekjaar:
_, last_day = calendar.monthrange(termijnen[-1].year, termijnen[-1].month)
termijnen[-1] = termijnen[-1].replace(day=last_day)
elif dagtekening.month <= 11:
einde_jaar = datetime(dagtekening.year, 12, 31)
if termijnen[-1] < einde_jaar:
termijnen[-1] = einde_jaar
return {
"invorderbaar": peildatum >= termijnen[0],
"deadline": termijnen[0],
"termijnen": termijnen,
"details": details,
"bron": "Art. 9 lid 5 IW 1990" + (" (Corr. § 9.1 LI 2008)" if afwijkend_boekjaar or dagtekening.month <= 11 else "")
}
# Fallback naar lid 1 als resterende_maanden <= 1
# (wordt hieronder afgehandeld door de standaard 6 weken + LI 9.1 correctie)
# Standaard 6 weken (Art 9 lid 1) of Fallback van Lid 5
deadline = dagtekening + timedelta(days=basis_dagen)
bron = details["wetsartikel"]
# LI 9.1 Correctie voor enige/laatste termijn
if aanslagtype.startswith("voorlopig"):
if afwijkend_boekjaar:
_, last_day = calendar.monthrange(deadline.year, deadline.month)
deadline = deadline.replace(day=last_day)
bron = "§ 9.1 LI 2008 (Afwijkend boekjaar)"
elif dagtekening.month <= 11:
einde_jaar = datetime(dagtekening.year, 12, 31)
if deadline < einde_jaar:
deadline = einde_jaar
bron = "§ 9.1 LI 2008 (31 december regel)"
return {
"invorderbaar": peildatum >= deadline,
"deadline": deadline,
"details": details,
"bron": bron
}