blockshiftnetwork / sapb1-client
A robust, production-grade Laravel package for SAP Business One HTTP integration, supporting both OData and custom (non-OData) SAP Service Layer (SML) endpoints.
Fund package maintenance!
blockshiftnetwork
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 1
pkg:composer/blockshiftnetwork/sapb1-client
Requires
- php: ^8.3
- illuminate/contracts: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^2.9||^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1.1
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^2.0||^3.0
- pestphp/pest-plugin-arch: ^2.5||^3.0
- pestphp/pest-plugin-laravel: ^2.0||^3.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^1.1||^2.0
- phpstan/phpstan-phpunit: ^1.3||^2.0
- spatie/laravel-ray: ^1.35
This package is auto-updated.
Last update: 2025-11-28 03:05:34 UTC
README
A robust, production-grade Laravel package for SAP Business One HTTP integration, supporting both OData and custom (non-OData) SAP Service Layer (SML) endpoints.
Requirements
- PHP 8.3 or higher
- Laravel 11.x or 12.x
Installation
You can install the package via composer:
composer require blockshiftnetwork/sapb1-client
You can publish the config file with:
php artisan vendor:publish --tag="sapb1-client-config"
This is the contents of the published config file:
return [ 'server' => env('SAPB1_SERVER'), 'database' => env('SAPB1_DATABASE'), 'username' => env('SAPB1_USERNAME'), 'password' => env('SAPB1_PASSWORD'), 'cache_ttl' => env('SAPB1_CACHE_TTL', 1800), 'verify_ssl' => env('SAPB1_VERIFY_SSL', true), ];
Usage
A. Typical OData Example
First, make sure to configure your SAP B1 credentials in your .env file.
use BlockshiftNetwork\SapB1Client\Facades\SapB1; // Query top 5 items $response = SapB1::odataQuery('Items', [ '$filter' => "ItemsGroupCode eq 100", '$orderby' => "ItemCode desc", '$top' => 5, ]); $items = $response->json('value');
B. Advanced OData Queries with the Query Builder
For more complex scenarios, you can use the ODataQuery builder to construct your queries in a readable and maintainable way, very similar to Laravel's Eloquent.
use BlockshiftNetwork\SapB1Client\Facades\SapB1; use BlockshiftNetwork\SapB1Client\ODataQuery; $query = (new ODataQuery()) ->select('CardCode', 'CardName', 'Balance') ->where('CardType', '=', 'cCustomer') // ->where('CardType', 'cCustomer') also works ->orWhere('CardName', 'contains', 'Acme Inc.') ->where('Balance', '>', 0) ->where('CreateDate', 'between', ['2023-01-01', '2023-12-31']) ->orderBy('CardName', 'desc') ->top(50) ->skip(10); $response = SapB1::odataQuery('BusinessPartners', $query); $customers = $response->json('value');
Supported Operators
The where and orWhere methods support a variety of operators:
| Operator | Description | Example |
|---|---|---|
=, eq |
Equal | ->where('CardType', '=', 'cCustomer') |
!=, ne |
Not Equal | ->where('Status', '!=', 'Inactive') |
>, gt |
Greater Than | ->where('Balance', '>', 1000) |
>=, ge |
Greater Than or Equal | ->where('Stock', '>=', 10) |
<, lt |
Less Than | ->where('DocTotal', '<', 500) |
<=, le |
Less Than or Equal | ->where('Discount', '<=', 15) |
contains |
String Contains | ->where('CardName', 'contains', 'Shop') |
startswith |
String Starts With | ->where('ItemCode', 'startswith', 'A') |
endswith |
String Ends With | ->where('Address', 'endswith', 'USA') |
in |
In Array | ->where('GroupCode', 'in', [1, 2, 5]) |
notin |
Not In Array | ->where('Country', 'notin', ['US', 'CA']) |
between |
Between two values | ->where('DocDate', 'between', ['2024-01-01', '2024-01-31']) |
For very specific or complex filters that are not covered by the operators above, you can still pass a Filter instance directly: ->where(new Raw("substring(CardName, 1, 3) eq 'ABC'"))
C. Custom SML Request Example
// Custom SML endpoint, custom headers $response = SapB1::withHeaders(['X-Company-Context' => 'VENEZUELA']) ->get('/sml.svc/ItemsWithStock', [ 'warehouse'=> 'CABUDARE01' ]); $data = $response->json();
D. File Uploads and Custom Requests
For scenarios like file uploads or other complex requests that are not covered by the standard methods, you can use the sendRequestWithCallback method. This gives you direct access to the configured HTTP client instance while still benefiting from the automatic re-login logic.
use BlockshiftNetwork\SapB1Client\Facades\SapB1; $response = SapB1::sendRequestWithCallback(function ($httpClient) { return $httpClient ->attach('my_file', file_get_contents('/path/to/file.pdf'), 'file.pdf') ->post('Attachments2'); });
E. POST, PATCH, DELETE Requests
// POST example $newCustomer = [ 'CardCode' => 'C2024', 'CardName' => 'Beta Tech VZLA' ]; $created = SapB1::post('BusinessPartners', $newCustomer); // PATCH example $body = ['CardName' => 'New Beta Tech']; $update = SapB1::patch("BusinessPartners('C2024')", $body); // DELETE example $delete = SapB1::delete("BusinessPartners('C2024')");
F. Concurrent Requests with Pool
Execute multiple requests concurrently for better performance:
use BlockshiftNetwork\SapB1Client\Facades\SapB1; $responses = SapB1::pool(function ($pool) { return [ $pool->as('items')->get('Items', ['$top' => 10]), $pool->as('partners')->get('BusinessPartners', ['$top' => 10]), $pool->as('warehouses')->get('Warehouses'), $pool->as('orders')->get('Orders', ['$top' => 5]), ]; }); // Access responses by their keys $items = $responses['items']->json('value'); $partners = $responses['partners']->json('value'); $warehouses = $responses['warehouses']->json('value'); $orders = $responses['orders']->json('value');
You can also use POST, PUT, PATCH, DELETE in pool:
$responses = SapB1::pool(function ($pool) { return [ $pool->as('create')->post('BusinessPartners', ['CardCode' => 'C001', 'CardName' => 'New Customer']), $pool->as('update')->patch("Items('A001')", ['ItemName' => 'Updated Item']), $pool->as('fetch')->get('Orders', ['$top' => 1]), ]; });
G. Explicit Logout
SapB1::logout();
Testing
composer test
Credits
License
The MIT License (MIT). Please see License File for more information.