# Rule: SimpleProperty — DOM types, binding, and identity

A `<SimpleProperty>` declares one typed field on a BusinessObject. The framework generates getter/setter pairs (`getPropertyName()` / `setPropertyName()`) for every declared property.

## Core attributes

| Attribute            | Required             | Purpose                                                                           |
| -------------------- | -------------------- | --------------------------------------------------------------------------------- |
| `name`               | yes                  | camelCase field name; getter/setter is derived from this                          |
| `type`               | yes                  | Domain type (see table below)                                                     |
| `id="true"`          | one per BO           | Marks the primary key; used by the framework for identity, load, and save routing |
| `id="false"`         | default              | All non-key properties                                                            |
| `dataSourceProperty` | for persisted fields | Names the DS `<Attribute>` that maps this property to a column                    |
| `storable="false"`   | computed/join-only   | Prevents the field from being written back on save; safe for joined columns       |
| `blobPKeyField`      | blob types           | Names the property that holds the blob's parent pKey                              |
| `blobTable`          | blob types           | Names the SQLite table holding the blob column                                    |

## The `id="true"` rule

Exactly one `<SimpleProperty>` must carry `id="true"`.

-   Platform BOs: the validator enforces this and rejects files without it.
-   The pKey field uses `type="DomPKey"`.
-   Always name it `pKey` for consistency with all shipped BO examples.

```xml
<!-- Correct — one and only one id="true" -->
<SimpleProperty name="pKey" type="DomPKey" id="true" dataSourceProperty="pKey" />
```

## The `dataSourceProperty` binding

`dataSourceProperty="name"` tells the framework which DS `<Attribute name="...">` maps to this BO property.

```xml
<!-- DS declares: <Attribute name="status" table="Visit" column="Status" /> -->
<!-- BO binds:   -->
<SimpleProperty name="status" type="DomVisitStatus" id="false" dataSourceProperty="status" />
```

**If `dataSourceProperty` is absent**, the property is treated as computed — the framework never reads it from the DS and never writes it back. Values must be set manually in `afterLoadAsync`, `afterCreateAsync`, or other hooks.

```xml
<!-- Computed — must be populated in BL -->
<SimpleProperty name="statusIcon" type="DomString" />
<SimpleProperty name="isEditEnabled" type="DomBool" />
```

## `storable="false"` — joined/read-only columns

A property from a LEFT/INNER joined table should be marked `storable="false"` so the save routine skips it. Without this, the framework may attempt an UPDATE on a column that belongs to a different table, causing a save error.

```xml
<!-- From a join — read-only, should not be written back -->
<SimpleProperty name="accountName" type="DomText" storable="false" dataSourceProperty="accountName" />
```

Real-file citation: `src/Visit/BO/BoVisit/BoVisit.businessobject.xml` shows `visitor` (type `DomText`) bound to the `visitor` DS attribute, which comes from a User join.

## Domain type reference

### Primitive types

| Type                 | Purpose                                            | Example value            |
| -------------------- | -------------------------------------------------- | ------------------------ |
| `DomPKey`            | Salesforce 18-char record ID (primary key)         | `"001O300001TYlYFIA1"`   |
| `DomId`              | Shorter identifier field (not always 18 chars)     | `"ORD-00001"`            |
| `DomText`            | Short text / string                                | `"Northern Trail"`       |
| `DomLongText`        | Multi-paragraph text                               | Long descriptions        |
| `DomLongDescription` | Like `DomLongText`, for description fields         | Notes, messages          |
| `DomString`          | Generic string for icons, codes, arbitrary strings | `"Active24"`             |
| `DomBool`            | Boolean                                            | `true` / `false`         |
| `DomInteger`         | Whole number                                       | `42`                     |
| `DomDecimal`         | Decimal / float                                    | `123.45`                 |
| `DomMoney`           | Currency value                                     | `1299.99`                |
| `DomDate`            | Date only (ANSI format: YYYY-MM-DD)                | `"2026-04-27"`           |
| `DomTime`            | Time only (HH:MM)                                  | `"14:30"`                |
| `DomDateTime`        | Full timestamp                                     | `"2026-04-27T14:30:00Z"` |
| `DomRgbColor`        | Hex color code                                     | `"#FF5733"`              |
| `DomDegree`          | Geographic degree (lat/lng)                        | `48.8566`                |

### Module-specific domain types (picklist enumerations)

| Type                      | Module  | Used for                                                   |
| ------------------------- | ------- | ---------------------------------------------------------- |
| `DomVisitStatus`          | Visit   | Visit lifecycle state (Planned, In Progress, Completed, …) |
| `DomVisitPriority`        | Visit   | Visit urgency level                                        |
| `DomSdoPhase`             | Order   | Order document phase                                       |
| `DomSdoSubType`           | Order   | Order document type                                        |
| `DomSdoCalculationStatus` | Order   | Pricing calculation state                                  |
| `DomCurrency`             | Order   | Currency code                                              |
| `DomPaymentMethod`        | Order   | Payment method enum                                        |
| `DomSalesOrg`             | Order   | Sales organisation                                         |
| `DomPrdCategory`          | Product | Product category classification                            |
| `DomDistribChannel`       | Order   | Distribution channel                                       |

These are declared elsewhere in the contracts as typed enumerations. Use them instead of `DomText` when a field has a fixed set of values — the framework can validate against them.

## Property change events

A property can fire a declared method when its value changes:

```xml
<SimpleProperty name="deliveryDate" type="DomDate" dataSourceProperty="deliveryDate">
  <Events>
    <Event name="onChanged" eventHandler="onDeliveryDateChanged"/>
  </Events>
</SimpleProperty>
```

The `eventHandler` value must match both a `<Method name="..."/>` declaration in `<Methods>` AND a `.bl.js` implementation.

Real-file citation: `src/Order/BO/BoOrder/BoOrder.businessobject.xml` uses `onChanged` events on `deliveryDate`, `headerDiscount`, `paidAmountReceipt`, and `paymentMethod`.

## Common authoring mistakes

| Mistake                                           | Consequence                                     | Fix                                                             |
| ------------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------- |
| Missing `dataSourceProperty` on a persisted field | `getFieldName()` returns `undefined` at runtime | Add `dataSourceProperty="<dsAttrName>"` matching a DS attribute |
| Two properties with `id="true"`                   | Build validation error                          | Keep exactly one `id="true"`                                    |
| `storable` omitted on joined-table field          | Save routine tries to update the wrong table    | Add `storable="false"` to joined fields                         |
| Typo in `dataSourceProperty`                      | Silently returns `undefined`                    | Spell must match the DS `<Attribute name="...">` exactly        |
| Missing `<Method>` for `eventHandler`             | Method not found at runtime                     | Declare the handler in `<Methods>`                              |
