TradingPartner.ktThe central domain model for D-velop integration. A trading partner represents a business entity (company or person) that ProjectForge exchanges invoices with — suppliers (vendors), customers, or entities that are both. This class maps directly to D-velop's REST API JSON structure for trading partners and includes all fields needed for address management (bill-to, ship-to, and physical addresses), contact info, organizational assignment, and a custom field mechanism that bridges ProjectForge's DATEV account number to D-velop's custom fields API.
D-velop uses enum-like value objects rather than plain strings. ProjectForge wraps these as inner classes:
| Inner Class | Enum Values | JSON Structure |
|---|---|---|
Type | VENDOR, CUSTOMER, PARTNER | { "value": "VENDOR" } |
ContactType | COMPANY, PRIVATE | { "value": "COMPANY" } |
Active | TRUE, FALSE | { "value": "TRUE" } |
Organization | id, number?, name? | { "id": "...", "number": null, "name": null } |
Organization implements equals() and hashCode() based solely on id for set-based deduplication.
companion object {
var datevKontoFieldId: String? = null
}
The datevKontoFieldId is a globally cached ID of the D-velop custom field definition for "datevKonto". It is set once during D-velop bootstrapping (by discovering the custom field definitions) and then used by the customFields property to serialize/deserialize the DATEV account number through D-velop's custom field mechanism.
| Property | Type | Required? | Description |
|---|---|---|---|
id | String? | — | Unique identifier assigned by D-velop after creation |
number | String? | Required | Business partner number (external identifier) |
name | String? | Read-only | Calculated by D-velop from company or firstName+lastName |
shortName | String? | — | Short identifier for list displays |
contactType | ContactType? | Required | COMPANY or PRIVATE |
firstName | String? | — | First name (for PRIVATE contacts) |
lastName | String? | If PRIVATE | Last name (required if contactType=PRIVATE) |
company | String? | If COMPANY | Company name (required if contactType=COMPANY) |
type | Type? | Required | VENDOR, CUSTOMER, or PARTNER |
active | Active? | Required | Whether the partner is active |
organization | Organization? | Required | The D-velop organization this partner belongs to |
| Property | Type |
|---|---|
street | String? |
zip | String? |
city | String? |
region | String? |
country | String? |
postBoxZip | String? |
postBox | String? |
addressAdditional | String? |
billTo*)| Property | Type | Description |
|---|---|---|
billToStreet | String? | Billing street address |
billToZip | String? | Billing postal code |
billToCity | String? | Billing city |
billToRegion | String? | Billing region/state |
billToCountry | String? | Billing country |
billToAddressAdditional | String? | Additional billing address lines |
isBillToAddressEmpty | Boolean (computed) | True if all billTo fields are blank |
shipTo*)| Property | Type |
|---|---|
shipToStreet | String? |
shipToZip | String? |
shipToCity | String? |
shipToRegion | String? |
shipToCountry | String? |
shipToAddressAdditional | String? |
| Property | Type | Description |
|---|---|---|
phoneNumber | String? | Phone number |
faxNumber | String? | Fax number |
eMail | String? | Email address |
website | String? | Website URL |
remarks | String? | Free-text notes |
responsible | String? | User ID of the responsible person |
relationSince | String? | Start date of business relation (format: "2022-05-11 00:00:00") |
relationUntil | String? | End date of business relation |
importCode | String? | Leading ID in the external system (used during migration) |
The customFields property with custom getter/setter is the bridge between ProjectForge's datevKonto field and D-velop's generic custom field API:
get() {
if (datevKonto == null || datevKontoFieldId == null) return null
return mapOf(datevKontoFieldId!! to CustomField(
configID = datevKontoFieldId!!,
name = "datevKonto",
value = datevKonto
))
}
If a DATEV account number is set and the datevKontoFieldId is known, it creates a single-entry map with the custom field wrapper.
set(value) {
value?.values?.find { it.name == "datevKonto" }?.value?.let {
datevKonto = it as Int?
}
if (value == null) { datevKonto = null }
}
When deserializing D-velop JSON responses, finds the "datevKonto" custom field and extracts its integer value.
@JsonIgnore on datevKonto prevents it from being serialized directly — it must go through the customFields mechanismType(value)) to match D-velop's JSON structure {"value": "..."}isBillToAddressEmpty is annotated with @JsonIgnore to prevent serializationvar properties (not a data class) because it has custom getters/setters and companion object logicstreet/zip/city), billing (billTo*), and shipping (shipTo*)868d6abb7 2025 -> 2026 63081666f Source file headers: 2024-> 2025. b6092df09 Copyright 2023 -> 2024 510974f0f D-velop: test fixed. adc61b60b Nothing real bf2e51373 WIP D.velop be750e77e WIP D.velop 9ebb99c88 WIP D.velop cb2915283 WIP D.velop aec5b4be0 Nothing real. cb6d633f9 WIP D-velop 6a4ee1932 WIP D-velop 50926baa8 WIP D-velop 912400e42 WIP D-velop c2418da24 dvelop package moved from projectforge-business to projectforge-rest. f993107db Initial revision. Spring boot 2.7.6->2.7.7