import { Callout } from "zudoku/ui/Callout";

# Extensibility Events

`365 business Print Agent` publishes four events another extension can subscribe to. Three of them report that printing has stopped working somewhere, the fourth lets you take over when a printer configuration cannot be enabled.

| Object | Event | Raised |
| --- | --- | --- |
| `bdev.Print Agent Events` (`5523820`) | [`PrintAgentClientOfflineEvent`](#printagentclientofflineevent---event) | A Print Agent Client is no longer reachable. |
| `bdev.Print Agent Events` (`5523820`) | [`PrinterOfflineEvent`](#printerofflineevent---event) | A printer has gone offline or is not available. |
| `bdev.Print Agent Events` (`5523820`) | [`PrinterFailureEvent`](#printerfailureevent---event) | A printer reports a problem - out of paper, low toner, jammed. |
| `bdev.PrA Printer Configuration` (`5523743`) | [`OnTryEnablePrinterConfigurationFailed`](#ontryenableprinterconfigurationfailed---event) | A printer configuration could not be enabled. |

The three monitoring events exist for the same reason: printing happens outside Business Central, and a job that never arrives is invisible to the user until somebody looks for the document. Subscribe to them to raise a ticket, send a mail, or mark the process that depends on the printer.

## PrintAgentClientOfflineEvent - Event

Raised for every Print Agent Client that is currently offline, while the app checks the state of its clients.

```pascal
    /// <summary>
    /// Event raised when a Print Agent Client goes offline.
    /// </summary>
    /// <param name="printAgentName">Name of the print agent client service.</param>
    /// <param name="lastSeen">Date/time the print agent client service was last seen.</param>
    [IntegrationEvent(false, false)]
    local procedure PrintAgentClientOfflineEvent(printAgentName: Text[200]; lastSeen: DateTime)
    begin
    end;
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `printAgentName` | Text[200] | The name of the client service. |
| `lastSeen` | DateTime | When the client was last reachable. |

<Callout type="caution" title="The event follows the notification">
The event is raised on the path that sends the "one or more print agents are currently offline" notification. A user who dismissed that notification for good, or a session in which notifications are suppressed, also stops the event. Do not build a monitoring that has to be complete on this event alone.
</Callout>

### Example

```pascal
codeunit 50000 "My Print Agent Subscriber"
{
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"bdev.Print Agent Events", 'PrintAgentClientOfflineEvent', '', true, true)]
    local procedure LogOfflineClientOnPrintAgentClientOfflineEvent(printAgentName: Text[200]; lastSeen: DateTime)
    var
        printerIncident: Record "My Printer Incident";
    begin
        printerIncident.Init();
        printerIncident."Entry No." := 0;
        printerIncident.Type := printerIncident.Type::"Client offline";
        printerIncident."Agent Name" := printAgentName;
        printerIncident."Last Seen" := lastSeen;
        printerIncident.Insert(true);
    end;
}
```

## PrinterOfflineEvent - Event

Raised when the status of a printer changes to `Offline` or `Not Available`.

```pascal
    [IntegrationEvent(false, false)]
    local procedure PrinterOfflineEvent(printAgentName: Text[200]; printerName: Text[100]; status: Text[1024])
    begin
    end;
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `printAgentName` | Text[200] | The client hosting the printer. |
| `printerName` | Text[100] | The name of the printer. |
| `status` | Text[1024] | The new status, `Offline` or `Not Available`. |

## PrinterFailureEvent - Event

Raised when the status of a printer changes to anything else that is not `Ready` - out of paper, paper jam, low toner, door open.

```pascal
    [IntegrationEvent(false, false)]
    local procedure PrinterFailureEvent(printAgentName: Text[200]; printerName: Text[100]; status: Text[1024])
    begin
    end;
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `printAgentName` | Text[200] | The client hosting the printer. |
| `printerName` | Text[100] | The name of the printer. |
| `status` | Text[1024] | The new status. A printer can report several at once, in which case they arrive as a comma-separated list. |

Both printer events are raised on a **change** of status, while the app reads the printer information from its clients: as long as a printer stays out of paper, the event fires once. A printer returning to `Ready` raises nothing at all - if you opened an incident on the event, close it by watching the `Status` field of `bdev.Print Agent Printers`.

<Callout type="info" title="Disable Status Check does not silence them">
The `Disable Status Check` field of a printer suppresses the status check the client performs **before a print job**. The status is still read and the events are still raised.
</Callout>

## OnTryEnablePrinterConfigurationFailed - Event

The app enables a printer configuration by testing it against the printer. When that test fails, it shows the user a message saying the configuration has to be enabled manually. This event is raised first, and lets you handle the failure differently.

```pascal
    [IntegrationEvent(false, false)]
    local procedure OnTryEnablePrinterConfigurationFailed(printerConfiguration: Record "bdev.PrA Printer Configuration"; var isHandled: Boolean)
    begin
    end;
```

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `printerConfiguration` | Record "bdev.PrA Printer Configuration" | The configuration that could not be enabled. |
| `isHandled` | Boolean | Set to `true` to suppress the message the app would show. |

The reason for the failure is in `GetLastErrorText()` at the time the event is raised.

Setting `isHandled` suppresses the message and nothing else - the configuration stays disabled either way. Use it where a message would be wrong: in a data migration, in a setup wizard of your own, or wherever the failure is collected and presented in one place rather than one dialog per configuration.

```pascal
    [EventSubscriber(ObjectType::Table, Database::"bdev.PrA Printer Configuration", 'OnTryEnablePrinterConfigurationFailed', '', true, true)]
    local procedure CollectFailureOnTryEnablePrinterConfigurationFailed(printerConfiguration: Record "bdev.PrA Printer Configuration"; var isHandled: Boolean)
    begin
        if (not MigrationIsRunning()) then
            exit;

        LogConfigurationFailure(printerConfiguration.Code, GetLastErrorText());
        isHandled := true;
    end;
```

## See also

- [365 business Print Agent - Overview](readme.mdx)
- [Print Agent](print-agent.mdx)
- [Documentation - Print Agent Clients](../../en-us/365-business-print-agent/print-agent-clients.mdx)
