Skip to content

Commit e3e2540

Browse files
committed
feat: support custom attributes
1 parent 6915461 commit e3e2540

6 files changed

Lines changed: 136 additions & 0 deletions

File tree

src/Zammad.Client.SystemTextJson/Resources/Group.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Zammad.Client.Resources;
@@ -47,4 +48,13 @@ public class Group
4748

4849
[JsonPropertyName("updated_at")]
4950
public DateTimeOffset? UpdatedAt { get; set; }
51+
52+
/// <summary>
53+
/// Additional properties that are not explicitly defined in this class.
54+
/// </summary>
55+
/// <remarks>
56+
/// This will contain custom attributes configured in the Zammad object manager.
57+
/// </remarks>
58+
[JsonExtensionData]
59+
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
5060
}

src/Zammad.Client.SystemTextJson/Resources/Organization.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Zammad.Client.Resources;
@@ -44,4 +45,13 @@ public class Organization
4445

4546
[JsonPropertyName("updated_at")]
4647
public DateTimeOffset? UpdatedAt { get; set; }
48+
49+
/// <summary>
50+
/// Additional properties that are not explicitly defined in this class.
51+
/// </summary>
52+
/// <remarks>
53+
/// This will contain custom attributes configured in the Zammad object manager.
54+
/// </remarks>
55+
[JsonExtensionData]
56+
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
4757
}

src/Zammad.Client.SystemTextJson/Resources/Ticket.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Zammad.Client.Resources;
@@ -194,4 +195,13 @@ public class Ticket
194195

195196
[JsonPropertyName("create_article_sender")]
196197
public string? CreateArticleSender { get; set; }
198+
199+
/// <summary>
200+
/// Additional properties that are not explicitly defined in this class.
201+
/// </summary>
202+
/// <remarks>
203+
/// This will contain custom attributes configured in the Zammad object manager.
204+
/// </remarks>
205+
[JsonExtensionData]
206+
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
197207
}

src/Zammad.Client.SystemTextJson/Resources/User.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Text.Json;
34
using System.Text.Json.Serialization;
45

56
namespace Zammad.Client.Resources;
@@ -107,4 +108,13 @@ public class User
107108

108109
[JsonPropertyName("updated_at")]
109110
public DateTimeOffset? UpdatedAt { get; set; }
111+
112+
/// <summary>
113+
/// Additional properties that are not explicitly defined in this class.
114+
/// </summary>
115+
/// <remarks>
116+
/// This will contain custom attributes configured in the Zammad object manager.
117+
/// </remarks>
118+
[JsonExtensionData]
119+
public Dictionary<string, JsonElement>? ExtensionData { get; set; }
110120
}

test/Zammad.Client.Tests/Deserialization/DeserializationTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4+
using System.Linq;
45
using System.Runtime.CompilerServices;
56
using System.Text.Json;
67
using System.Threading.Tasks;
@@ -28,11 +29,30 @@ public class DeserializationTests
2829
[Theory]
2930
[InlineData(typeof(Ticket), "ticket.json")]
3031
[InlineData(typeof(Ticket), "ticket1.json")]
32+
[InlineData(typeof(Ticket), "ticketExtended.json")]
3133
[InlineData(typeof(List<Ticket>), "tickets.json")]
3234
public async Task CanDeserialize(Type type, string fileName)
3335
{
3436
var json = await TestFile.ReadStringAsync("Responses", fileName);
3537
var result = JsonSerializer.Deserialize(json, type);
3638
Assert.NotNull(result);
3739
}
40+
41+
[Fact]
42+
public async Task CanDeserializeExtensionData()
43+
{
44+
var json = await TestFile.ReadStringAsync("Responses", "ticketExtended.json");
45+
var result = JsonSerializer.Deserialize<Ticket>(json);
46+
Assert.NotNull(result);
47+
Assert.NotNull(result.ExtensionData);
48+
Assert.Equal(3, result.ExtensionData.Count);
49+
Assert.True(result.ExtensionData.ContainsKey("category"));
50+
Assert.True(result.ExtensionData.ContainsKey("supportclaim"));
51+
Assert.True(result.ExtensionData.ContainsKey("product_line"));
52+
Assert.Equal("", result.ExtensionData["category"].GetString());
53+
Assert.False(result.ExtensionData["supportclaim"].GetBoolean());
54+
Assert.Equal(JsonValueKind.Array, result.ExtensionData["product_line"].ValueKind);
55+
Assert.Single(result.ExtensionData["product_line"].EnumerateArray());
56+
Assert.Equal("TEST", result.ExtensionData["product_line"].EnumerateArray().First().GetString());
57+
}
3858
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"id": 1234,
3+
"group_id": 9,
4+
"priority_id": 2,
5+
"state_id": 4,
6+
"organization_id": null,
7+
"number": "123456",
8+
"title": "Mustermann (+1234567890) über WhatsApp",
9+
"owner_id": 4,
10+
"customer_id": 321,
11+
"note": null,
12+
"first_response_at": "2026-03-03T09:58:25.502Z",
13+
"first_response_escalation_at": null,
14+
"first_response_in_min": 0,
15+
"first_response_diff_in_min": 59940,
16+
"close_at": "2026-03-03T09:58:46.200Z",
17+
"close_escalation_at": null,
18+
"close_in_min": null,
19+
"close_diff_in_min": null,
20+
"update_escalation_at": null,
21+
"update_in_min": null,
22+
"update_diff_in_min": null,
23+
"last_close_at": "2026-03-03T10:02:21.125Z",
24+
"last_contact_at": "2026-03-03T10:02:10.280Z",
25+
"last_contact_agent_at": "2026-03-03T10:02:10.280Z",
26+
"last_contact_customer_at": "2026-03-03T09:58:01.887Z",
27+
"last_owner_update_at": null,
28+
"create_article_type_id": 14,
29+
"create_article_sender_id": 2,
30+
"article_count": 3,
31+
"escalation_at": null,
32+
"pending_time": null,
33+
"type": null,
34+
"time_unit": null,
35+
"preferences": {
36+
"channel_id": 14,
37+
"channel_area": "WhatsApp::Business",
38+
"whatsapp": {
39+
"from": {
40+
"phone_number": "1234567890",
41+
"display_name": "Mustermann"
42+
},
43+
"timestamp_incoming": "1772531879",
44+
"timestamp_outgoing": "1772532133"
45+
},
46+
"escalation_calculation": {
47+
"first_response_at": "2026-03-03T09:58:25.502Z",
48+
"last_update_at": "2026-03-03T10:02:10.280Z",
49+
"close_at": "2026-03-03T09:58:46.200Z",
50+
"last_contact_at": "2026-03-03T10:02:10.280Z",
51+
"sla_id": 1,
52+
"sla_updated_at": "2025-08-11T13:06:22.275Z",
53+
"calendar_id": 1,
54+
"calendar_updated_at": "2026-03-02T14:34:40.449Z",
55+
"escalation_disabled": false
56+
}
57+
},
58+
"updated_by_id": 4,
59+
"created_by_id": 243,
60+
"created_at": "2026-03-03T09:58:01.746Z",
61+
"updated_at": "2026-03-03T10:02:21.122Z",
62+
"checklist_id": null,
63+
"category": "",
64+
"supportclaim": false,
65+
"product_line": [
66+
"TEST"
67+
],
68+
"referencing_checklist_ids": [],
69+
"article_ids": [
70+
5926,
71+
5927,
72+
5928,
73+
5931
74+
],
75+
"ticket_time_accounting_ids": []
76+
}

0 commit comments

Comments
 (0)