# Framework APIs for `.bl.js` Business Logic

All APIs listed here are globals available inside any `.bl.js` function body. No import statements
are needed — the runtime injects them.

## BoFactory — Object Creation and Loading

`BoFactory` is the primary way to create and load typed business objects.

### Load a BO by parameters

```javascript
BoFactory.loadObjectByParamsAsync('BoSettings', {
    params: [{ field: 'pKey', value: settingsPKey, operator: 'EQ' }],
}).then(function (settings) {
    me.setBoSettings(settings);
    return me;
});
```

Real usage: `src/Visit/BO/BoVisit/Mv2/BoVisit.StartVisit.bl.js` — loads a settings BO before
modifying visit state.

### Load a list (LO) by parameters

```javascript
BoFactory.loadListAsync('LoWfeState', {
    params: [{ field: 'wfeWorkflowPKey', value: me.getPKey(), operator: 'EQ' }],
}).then(function (loState) {
    me.setLoWfeState(loState);
    return me;
});
```

### Create a new BO instance

```javascript
BoFactory.createObjectAsync('BoGeoHelper', {}).then(function (geoHelper) {
    return geoHelper.computeDistance(lat1, lon1, lat2, lon2);
});
```

### Instantiate from raw data (lookup pattern)

```javascript
var jsonQuery = { params: [{ field: 'pKey', value: productPKey, operator: 'EQ' }] };
Facade.getObjectAsync('LuProduct', jsonQuery).then(function (rawData) {
    var luProduct = BoFactory.instantiate('LuProduct', rawData);
    me.setProduct(luProduct);
    return me;
});
```

---

## Facade — Backend Data Operations

`Facade` is the lower-level layer for raw list and object data (without the full BO lifecycle).

### Load a list (returns raw item array, not an LO instance)

```javascript
var jsonQuery = {};
jsonQuery.params = [];
jsonQuery.cond = " AND Task.Status IN ('Active') AND Task.ActivityDate <= #cardDate# ";
jsonQuery.params.push({
    field: 'cardDate',
    value: Utils.convertForDBParam(cardDate, 'DomDate'),
});
return Facade.getListAsync('LoMyTask', jsonQuery).then(function (items) {
    me.addItems(items, jsonQuery.params);
    return me;
});
```

Real usage: `src/Visit/BO/BoVisit/Mv2/BoVisit.IsStartVisitButtonVisible.bl.js` — card data loading
pattern using `Facade.getListAsync` to populate an LO for a cockpit card.

### Load a single lookup record

```javascript
Facade.getObjectAsync('LuProductUom', {
    params: [{ field: 'pKey', value: uomPKey, operator: 'EQ' }],
}).then(function (rawData) {
    // rawData is a plain JSON object
    return rawData;
});
```

### Save an object

```javascript
Facade.saveObjectAsync(me).then(function () {
    return me;
});
```

### Get error details after failure

```javascript
promise = Facade.saveObjectAsync(me)
    .then(function (result) {
        return result;
    })
    .catch(function (err) {
        var details = Facade.getErrorDetails();
        ApplicationContext.log('Save failed: ' + details);
        return me;
    });
```

---

## ApplicationContext — Global State

### Current user

```javascript
var user = ApplicationContext.get('user');
var userPKey = user.getPKey();
var hasRole = user.hasRole('TourUser'); // Boolean
```

### Logging and diagnostics

```javascript
ApplicationContext.log('Processing visit ' + me.getPKey());
ApplicationContext.logError("Expected 'Active' but got: " + me.getStatus());
```

These write to the mobile app devtools console. Use structured messages to aid debugging.

### Display error to user

```javascript
ApplicationContext.displayErrorMessage('Validation failed: Name is required.');
```

Renders a visible error banner in the app UI.

---

## PKey — ID Generation

```javascript
var newPKey = PKey.next();
me.setPKey(newPKey);
```

`PKey.next()` generates a new unique primary key string. Required when creating new list items
from BL code (`STATE.NEW | STATE.DIRTY` items).

Real usage: `src/Visit/BO/BoVisit/Mv2/BoVisit.StartVisit.bl.js`.

---

## Promise Patterns

### Basic synchronous resolution

```javascript
var promise = when.resolve(context);
return promise;
```

Use when no async work is needed but the lifecycle contract requires a Promise return.

### Sequential async chain (.then)

```javascript
var promise = BoFactory.loadObjectByParamsAsync('BoSettings', query)
    .then(function (settings) {
        me.setBoSettings(settings);
        return BoFactory.loadObjectByParamsAsync('BoSales', query2);
    })
    .then(function (sales) {
        me.setBoSales(sales);
        return me;
    });
return promise;
```

### Parallel async load (when.all)

```javascript
var promises = [];
promises.push(Facade.saveObjectAsync(me));
promises.push(me.getBoAnnotation().saveAsync());
promises.push(me.getLoRecentState().saveAsync());

var promise = when.all(promises).then(function () {
    return me;
});
return promise;
```

Use `when.all` when multiple independent async operations can run concurrently.

### Error handling (.catch)

```javascript
var promise = BoFactory.loadObjectByParamsAsync('BoVisit', query)
    .then(function (boVisit) {
        me.setBoVisit(boVisit);
        return me;
    })
    .catch(function (err) {
        ApplicationContext.logError('Failed to load BoVisit: ' + err);
        return me;
    });
return promise;
```

---

## Utils — Utility Helpers

### Date utilities

```javascript
Utils.createAnsiDateToday(); // "2026-04-27"
Utils.createAnsiDateTimeNow(); // "2026-04-27T14:30:00Z"
Utils.createAnsiDateTimeToday(); // "2026-04-27T00:00:00Z"
Utils.convertAnsiDate2Date(str); // ANSI date string → JS Date
Utils.convertAnsiDateTime2AnsiDate(dt); // "2026-04-27T14:30:00Z" → "2026-04-27"
Utils.addDays2AnsiDate(date, days); // Add N days to an ANSI date string
Utils.getMinDate(); // System minimum sentinel date "1700-01-01"
```

Real usage: `src/Visit/BO/BoVisit/Mv2/LoadAsync/BoVisit.AfterLoadAsync.bl.js` — time/date
extraction from `getPlannedStartDateTime()`.

### String / value utilities

```javascript
Utils.isDefined(value); // true if not null/undefined
Utils.isEmptyString(str); // true if null, undefined, or ""
Utils.isPhone(); // true if running on phone form factor
Utils.getToggleText(domain, value, short); // Domain list display text
Utils.convertForDBParam(value, type); // Safe conversion for DS query params
```

### Localization

```javascript
Localization.localize(value, 'time'); // Format time for device locale
Localization.localize(value, 'date'); // Format date for device locale
Localization.resolve('MessageKey'); // Resolved message string by key
```

---

## Collection Operations on LO / BO

```javascript
// Read all items in a list
var items = me.getAllItems();

// Find by primary key
var item = me.getItemByPKey(pKey);

// Find by property value
var groups = me.getItemsByParam({ prdMetaType: 'PrdGroup' });

// Count
var count = me.getCount();

// Filter view (non-destructive)
me.setFilter('phase', 'Initial', 'EQ');
me.resetFilter('phase');

// Sort
me.orderBy({ dateFrom: 'DESC', priority: 'ASC' });

// Bulk add / replace
me.addItems(itemArray, jsonQuery.params);
me.addListItems([newItemObject]); // raw object(s)
me.removeAllItems();
me.removeItem(item);
```

---

## ACL — Protected Property Modification

Some BO properties have ACL rules that prevent direct writes. To override:

```javascript
var aclBo = me.getACL();
aclBo.addRight(AclObjectType.PROPERTY, 'status', AclPermission.EDIT);
me.setStatus('InProgress');
aclBo.removeRight(AclObjectType.PROPERTY, 'status', AclPermission.EDIT);
```

Real usage: `src/Visit/BO/BoVisit/Mv2/BoVisit.StartVisit.bl.js`.

---

## STATE Flags

Used when building new list items programmatically:

```javascript
var newItem = {
    pKey: PKey.next(),
    parentPKey: me.getPKey(),
    userPKey: ApplicationContext.get('user').getPKey(),
    objectStatus: STATE.NEW | STATE.DIRTY,
};
me.getLoMySubList().addListItems([newItem]);
```

`STATE.NEW | STATE.DIRTY` marks the item for save on the next `saveAsync` cycle.

---

## MessageBox — User Confirmation Dialogs

```javascript
MessageBox.displayMessage('Title', 'Are you sure?', ['Yes', 'No']).then(function (input) {
    if (input.buttonPressed === 'Yes') {
        return me.doSomething();
    }
    return me;
});
```
