@eventconnectors/ndtrc_model 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +14 -0
- package/CLAUDE.md +54 -0
- package/package.json +3 -3
- package/src/__tests__/model.test.js +327 -0
- package/src/model/ndtrc/Calendar.js +6 -0
- package/src/model/ndtrc/Categories.js +49 -144
- package/src/model/ndtrc/ContactInfo.js +3 -1
- package/src/model/ndtrc/Location.js +2 -1
- package/src/model/ndtrc/TRCItem.js +5 -2
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm test)",
|
|
5
|
+
"Bash(node -e:*)",
|
|
6
|
+
"WebFetch(domain:github.com)",
|
|
7
|
+
"WebFetch(domain:api.github.com)",
|
|
8
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
9
|
+
"Bash(npm publish:*)"
|
|
10
|
+
],
|
|
11
|
+
"deny": [],
|
|
12
|
+
"ask": []
|
|
13
|
+
}
|
|
14
|
+
}
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is the `@eventconnectors/ndtrc_model` npm package - a Node.js data model library for NDTRC (Nationale Databank Toerisme en Recreatie Centraal), the Dutch national tourism and recreation database. It provides JavaScript classes for representing tourism events, locations, and related entities.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
- **Run tests**: `npm test` (uses Jest)
|
|
12
|
+
- **Install dependencies**: `npm install`
|
|
13
|
+
|
|
14
|
+
## Architecture
|
|
15
|
+
|
|
16
|
+
### Entry Point
|
|
17
|
+
- `index.js` - Exports all model classes from a single entry point
|
|
18
|
+
|
|
19
|
+
### Model Classes (`src/model/`)
|
|
20
|
+
|
|
21
|
+
**Core Entry Types:**
|
|
22
|
+
- `FetchedEntry` - Raw data fetched from external sources (with `ExternalLocationInfo`)
|
|
23
|
+
- `ConvertedEntry` - Processed entry containing a validated `TRCItem`
|
|
24
|
+
|
|
25
|
+
**NDTRC Models (`src/model/ndtrc/`):**
|
|
26
|
+
- `TRCItem` - Main entity representing an event/location with static enums `WFStatus` and `EntityType`
|
|
27
|
+
- `TRCItemDetail` - Multilingual details (title, descriptions) per language
|
|
28
|
+
- `Calendar` - Complex scheduling with single dates, pattern dates, and exception handling
|
|
29
|
+
- `Location` - Location info with address and optional `LocationItem` reference
|
|
30
|
+
- `TRCItemCategories` - Category assignments for items
|
|
31
|
+
|
|
32
|
+
**Supporting Models:**
|
|
33
|
+
- `Address`, `ContactInfo`, `GISCoordinate` - Location/contact data
|
|
34
|
+
- `PriceElement`, `ExtraPriceInformation` - Pricing information
|
|
35
|
+
- `File`, `Performer`, `Promotion` - Media and marketing
|
|
36
|
+
- `Translations`, `RouteInfo`, `SubItemGroup`, `TRCItemGroup`, `TRCItemRelation`
|
|
37
|
+
|
|
38
|
+
### Utilities (`src/util/`)
|
|
39
|
+
- `CategoryMap` - Maps external category names to NDTRC category IDs with associated tags
|
|
40
|
+
- `Categories` - NDTRC category ID lookup table
|
|
41
|
+
|
|
42
|
+
### Key Patterns
|
|
43
|
+
|
|
44
|
+
1. **Constructor-based initialization**: All model classes use destructured object parameters with defaults
|
|
45
|
+
2. **Nested class instantiation**: Parent classes automatically instantiate child classes (e.g., `TRCItem` creates `Calendar`, `Location` instances)
|
|
46
|
+
3. **Moment.js dates**: Date fields use `moment` for parsing and manipulation
|
|
47
|
+
4. **Static enums**: Enums are defined as static properties on classes (e.g., `TRCItem.WFStatus`, `Calendar.CalendarType`)
|
|
48
|
+
|
|
49
|
+
### Entity Types
|
|
50
|
+
- `EVENEMENT` - Event
|
|
51
|
+
- `LOCATIE` - Location/venue
|
|
52
|
+
- `EVENEMENTGROEP` - Event group
|
|
53
|
+
- `PLAATSREGIO` - Place/region
|
|
54
|
+
- `ROUTE` - Route
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventconnectors/ndtrc_model",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "jest"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"dayjs": "^1.11.
|
|
9
|
+
"dayjs": "^1.11.19",
|
|
10
10
|
"moment": "^2.30.1",
|
|
11
11
|
"xmlbuilder": "^15.1.1"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"jest": "^
|
|
14
|
+
"jest": "^30.2.0"
|
|
15
15
|
},
|
|
16
16
|
"private": false,
|
|
17
17
|
"author": "wwwappz",
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
const {
|
|
2
|
+
TRCItem,
|
|
3
|
+
FetchedEntry: FetchedEntryModule,
|
|
4
|
+
ExternalLocationInfo,
|
|
5
|
+
ConvertedEntry,
|
|
6
|
+
Location,
|
|
7
|
+
Calendar: CalendarModule,
|
|
8
|
+
Contactinfo,
|
|
9
|
+
File,
|
|
10
|
+
PriceElement,
|
|
11
|
+
Performer,
|
|
12
|
+
TRCItemDetail,
|
|
13
|
+
Address,
|
|
14
|
+
GISCoordinate,
|
|
15
|
+
Categories,
|
|
16
|
+
CategoryMap,
|
|
17
|
+
} = require("../../index.js");
|
|
18
|
+
|
|
19
|
+
const { FetchedEntry } = FetchedEntryModule;
|
|
20
|
+
const { Calendar } = CalendarModule;
|
|
21
|
+
|
|
22
|
+
describe("TRCItem", () => {
|
|
23
|
+
test("should create with default values", () => {
|
|
24
|
+
const item = new TRCItem();
|
|
25
|
+
expect(item.trcid).toBe("");
|
|
26
|
+
expect(item.published).toBe(false);
|
|
27
|
+
expect(item.deleted).toBe(false);
|
|
28
|
+
expect(item.forceOverwrite).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("should create with custom values", () => {
|
|
32
|
+
const item = new TRCItem({
|
|
33
|
+
trcid: "test123",
|
|
34
|
+
published: true,
|
|
35
|
+
forceOverwrite: true,
|
|
36
|
+
entitytype: TRCItem.EntityType.EVENEMENT,
|
|
37
|
+
});
|
|
38
|
+
expect(item.trcid).toBe("test123");
|
|
39
|
+
expect(item.published).toBe(true);
|
|
40
|
+
expect(item.forceOverwrite).toBe(true);
|
|
41
|
+
expect(item.entitytype).toBe("EVENEMENT");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("should have all EntityType values", () => {
|
|
45
|
+
expect(TRCItem.EntityType.EVENEMENT).toBe("EVENEMENT");
|
|
46
|
+
expect(TRCItem.EntityType.LOCATIE).toBe("LOCATIE");
|
|
47
|
+
expect(TRCItem.EntityType.EVENEMENTGROEP).toBe("EVENEMENTGROEP");
|
|
48
|
+
expect(TRCItem.EntityType.PLAATSREGIO).toBe("PLAATSREGIO");
|
|
49
|
+
expect(TRCItem.EntityType.ROUTE).toBe("ROUTE");
|
|
50
|
+
expect(TRCItem.EntityType.VENUE).toBe("VENUE");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("should have all WFStatus values", () => {
|
|
54
|
+
expect(TRCItem.WFStatus.DRAFT).toBe("draft");
|
|
55
|
+
expect(TRCItem.WFStatus.READY_FOR_VALIDATION).toBe("readyforvalidation");
|
|
56
|
+
expect(TRCItem.WFStatus.APPROVED).toBe("approved");
|
|
57
|
+
expect(TRCItem.WFStatus.REJECTED).toBe("rejected");
|
|
58
|
+
expect(TRCItem.WFStatus.DELETED).toBe("deleted");
|
|
59
|
+
expect(TRCItem.WFStatus.ARCHIVED).toBe("archived");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("should create nested objects", () => {
|
|
63
|
+
const item = new TRCItem({
|
|
64
|
+
trcid: "test",
|
|
65
|
+
location: { label: "Test Location" },
|
|
66
|
+
contactinfo: { label: "Test Contact" },
|
|
67
|
+
performers: [{ label: "Artist 1" }],
|
|
68
|
+
files: [{ filename: "image.jpg" }],
|
|
69
|
+
trcItemDetails: [{ lang: "nl", title: "Test" }],
|
|
70
|
+
});
|
|
71
|
+
expect(item.location).toBeInstanceOf(Location);
|
|
72
|
+
expect(item.contactinfo).toBeInstanceOf(Contactinfo);
|
|
73
|
+
expect(item.performers).toHaveLength(1);
|
|
74
|
+
expect(item.files).toHaveLength(1);
|
|
75
|
+
expect(item.trcItemDetails).toHaveLength(1);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("Location", () => {
|
|
80
|
+
test("should create with default values", () => {
|
|
81
|
+
const loc = new Location();
|
|
82
|
+
expect(loc.label).toBe("");
|
|
83
|
+
expect(loc.address).toBeNull();
|
|
84
|
+
expect(loc.locationItem).toBeNull();
|
|
85
|
+
expect(loc.venueItem).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("should create with locationItem and venueItem", () => {
|
|
89
|
+
const loc = new Location({
|
|
90
|
+
label: "Test",
|
|
91
|
+
locationItem: { id: "1", trcid: "loc1", text: "Location" },
|
|
92
|
+
venueItem: { id: "2", trcid: "venue1", text: "Venue" },
|
|
93
|
+
});
|
|
94
|
+
expect(loc.locationItem.id).toBe("1");
|
|
95
|
+
expect(loc.locationItem.trcid).toBe("loc1");
|
|
96
|
+
expect(loc.venueItem.id).toBe("2");
|
|
97
|
+
expect(loc.venueItem.trcid).toBe("venue1");
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("should create address", () => {
|
|
101
|
+
const loc = new Location({
|
|
102
|
+
address: { city: "Amsterdam", street: "Damrak" },
|
|
103
|
+
});
|
|
104
|
+
expect(loc.address).toBeInstanceOf(Address);
|
|
105
|
+
expect(loc.address.city).toBe("Amsterdam");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("Calendar", () => {
|
|
110
|
+
test("should create with default values", () => {
|
|
111
|
+
const cal = new Calendar();
|
|
112
|
+
expect(cal.singleDates).toEqual([]);
|
|
113
|
+
expect(cal.patternDates).toEqual([]);
|
|
114
|
+
expect(cal.excludeholidays).toBe(false);
|
|
115
|
+
expect(cal.cancelled).toBe(false);
|
|
116
|
+
expect(cal.soldout).toBe(false);
|
|
117
|
+
expect(cal.onrequest).toBe(false);
|
|
118
|
+
expect(cal.alwaysopen).toBe(false);
|
|
119
|
+
expect(cal.comment).toBeNull();
|
|
120
|
+
expect(cal.calendarType).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("should have CalendarType enum", () => {
|
|
124
|
+
expect(Calendar.CalendarType.NONE).toBe("NONE");
|
|
125
|
+
expect(Calendar.CalendarType.ALWAYSOPEN).toBe("ALWAYSOPEN");
|
|
126
|
+
expect(Calendar.CalendarType.ONREQUEST).toBe("ONREQUEST");
|
|
127
|
+
expect(Calendar.CalendarType.OPENINGTIMES).toBe("OPENINGTIMES");
|
|
128
|
+
expect(Calendar.CalendarType.PATTERNDATES).toBe("PATTERNDATES");
|
|
129
|
+
expect(Calendar.CalendarType.SINGLEDATES).toBe("SINGLEDATES");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("should determine ALWAYSOPEN calendar type", () => {
|
|
133
|
+
const cal = new Calendar();
|
|
134
|
+
cal.alwaysopen = true;
|
|
135
|
+
cal.determineCalendarType();
|
|
136
|
+
expect(cal.calendarType).toBe("ALWAYSOPEN");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("should determine ONREQUEST calendar type", () => {
|
|
140
|
+
const cal = new Calendar();
|
|
141
|
+
cal.onrequest = true;
|
|
142
|
+
cal.determineCalendarType();
|
|
143
|
+
expect(cal.calendarType).toBe("ONREQUEST");
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("Contactinfo", () => {
|
|
148
|
+
test("should create with default values", () => {
|
|
149
|
+
const contact = new Contactinfo();
|
|
150
|
+
expect(contact.label).toBe("");
|
|
151
|
+
expect(contact.mails).toEqual([]);
|
|
152
|
+
expect(contact.phones).toEqual([]);
|
|
153
|
+
expect(contact.urls).toEqual([]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("should create nested Mail objects", () => {
|
|
157
|
+
const contact = new Contactinfo({
|
|
158
|
+
mails: [{ email: "test@example.com" }],
|
|
159
|
+
});
|
|
160
|
+
expect(contact.mails).toHaveLength(1);
|
|
161
|
+
expect(contact.mails[0].email).toBe("test@example.com");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("should create nested Url objects", () => {
|
|
165
|
+
const contact = new Contactinfo({
|
|
166
|
+
urls: [{ url: "https://example.com", urlServiceType: "general" }],
|
|
167
|
+
});
|
|
168
|
+
expect(contact.urls).toHaveLength(1);
|
|
169
|
+
expect(contact.urls[0].url).toBe("https://example.com");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("should have all URLServiceType values", () => {
|
|
173
|
+
const types = Contactinfo.Url.URLServiceType;
|
|
174
|
+
expect(types.general).toBe("general");
|
|
175
|
+
expect(types.booking).toBe("booking");
|
|
176
|
+
expect(types.review).toBe("review");
|
|
177
|
+
expect(types.video).toBe("video");
|
|
178
|
+
expect(types.webshop).toBe("webshop");
|
|
179
|
+
expect(types.socialmedia).toBe("socialmedia");
|
|
180
|
+
expect(types.lastminute).toBe("lastminute");
|
|
181
|
+
expect(types.virtualtour).toBe("virtualtour");
|
|
182
|
+
expect(types.dmo).toBe("dmo");
|
|
183
|
+
expect(types.sustainability).toBe("sustainability");
|
|
184
|
+
expect(types.venuefinder).toBe("venuefinder");
|
|
185
|
+
expect(types.travelbase).toBe("travelbase");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
describe("File", () => {
|
|
190
|
+
test("should create with default values", () => {
|
|
191
|
+
const file = new File();
|
|
192
|
+
expect(file.trcid).toBe("");
|
|
193
|
+
expect(file.main).toBe(false);
|
|
194
|
+
expect(file.filename).toBe("");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("should have FileType enum", () => {
|
|
198
|
+
expect(File.FileType.jpeg).toBe("jpeg");
|
|
199
|
+
expect(File.FileType.youtube).toBe("youtube");
|
|
200
|
+
expect(File.FileType.vimeo).toBe("vimeo");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("should have MediaType enum", () => {
|
|
204
|
+
expect(File.MediaType.photo).toBe("photo");
|
|
205
|
+
expect(File.MediaType.video).toBe("video");
|
|
206
|
+
expect(File.MediaType.poster).toBe("poster");
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("should normalize YouTube URL", () => {
|
|
210
|
+
const shortUrl = "https://youtu.be/dQw4w9WgXcQ";
|
|
211
|
+
const normalized = File.normalizeYouTubeURL(shortUrl);
|
|
212
|
+
expect(normalized).toBe("https://www.youtube.com/watch?v=dQw4w9WgXcQ");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
test("should extract YouTube video ID", () => {
|
|
216
|
+
const url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ";
|
|
217
|
+
const videoId = File.youtubeVideoID(url);
|
|
218
|
+
expect(videoId).toBe("dQw4w9WgXcQ");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
describe("PriceElement", () => {
|
|
223
|
+
test("should create with default values", () => {
|
|
224
|
+
const price = new PriceElement();
|
|
225
|
+
expect(price.freeentrance).toBe(false);
|
|
226
|
+
expect(price.priceValue).toBeNull();
|
|
227
|
+
expect(price.comments).toEqual([]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("should create with price value", () => {
|
|
231
|
+
const price = new PriceElement({
|
|
232
|
+
freeentrance: false,
|
|
233
|
+
priceValue: { from: 10.0, until: 25.0 },
|
|
234
|
+
});
|
|
235
|
+
expect(price.priceValue.from).toBe(10.0);
|
|
236
|
+
expect(price.priceValue.until).toBe(25.0);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("should have PriceDescriptionValue enum", () => {
|
|
240
|
+
const values = PriceElement.Description.PriceDescriptionValue;
|
|
241
|
+
expect(values.Adults).toBe("Adults");
|
|
242
|
+
expect(values.Children).toBe("Children");
|
|
243
|
+
expect(values.Groups).toBe("Groups");
|
|
244
|
+
expect(values.CJP).toBe("CJP");
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe("FetchedEntry", () => {
|
|
249
|
+
test("should create with default values", () => {
|
|
250
|
+
const entry = new FetchedEntry();
|
|
251
|
+
expect(entry.feed).toBe("");
|
|
252
|
+
expect(entry.sourceId).toBe("");
|
|
253
|
+
expect(entry.externalId).toBe("");
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
test("should create with custom values", () => {
|
|
257
|
+
const entry = new FetchedEntry({
|
|
258
|
+
feed: "test-feed",
|
|
259
|
+
sourceId: "source-123",
|
|
260
|
+
externalId: "ext-456",
|
|
261
|
+
data: { key: "value" },
|
|
262
|
+
});
|
|
263
|
+
expect(entry.feed).toBe("test-feed");
|
|
264
|
+
expect(entry.sourceId).toBe("source-123");
|
|
265
|
+
expect(entry.data.key).toBe("value");
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("ConvertedEntry", () => {
|
|
270
|
+
test("should create with default values", () => {
|
|
271
|
+
const entry = new ConvertedEntry();
|
|
272
|
+
expect(entry.label).toBe("");
|
|
273
|
+
expect(entry.externalId).toBe("");
|
|
274
|
+
expect(entry.trcItem).toBeNull();
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test("should accept TRCItem instance", () => {
|
|
278
|
+
const trcItem = new TRCItem({ trcid: "test" });
|
|
279
|
+
const entry = new ConvertedEntry({
|
|
280
|
+
label: "Test Entry",
|
|
281
|
+
trcItem: trcItem,
|
|
282
|
+
});
|
|
283
|
+
expect(entry.trcItem).toBe(trcItem);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
describe("Address", () => {
|
|
288
|
+
test("should create with default values", () => {
|
|
289
|
+
const address = new Address();
|
|
290
|
+
expect(address.city).toBe("");
|
|
291
|
+
expect(address.country).toBe("NL");
|
|
292
|
+
expect(address.main).toBe(false);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test("should normalize zipcode", () => {
|
|
296
|
+
const address = new Address({ zipcode: "1234ab" });
|
|
297
|
+
address.normaliseAdresItems();
|
|
298
|
+
expect(address.zipcode).toBe("1234 AB");
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test("should check isEmpty", () => {
|
|
302
|
+
const emptyAddress = new Address();
|
|
303
|
+
const filledAddress = new Address({ city: "Amsterdam" });
|
|
304
|
+
expect(emptyAddress.isEmpty()).toBe(true);
|
|
305
|
+
expect(filledAddress.isEmpty()).toBe(false);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
describe("Categories", () => {
|
|
310
|
+
test("should have category mappings", () => {
|
|
311
|
+
expect(Categories.categories).toBeDefined();
|
|
312
|
+
expect(Categories.categories["Beurs"]).toBe("2.3.1");
|
|
313
|
+
expect(Categories.categories["Film"]).toBe("2.5.2");
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe("CategoryMap", () => {
|
|
318
|
+
test("should have categoryMap", () => {
|
|
319
|
+
expect(CategoryMap.CategoryMap.categoryMap).toBeDefined();
|
|
320
|
+
expect(CategoryMap.CategoryMap.categoryMap["concert"].catId).toBe("2.6.5");
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("should have categoryType", () => {
|
|
324
|
+
expect(CategoryMap.CategoryMap.categoryType).toBeDefined();
|
|
325
|
+
expect(CategoryMap.CategoryMap.categoryType["Cabaret"]).toBe("2.9.1");
|
|
326
|
+
});
|
|
327
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Calendar.js
|
|
2
2
|
|
|
3
3
|
const moment = require("moment");
|
|
4
|
+
const Contactinfo = require("./ContactInfo");
|
|
4
5
|
|
|
5
6
|
class Calendar {
|
|
6
7
|
constructor() {
|
|
@@ -15,6 +16,10 @@ class Calendar {
|
|
|
15
16
|
this.excludeholidays = false;
|
|
16
17
|
this.cancelled = false;
|
|
17
18
|
this.soldout = false;
|
|
19
|
+
this.onrequest = false;
|
|
20
|
+
this.alwaysopen = false;
|
|
21
|
+
this.comment = null;
|
|
22
|
+
this.calendarType = null;
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
static CalendarType = {
|
|
@@ -172,6 +177,7 @@ class When {
|
|
|
172
177
|
this.status = status;
|
|
173
178
|
this.statustranslations = [];
|
|
174
179
|
this.extrainformations = [];
|
|
180
|
+
this.url = Contactinfo.Url ? new Contactinfo.Url() : [];
|
|
175
181
|
}
|
|
176
182
|
|
|
177
183
|
equals(other) {
|
|
@@ -1,149 +1,54 @@
|
|
|
1
1
|
// FeedData.js
|
|
2
2
|
|
|
3
3
|
const categories = {
|
|
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
|
-
"congres- en vergaderaccommodatie": "1.1.1",
|
|
54
|
-
"campings": "1.2",
|
|
55
|
-
"camping": "1.2.1",
|
|
56
|
-
"logies": "1.3",
|
|
57
|
-
"bed and breakfast": "1.3.1",
|
|
58
|
-
"groepsaccommodatie": "1.3.2",
|
|
59
|
-
"hostel": "1.3.3",
|
|
60
|
-
"hotel": "1.3.4",
|
|
61
|
-
"stacaravan": "1.4.7",
|
|
62
|
-
"attracties": "2.1",
|
|
63
|
-
"attractie": "2.1.1",
|
|
64
|
-
"galerie": "2.2.4",
|
|
65
|
-
"museum": "2.1.6",
|
|
66
|
-
"rondvaart": "2.1.8",
|
|
67
|
-
"wellness": "2.1.2",
|
|
68
|
-
"winkelcentrum": "2.1.12",
|
|
69
|
-
"bezienswaardigheden": "2.2",
|
|
70
|
-
"architectuur": "2.2.1",
|
|
71
|
-
"kerk": "2.2.7",
|
|
72
|
-
"monument": "2.2.9",
|
|
73
|
-
"bos": "2.2.18",
|
|
74
|
-
"bezienswaardigheid": "2.2.19",
|
|
75
|
-
"haven": "2.20",
|
|
76
|
-
"bierbrouwerij": "2.2.20",
|
|
77
|
-
"routes": "2.7",
|
|
78
|
-
"fietsroute": "2.7.3",
|
|
79
|
-
"wandelroute": "2.7.9",
|
|
80
|
-
"natuur": "2.10",
|
|
81
|
-
"natuurgebied": "2.2.10",
|
|
82
|
-
"recreatiegebied": "2.1.7",
|
|
83
|
-
"park/tuin": "2.2.11",
|
|
84
|
-
"strand": "2.2.12",
|
|
85
|
-
"groepsarrangementen en activiteiten": "2.11",
|
|
86
|
-
"tocht": "2.11.4",
|
|
87
|
-
"actief en sportief": "2.11.10",
|
|
88
|
-
"kunst en cultuur": "2.11.11",
|
|
89
|
-
"restaurants": "3.1",
|
|
90
|
-
"restaurant": "3.1.1",
|
|
91
|
-
"strandpaviljoen": "3.1.5",
|
|
92
|
-
"visrestaurant": "3.1.6",
|
|
93
|
-
"kleine horeca": "3.2",
|
|
94
|
-
"ijssalon": "3.2.3",
|
|
95
|
-
"brasserie/lunchroom": "3.2.6",
|
|
96
|
-
"koffiebar": "3.2.7",
|
|
97
|
-
"viswinkel": "3.2.8",
|
|
98
|
-
"uitgaan": "3.3",
|
|
99
|
-
"café of bar": "3.3.1",
|
|
100
|
-
"uitgaanscentrum": "3.3.2",
|
|
101
|
-
"bioscoop": "3.3.3",
|
|
102
|
-
"filmtheater": "3.3.4",
|
|
103
|
-
"muziekpodium": "3.3.5",
|
|
104
|
-
"theaterpodium": "3.3.6",
|
|
105
|
-
"buiten locatie": "3.3.7",
|
|
106
|
-
"algemene voorzieningen ter plaatse": "4.1",
|
|
107
|
-
"transferium": "4.1.7",
|
|
108
|
-
"parkeergarage": "4.1.11",
|
|
109
|
-
"bedrijven ter plaatse": "4.2",
|
|
110
|
-
"beursgebouw": "4.2.4",
|
|
111
|
-
"bibliotheek": "4.2.12",
|
|
112
|
-
"touroperator": "4.2.17",
|
|
113
|
-
"evenementenbureau": "4.2.18",
|
|
114
|
-
"conferentie services": "4.2.21",
|
|
115
|
-
"gids": "4.2.23",
|
|
116
|
-
"vvv": "4.5.1",
|
|
117
|
-
"verhuurbedrijven": "4.3",
|
|
118
|
-
"fietsverhuurbedrijf": "4.3.4",
|
|
119
|
-
"bootverhuurbedrijf": "4.3.2",
|
|
120
|
-
"autoverhuurbedrijf": "4.3.1",
|
|
121
|
-
"partylocatie of zaalverhuur": "4.3.5",
|
|
122
|
-
"bijzonder verhuur": "4.3.9",
|
|
123
|
-
"bus en touringcarverhuur": "4.3.15",
|
|
124
|
-
"winkels": "4.6",
|
|
125
|
-
"huis- en tuin": "4.6.5",
|
|
126
|
-
"voeding/drank": "4.6.7",
|
|
127
|
-
"cadeau": "4.6.8",
|
|
128
|
-
"sport/outdoor/auto": "4.6.9",
|
|
129
|
-
"overige winkels": "4.6.10",
|
|
130
|
-
"vintage": "4.6.11",
|
|
131
|
-
"kinderen": "4.6.12",
|
|
132
|
-
"sieraden/juwelier": "4.6.15",
|
|
133
|
-
"schoenen": "4.6.16",
|
|
134
|
-
"boeken": "4.6.19",
|
|
135
|
-
"speelgoed": "4.6.20",
|
|
136
|
-
"kunst/antiek": "4.6.22",
|
|
137
|
-
"warenhuis": "4.6.25",
|
|
138
|
-
"kleding": "4.6.26",
|
|
139
|
-
"lichaamsverzorging/gezondheid": "4.6.27",
|
|
140
|
-
"hobby/vrije tijd": "4.6.29",
|
|
141
|
-
"vervoer": "4.6.31",
|
|
142
|
-
"cultuur- en sportverenigingen": "4.8",
|
|
143
|
-
"culturele organisaties": "4.8.2",
|
|
144
|
-
"functie": "8.1",
|
|
145
|
-
"onderwijs": "8.1.1",
|
|
146
|
-
"dienstverleners": "8.1.2"
|
|
147
|
-
};
|
|
4
|
+
"evenementen": "2.3",
|
|
5
|
+
"Beurs": "2.3.1",
|
|
6
|
+
"Braderie": "2.3.2",
|
|
7
|
+
"Congres": "2.3.4",
|
|
8
|
+
"Corso of Optocht": "2.3.5",
|
|
9
|
+
"Culinair": "2.3.6",
|
|
10
|
+
"Excursie": "2.7.2",
|
|
11
|
+
"Kermis": "2.3.8",
|
|
12
|
+
"Lezing/Debat": "2.3.9",
|
|
13
|
+
"Markt": "2.3.10",
|
|
14
|
+
"Open Dag": "2.3.11",
|
|
15
|
+
"Rondleiding": "2.3.12",
|
|
16
|
+
"Sportevenement": "2.3.13",
|
|
17
|
+
"Workshop": "2.3.15",
|
|
18
|
+
"Wandeltocht": "2.3.17",
|
|
19
|
+
"Varia": "2.3.18",
|
|
20
|
+
"Grootstedelijk evenement": "2.3.23",
|
|
21
|
+
"Rommelmarkt": "2.4.6",
|
|
22
|
+
"Film": "2.5.2",
|
|
23
|
+
"Jeugd": "2.3.25",
|
|
24
|
+
"Wijkfeest": "2.3.26",
|
|
25
|
+
"Speeltuin": "2.3.27",
|
|
26
|
+
"Festivals": "2.4",
|
|
27
|
+
"Cultureel festival": "2.4.1",
|
|
28
|
+
"Filmfestival": "2.4.2",
|
|
29
|
+
"Muziekfestival": "2.4.3",
|
|
30
|
+
"Theaterfestival": "2.4.4",
|
|
31
|
+
"Jeugdfestival": "2.4.5",
|
|
32
|
+
"Festival": "2.4.7",
|
|
33
|
+
"Dancefestival": "2.4.8",
|
|
34
|
+
"Muziek": "2.6",
|
|
35
|
+
"Dance": "2.6.1",
|
|
36
|
+
"Jazz of Wereldmuziek": "2.6.2",
|
|
37
|
+
"Klassieke muziek": "2.6.3",
|
|
38
|
+
"Lichte muziek": "2.6.4",
|
|
39
|
+
"Pop en Rock": "2.6.5",
|
|
40
|
+
"R&B en Soul": "2.6.6",
|
|
41
|
+
"Muziek overig": "2.6.8",
|
|
42
|
+
"Gezelschap/orkest": "2.6.9",
|
|
43
|
+
"Theater": "2.9",
|
|
44
|
+
"Cabaret": "2.9.1",
|
|
45
|
+
"Dans en Ballet": "2.9.2",
|
|
46
|
+
"Jeugdtheater": "2.9.3",
|
|
47
|
+
"Musical of Show": "2.9.4",
|
|
48
|
+
"Opera": "2.9.5",
|
|
49
|
+
"Theater en Toneel": "2.9.6",
|
|
50
|
+
"Tentoonstellingen": "2.12",
|
|
51
|
+
"Tentoonstelling": "2.3.14"
|
|
52
|
+
};
|
|
148
53
|
|
|
149
54
|
module.exports = { categories };
|
|
@@ -170,7 +170,9 @@ Contactinfo.Url.URLServiceType = {
|
|
|
170
170
|
lastminute: 'lastminute',
|
|
171
171
|
virtualtour: 'virtualtour',
|
|
172
172
|
dmo: 'dmo',
|
|
173
|
-
sustainability: 'sustainability'
|
|
173
|
+
sustainability: 'sustainability',
|
|
174
|
+
venuefinder: 'venuefinder',
|
|
175
|
+
travelbase: 'travelbase'
|
|
174
176
|
};
|
|
175
177
|
|
|
176
178
|
/**
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const Address = require('./Address'); // Importeer de Address-klasse
|
|
2
2
|
|
|
3
3
|
class Location {
|
|
4
|
-
constructor({ address = null, label = '', locationItem = null } = {}) {
|
|
4
|
+
constructor({ address = null, label = '', locationItem = null, venueItem = null } = {}) {
|
|
5
5
|
this.address = address ? new Address(address) : null;
|
|
6
6
|
this.label = label;
|
|
7
7
|
this.locationItem = locationItem ? new Location.LocationItem(locationItem) : null;
|
|
8
|
+
this.venueItem = venueItem ? new Location.LocationItem(venueItem) : null;
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -53,7 +53,8 @@ class TRCItem {
|
|
|
53
53
|
extrapriceinformations = [],
|
|
54
54
|
routeInfo = null,
|
|
55
55
|
translations = null,
|
|
56
|
-
promotions = []
|
|
56
|
+
promotions = [],
|
|
57
|
+
forceOverwrite = false
|
|
57
58
|
} = {}) {
|
|
58
59
|
this.trcid = trcid;
|
|
59
60
|
this.creationdate = creationdate ? moment(creationdate) : null;
|
|
@@ -96,6 +97,7 @@ class TRCItem {
|
|
|
96
97
|
this.routeInfo = routeInfo ? new RouteInfo(routeInfo) : null;
|
|
97
98
|
this.translations = translations ? new Translations(translations) : new Translations();
|
|
98
99
|
this.promotions = promotions.map(promotion => new Promotion(promotion));
|
|
100
|
+
this.forceOverwrite = forceOverwrite;
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
|
|
@@ -113,7 +115,8 @@ TRCItem.EntityType = {
|
|
|
113
115
|
LOCATIE: 'LOCATIE',
|
|
114
116
|
EVENEMENTGROEP: 'EVENEMENTGROEP',
|
|
115
117
|
PLAATSREGIO: 'PLAATSREGIO',
|
|
116
|
-
ROUTE: 'ROUTE'
|
|
118
|
+
ROUTE: 'ROUTE',
|
|
119
|
+
VENUE: 'VENUE'
|
|
117
120
|
};
|
|
118
121
|
|
|
119
122
|
TRCItem.Category = class Category {
|