rebelpl/bc-api2-client

Business Central API interface

dev-main 2025-06-23 09:58 UTC

This package is auto-updated.

Last update: 2025-06-23 09:58:17 UTC


README

This library includes client and base models to use Business Central API (v2.0) in PHP.

Installation

To install, use composer:

composer require rebelpl/bc-api2-client

To use standard resources provided by Microsoft:

composer require rebelpl/bc-api2-common

Usage

Setup

To use the client, you need OAuth authentication flow to be set up for your app: https://github.com/rebelpl/oauth2-businesscentral?tab=readme-ov-file#pre-requisites.

Create client

To create a client, you need a valid Access Token. You can use an OAuth library to obtain it, then:

$client = new Rebel\BCApi2\Client(
    accessToken: $accessToken,
    environment: 'sandbox',
    companyId: '123456',
);

or use Client\Factory helper (requires rebelpl/oauth2-businesscentral or any other implementation of League\OAuth2\Client\Provider\AbstractProvider):

// service-to-service
$client = Rebel\BCApi2\Client\Factory::useClientCredentials(
    new Rebel\OAuth2\Client\Provider\BusinessCentral([
        'tenantId' => 'mydomain.com',
        'clientId' => 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyyyyyy',
        'clientSecret' => '*************************',
    ]),
    environment: 'sandbox',
    companyId: '123456');
// login-as
$client = Rebel\BCApi2\Client\Factory::useAuthorizationCode(
    new Rebel\OAuth2\Client\Provider\BusinessCentral([
        'tenantId' => 'mydomain.com',
        'clientId' => 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyyyyyy',
        'clientSecret' => '*************************',
        'redirectUri' => 'https://localhost',
    ]),
    environment: 'sandbox',
    companyId: '123456',
    tokenFilename: 'tmp/token.json');

Get Companies

foreach ($client->getCompanies() as $company) {
    echo " - {$company->name}:\t{$company->id}\n";
}

Get Resources

$response = $client->get('companies(123456)/items?$top=3');
$data = json_decode($response->getBody(), true);
foreach ($data['value'] as $item) {
    echo " - {$item['number']}:\t{$item['displayName']}\n";
}

Use Request helper

$request = new Rebel\BCApi2\Request('PATCH', 'companies(123456)/items(32d80403)',
    body: json_encode([
        'displayName' => 'Updated Item Name',
        'unitPrice' => 99.95,
     ]), etag: 'W/"JzE5OzIxMzk2MzA0ODM0ODgyMTU4MDgxOzAwOyc="');
$response = $client->call($request);

Use Repository / Entity helpers

$repository = new Rebel\BCApi2\Entity\Repository($client, entitySetName: 'salesOrders');
$results = $repository->findBy([ 'customerNumber' => 'CU-0123' ], 'orderDate DESC', 5, expanded: [ 'salesOrderLines' ]);
foreach ($results as $salesOrder) {

    # use rebelpl/bc-api2-common or generate your own models for easier access to properties
    echo " - {$salesOrder->get('number')}:\t{$salesOrder->get('totalAmountIncludingTax')} {$salesOrder->get('currencyCode')}\n";
}

# create new salesOrder
$salesOrder = new \Rebel\BCApi2\Entity([
    'customerNumber' => 'CU-0123',
    'externalDocumentNumber' => 'TEST/123',
    'salesOrderLines' => [
        [
            "sequence" => 10000,
            "lineType" => "Item",
            "lineObjectNumber" => "1900-A",
            "quantity" => 5
        ],
        [
            "sequence" => 20000,
            "lineType" => "Item",
            "lineObjectNumber" => "1928-S",
            "quantity" => 20
        ],
    ],
], expanded: [ 'salesOrderLines' ]);

$repository->create($salesOrder);
echo " - {$salesOrder->get('number')}:\t{$salesOrder->get('totalAmountIncludingTax')} {$salesOrder->get('currencyCode')}\n";

Working with nested properties

Business Central does not support deep update and mixed insert/update operations. The Entity\Repository class provides a custom save() method that handles this limitation by using batchUpdate() to create / update the nested properties.

// Create a SalesOrder repository
$repository = new Rebel\BCApi2\Entity\SalesOrder\Repository($client);

// Get a sales order by ID
$salesOrder = $repository->get('abc-123', expanded: [ 'salesOrderLines' ]);

// Update properties of the sales order
$salesOrder->externalDocumentNumber = 'TEST';

// Update existing line
$salesOrder->salesOrderLines[0]->quantity = 10;

// Add new line
$salesOrder->salesOrderLines[] = new Rebel\BCApi2\Entity\SalesOrderLine\Record([
    'itemId' => '12345',
    'quantity' => 5
]);

// Save all changes in one operation
$repository->save($salesOrder);

Generate Entity models for your API

# fetch Metadata from BC...
$metadata = new Rebel\BCApi2\Client(
    accessToken: $token->getToken(),
    environment: 'sandbox',
    apiRoute: '/mycompany/myapi/v1.5'
)->getMetadata();

# ... or from the local file
$metadata = Rebel\BCApi2\Metadata\Factory::fromString(file_get_contents('files/metadata.xml'));

# then generate the files
$generator = new Rebel\BCApi2\Entity\Generator($metadata, namespacePrefix: 'App\\Models\\');
$generator->saveAllFilesTo('app/Models', overwrite: true);

Tests

./vendor/bin/phpunit