# Rule: BusinessObject lifecycle methods — declaration and implementation

## How methods work

Methods are declared in the BO XML `<Methods>` wrapper and implemented in separate `.bl.js` files under `Bo<Name>/Mv2/`. A method that appears only in XML (with no backing `.bl.js`) produces a build warning. A `.bl.js` that has no matching `<Method>` declaration is silently ignored by the framework — the method will never be called.

**Both must exist:** XML declaration + `.bl.js` file.

---

## Standard lifecycle hooks

These are called by the framework at well-defined points. Declare any you intend to implement.

### Load lifecycle

| Method name       | When called                                          | Common use                                                       |
| ----------------- | ---------------------------------------------------- | ---------------------------------------------------------------- |
| `beforeLoadAsync` | Before DS query executes                             | Set query parameters, add DS conditions                          |
| `loadAsync`       | Replaces the generated load; override only if needed | Custom multi-step load                                           |
| `afterLoadAsync`  | After DS attributes are mapped to BO properties      | Compute derived fields, set icons, split DateTime into date+time |

### Create lifecycle

| Method name         | When called                              | Common use                                                                |
| ------------------- | ---------------------------------------- | ------------------------------------------------------------------------- |
| `beforeCreateAsync` | Before framework creates the BO instance | Rarely used for creation; set up context                                  |
| `createAsync`       | Replaces the generated create            | Custom creation logic (e.g., copy-from template)                          |
| `afterCreateAsync`  | After BO is created with a new pKey      | **Set all default values**, set `objectStatus = STATE.NEW \| STATE.DIRTY` |

### Save lifecycle

| Method name       | When called                      | Common use                                                                 |
| ----------------- | -------------------------------- | -------------------------------------------------------------------------- |
| `beforeSaveAsync` | Before persistence write         | Recombine split Date+Time into DateTime, call `Facade.saveObjectAsync(me)` |
| `saveAsync`       | Replaces the generated save      | Advanced save with multiple objects                                        |
| `afterSaveAsync`  | After persistence write succeeds | Send notifications, update related records                                 |

### Validate lifecycle

| Method name             | When called                                  | Common use                                 |
| ----------------------- | -------------------------------------------- | ------------------------------------------ |
| `beforeDoValidateAsync` | Before validation pass runs                  | Set validation flags                       |
| `afterDoValidateAsync`  | After framework validation; add custom rules | Add errors/warnings via `messageCollector` |

### Initialize lifecycle

| Method name        | When called                     | Common use                                 |
| ------------------ | ------------------------------- | ------------------------------------------ |
| `beforeInitialize` | Before BO object is initialized | Rarely used                                |
| `afterInitialize`  | After BO object is initialized  | Set up internal state, register for events |

---

## `generateLoadMethod="true"` — when to use it

```xml
<BusinessObject name="BoVisit" schemaVersion="1.1" generateLoadMethod="true">
```

-   `true`: The framework auto-generates a `loadAsync` method that runs the DS query and maps attributes. You only need to declare and implement `beforeLoadAsync` / `afterLoadAsync` hooks.
-   `false` (or absent): You must write the entire `loadAsync` implementation manually.

Use `true` for all simple BOs. Use `false` only when load requires multiple DS queries or complex orchestration.

Real-file citations:

-   `BoVisit.businessobject.xml` — `generateLoadMethod="true"` (standard)
-   `BoOrder.businessobject.xml` — `generateLoadMethod="false"` (overrides load to handle multi-DS ordering)

---

## Custom methods

Any business-logic method specific to the entity is declared exactly the same way:

```xml
<Methods>
  <!-- Lifecycle hooks -->
  <Method name="afterLoadAsync"/>
  <Method name="afterCreateAsync"/>
  <Method name="beforeSaveAsync"/>
  <Method name="afterSaveAsync"/>
  <!-- Custom domain methods -->
  <Method name="startVisit"/>
  <Method name="endVisit"/>
  <Method name="getCallDuration"/>
</Methods>
```

Real-file citation: `BoVisit.businessobject.xml` declares custom methods `endVisit`, `startVisit`, `abandonVisit`, `reschedule`, `getCallDuration`, `getCameraSettings`, `capturePicture`.

---

## `onPropertyChanged` — responding to UI edits

Declare `onPropertyChanged` to receive a callback whenever any BO property changes. The BL implementation receives the property name and can react selectively:

```xml
<Method name="onPropertyChanged"/>
```

```javascript
/**
 * @function onPropertyChanged
 * @this BoVisit
 * @kind businessobject
 * @namespace CUSTOM
 * @param {String} propertyName
 * @returns void
 */
function onPropertyChanged(propertyName) {
    var me = this;
    if (propertyName === 'plannedStartDate') {
        // Recalculate duration when start date changes
        me.setDuration(Utils.calculateDuration(me.getPlannedStartDate(), me.getPlannedEndDate()));
    }
}
```

For granular handling on a single property, use an `<Event name="onChanged">` inside the `<SimpleProperty>` instead (see `references/simple-properties.md`).

---

## `<Validations>` block

Custom validation methods that the framework runs during the VALIDATION process action are declared in an optional `<Validations>` block:

```xml
<Validations>
  <Validation name="validateLengthOfFields"/>
  <Validation name="validateOperatingHours"/>
</Validations>
```

These are invoked automatically by the `VALIDATION` process action. Each validation method must also appear in `<Methods>` and be implemented in `.bl.js`. The BL receives a `messageCollector` via `context` to add errors and warnings.

Real-file citation: `BoVisit.businessobject.xml` has a `<Validations>` block with `validateLengthOfFields`. `BoOrder.businessobject.xml` has six validation entries.

---

## Critical: `beforeSaveAsync` must call `Facade.saveObjectAsync`

The framework's SAVE process action does NOT automatically persist properties. The BO's `beforeSaveAsync` must call:

```javascript
function beforeSaveAsync(context) {
    var me = this;
    // Recombine split fields before save (if using DateTimeAttribute split)
    me.setPlannedStartDateTime(me.getPlannedStartDate() + ' ' + me.getPlannedStartTime() + ':00');
    var promise = Facade.saveObjectAsync(me);
    return promise;
}
```

Without this call, the SAVE action completes without touching the database. This is one of the most common silent failures.

---

## `afterCreateAsync` must set `objectStatus`

New records must have their `objectStatus` set so the framework knows to INSERT rather than UPDATE:

```javascript
function afterCreateAsync(result, context) {
    var me = this;
    me.setPKey(PKey.next());
    me.setStatus('Planned');
    me.setObjectStatus(STATE.NEW | STATE.DIRTY);
    return when.resolve(result);
}
```

Without `STATE.NEW | STATE.DIRTY`, `Facade.saveObjectAsync` may skip the record or attempt an UPDATE on a non-existent row.

---

## BL file placement

```
src/<Module>/BO/Bo<Name>/
├── Bo<Name>.businessobject.xml
├── Bo<Name>.validationmessages.xml   ← companion file (optional but common)
└── Mv2/
    ├── Bo<Name>.AfterLoadAsync.bl.js
    ├── Bo<Name>.AfterCreateAsync.bl.js
    ├── Bo<Name>.BeforeSaveAsync.bl.js
    ├── Bo<Name>.AfterSaveAsync.bl.js
    ├── Bo<Name>.AfterDoValidateAsync.bl.js
    └── Bo<Name>.StartVisit.bl.js     ← custom method
```

All `.bl.js` files must use `@namespace CUSTOM` in their JSDoc block (see `_shared/namespace.md`).
