ktr/business-central-sdk 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

ktr/business-central-sdk

Composer 安装命令:

composer require ktr/business-central-sdk

包简介

Laravel SDK for Microsoft Business Central - Connect to Business Central web services with elegant model-based API

README 文档

README

Latest Version on Packagist Total Downloads Tests

A modern Laravel SDK for Microsoft Dynamics 365 Business Central. Connect to Business Central's web services with an elegant, Laravel-style API that feels right at home in your Laravel application.

Why This Package?

Building integrations with Microsoft Business Central can be complex and time-consuming. This SDK simplifies the entire process by providing:

  • Laravel-Native Integration - Feels like native Laravel code with familiar query builder patterns
  • Three Flexible APIs - Choose between HTTP Client macros, Facades, or Eloquent-style Models
  • Comprehensive Coverage - Access 85+ Business Central entities (Customers, Sales Orders, Items, Invoices, and more)
  • Modern PHP - Built for PHP 8.2+ and Laravel 11+
  • Type-Safe - Full PHPDoc annotations for IDE autocompletion
  • OAuth2 Authentication - Handles token management and caching automatically
  • OData Query Builder - Powerful filtering, sorting, expanding, and pagination

Features

Model-Based API - Eloquent-like models for all Business Central entities ✅ Query Builder - Intuitive filtering with where(), whereIn(), whereContains(), and more ✅ Relationship Expansion - Eager load related data with expand()Pagination Support - Built-in take(), skip(), lazy(), and all() methods ✅ HTTP Client Macro - Use Http::businessCentral() for quick API calls ✅ Facade Support - Simple BusinessCentral::get() / ::post() interface ✅ Automatic Token Management - OAuth2 tokens cached and refreshed automatically ✅ Laravel 11 & 12 Support - Tested on PHP 8.2 and 8.3

Requirements

  • PHP 8.2 or higher
  • Laravel 11.0 or higher

Installation

Install the package via Composer:

composer require ktr/business-central-sdk

Configuration

Add your Business Central credentials to your .env file:

BUSINESS_CENTRAL_CLIENT_ID=your-client-id
BUSINESS_CENTRAL_CLIENT_SECRET=your-client-secret
BUSINESS_CENTRAL_TENANT=your-tenant-id
BUSINESS_CENTRAL_ENVIRONMENT=production
BUSINESS_CENTRAL_COMPANY=your-company-id

Getting Your Credentials

  1. Register your app in Azure Portal
  2. Create an App Registration with API permissions for Business Central
  3. Generate a client secret
  4. Note your Tenant ID from Azure AD
  5. Find your Company ID and Environment from Business Central

Tip: For sandbox testing, set BUSINESS_CENTRAL_ENVIRONMENT=sandbox

Usage

This SDK provides three different APIs to fit your coding style. All examples below accomplish the same task - choose the one that feels best for your project.

1. Model-Based API (Recommended)

The Model API provides an Eloquent-like experience with full IDE autocompletion:

use Ktr\BusinessCentral\Models\ApiV20\SalesOrders;
use Ktr\BusinessCentral\Models\ApiV20\SalesOrderLines;
use Ktr\BusinessCentral\Models\ApiV20\Customers;
use Ktr\BusinessCentral\Models\ApiV20\Items;

// Create a sales order
$order = SalesOrders::create([
    'customerId' => '{customer-id}',
    'shipToName' => 'John Doe',
    'shipToAddress' => '123 Main St',
    'salesOrderLines' => [
        [
            'lineType' => 'Item',
            'itemId' => '{item-id}',
            'quantity' => 5,
            'unitPrice' => 29.99
        ]
    ]
]);

// Query with filters
$orders = SalesOrders::query()
    ->where('customerId', '{customer-id}')
    ->where('totalAmount', '>', 1000)
    ->orderBy('orderDate', 'desc')
    ->take(10)
    ->get();

// Select specific fields
$customer = Customers::select('id', 'displayName', 'email', 'phoneNumber')
    ->where('number', 'C-001')
    ->first();

// Expand related data
$order = SalesOrders::select('number', 'customerId', 'totalAmount')
    ->where('number', 'SO-001')
    ->expand(SalesOrderLines::class) // Load order lines
    ->first();

// Access expanded data
echo $order->number; // SO-001
echo $order->salesOrderLines[0]->quantity; // 5

// Update a record
$customer->email = 'newemail@example.com';
$customer->phoneNumber = '+1-555-0123';
$customer->save();

// Delete a record
$order->delete();

2. HTTP Client Macro

For quick, one-off API calls without models:

use Illuminate\Support\Facades\Http;

// Create a sales order
$order = Http::businessCentral()->post('salesOrders', [
    'customerId' => '{customer-id}',
    'shipToName' => 'Jane Smith',
    'salesOrderLines' => [
        [
            'lineType' => 'Item',
            'itemId' => '{item-id}',
            'quantity' => 3,
            'unitPrice' => 49.99
        ]
    ]
]);

// Get customers with query parameters
$customers = Http::businessCentral()->get('customers', [
    '$filter' => "city eq 'New York'",
    '$select' => 'id,displayName,email',
    '$top' => 20
]);

// Update with PATCH
$response = Http::businessCentral()->patch("customers('{id}')", [
    'phoneNumber' => '+1-555-9999'
]);

3. Facade API

Clean and simple for straightforward API interactions:

use Ktr\BusinessCentral\Facades\BusinessCentral;

// Create a customer
$customer = BusinessCentral::post('customers', [
    'displayName' => 'Acme Corporation',
    'email' => 'contact@acme.com',
    'phoneNumber' => '+1-555-1234',
    'addressLine1' => '456 Business Ave',
    'city' => 'San Francisco',
    'state' => 'CA',
    'postalCode' => '94102'
]);

// Get all items
$items = BusinessCentral::get('items');

// Get with filters
$items = BusinessCentral::get('items', [
    '$filter' => "type eq 'Inventory' and unitPrice gt 100",
    '$orderby' => 'displayName asc'
]);

Query Builder Examples

The Model API includes a powerful query builder with OData support:

Basic Filtering

use Ktr\BusinessCentral\Models\ApiV20\Items;

// Simple where clause
$items = Items::where('type', 'Inventory')->get();

// Multiple conditions
$items = Items::query()
    ->where('type', 'Inventory')
    ->where('unitPrice', '>', 50)
    ->where('blocked', false)
    ->get();

// Or conditions
$items = Items::query()
    ->where('type', 'Inventory')
    ->orWhere('type', 'Service')
    ->get();

Advanced Filtering

// Contains search
$customers = Customers::whereContains('displayName', 'Tech')->get();

// Starts with
$customers = Customers::whereStartsWith('displayName', 'Acme')->get();

// Ends with
$items = Items::whereEndsWith('number', '-X')->get();

// In clause
$customers = Customers::whereIn('city', ['New York', 'Los Angeles', 'Chicago'])->get();

// Date filtering
$orders = SalesOrders::whereDateTime('orderDate', '>=', now()->subDays(30))->get();

// Complex grouped conditions
$items = Items::query()
    ->where(function($query) {
        $query->where('type', 'Inventory')
              ->where('unitPrice', '>', 100);
    })
    ->orWhere(function($query) {
        $query->where('type', 'Service')
              ->where('unitCost', '<', 50);
    })
    ->get();

Selecting Fields

// Select specific fields only
$customers = Customers::select('id', 'displayName', 'email')
    ->get();

// Select with filtering
$items = Items::select('id', 'number', 'displayName', 'unitPrice')
    ->where('type', 'Inventory')
    ->orderBy('displayName')
    ->get();

Expanding Relationships

use Ktr\BusinessCentral\Models\ApiV20\SalesInvoices;
use Ktr\BusinessCentral\Models\ApiV20\SalesInvoiceLines;

// Expand related entities
$invoice = SalesInvoices::query()
    ->expand(SalesInvoiceLines::class)
    ->first();

// Multiple expands
$order = SalesOrders::query()
    ->expand(SalesOrderLines::class, 'customer', 'shipmentMethod')
    ->where('number', 'SO-001')
    ->first();

Sorting

// Order by single field
$customers = Customers::orderBy('displayName', 'asc')->get();

// Order by multiple fields
$items = Items::query()
    ->orderBy('type', 'asc')
    ->orderBy('unitPrice', 'desc')
    ->get();

Pagination

// Simple pagination
$items = Items::take(10)->get(); // First 10 items

// Skip and take
$items = Items::skip(20)->take(10)->get(); // Items 21-30

// Lazy loading for large datasets (memory efficient)
Items::lazy(1000)->each(function ($item) {
    // Process each item without loading all into memory
    echo $item->displayName;
});

// Get all records (uses lazy loading internally)
$allItems = Items::all();

Finding Records

// Find by ID
$customer = Customers::find('{customer-id}');

// First matching record
$customer = Customers::where('email', 'john@example.com')->first();

// Get all matching records
$customers = Customers::where('city', 'Boston')->get();

// Count records
$count = Customers::where('blocked', false)->count();

Data Type Handling

The query builder intelligently handles different data types to ensure correct OData formatting:

// String values - automatically quoted
Items::where('type', 'Inventory')->get();
// Generates: type eq 'Inventory'

// Numeric values - not quoted
Items::where('unitPrice', '>', 100)->get();
Items::where('quantity', 0)->get();
// Generates: unitPrice gt 100 and quantity eq 0

// Boolean values - not quoted
Items::where('blocked', false)->get();
Customers::where('taxLiable', true)->get();
// Generates: blocked eq false and taxLiable eq true

// DateTime/Carbon objects - auto-formatted to ISO 8601
Items::where('lastModifiedDateTime', '>=', Carbon::parse('2024-01-01'))->get();
// Generates: lastModifiedDateTime ge 2024-01-01T00:00:00.000Z

// Negative numbers work correctly
Customers::where('balanceDue', '<', 0)->get();
// Generates: balanceDue lt 0

// Real-world example: Items with inventory greater than zero
use Ktr\BusinessCentral\Models\ODataV4\ItemQuantities;

$items = ItemQuantities::query()
    ->where('Inventory', '>', 0)
    ->get();
// Generates: Inventory gt 0

Important Notes:

  • Numeric 0 is correctly handled as integer, not string '0'
  • Boolean false is distinct from integer 0
  • String values are automatically URL-encoded for OData compatibility
  • DateTime objects are automatically detected and formatted correctly

Available Models

This SDK provides access to 85+ Business Central entities. Here are the most commonly used:

Sales & Customers

  • Customers - Customer master data
  • SalesOrders - Sales orders
  • SalesOrderLines - Sales order line items
  • SalesInvoices - Posted sales invoices
  • SalesInvoiceLines - Sales invoice line items
  • SalesQuotes - Sales quotes
  • SalesShipments - Posted sales shipments
  • SalesCreditMemos - Sales credit memos

Purchasing & Vendors

  • Vendors - Vendor master data
  • PurchaseOrders - Purchase orders
  • PurchaseOrderLines - Purchase order line items
  • PurchaseInvoices - Posted purchase invoices
  • PurchaseInvoiceLines - Purchase invoice line items
  • PurchaseCreditMemos - Purchase credit memos

Inventory & Items

  • Items - Item master data
  • ItemCategories - Item categories
  • UnitsOfMeasure - Units of measure
  • InventoryPostingGroups - Inventory posting groups

Financial

  • Accounts - Chart of accounts
  • GeneralLedgerEntries - G/L entries
  • Currencies - Currency master data
  • CurrencyExchangeRates - Exchange rates
  • PaymentTerms - Payment terms
  • PaymentMethods - Payment methods
  • Dimensions - Financial dimensions
  • BankAccounts - Bank account master data

Journals

  • Journals - General journals
  • ItemJournals - Item journals
  • CustomerPaymentJournals - Payment journals
  • VendorPaymentJournals - Vendor payment journals

Reporting & Analysis

  • BalanceSheets - Balance sheet reports
  • IncomeStatements - Income statement reports
  • CashFlowStatements - Cash flow reports
  • AgedAccountsReceivables - AR aging reports
  • AgedAccountsPayables - AP aging reports
  • TrialBalances - Trial balance reports

Master Data

  • Employees - Employee records
  • Projects - Project/job cards
  • CountriesRegions - Countries and regions
  • TaxGroups - Tax groups
  • TaxAreas - Tax areas
  • Contacts - Contact information
  • CompanyInformation - Company details

Tip: All models are located in Ktr\BusinessCentral\Models\ApiV20 namespace and include full PHPDoc type hints for IDE autocompletion.

API Reference

For detailed information about available fields, filters, and operations for each entity, refer to the official Microsoft Business Central API v2.0 Documentation.

Real-World Examples

Example 1: Create a Complete Sales Order

use Ktr\BusinessCentral\Models\ApiV20\SalesOrders;
use Ktr\BusinessCentral\Models\ApiV20\Customers;
use Ktr\BusinessCentral\Models\ApiV20\Items;

// Find customer
$customer = Customers::where('number', 'C-001')->first();

// Find items
$item1 = Items::where('number', 'ITEM-001')->first();
$item2 = Items::where('number', 'ITEM-002')->first();

// Create order with multiple lines
$order = SalesOrders::create([
    'customerId' => $customer->id,
    'customerNumber' => $customer->number,
    'shipToName' => $customer->displayName,
    'shipToAddress' => $customer->addressLine1,
    'shipToCity' => $customer->city,
    'salesOrderLines' => [
        [
            'lineType' => 'Item',
            'itemId' => $item1->id,
            'quantity' => 10,
            'unitPrice' => $item1->unitPrice,
            'description' => $item1->displayName
        ],
        [
            'lineType' => 'Item',
            'itemId' => $item2->id,
            'quantity' => 5,
            'unitPrice' => $item2->unitPrice,
            'description' => $item2->displayName
        ]
    ]
]);

echo "Order created: {$order->number}";

Example 2: Generate Sales Report

use Ktr\BusinessCentral\Models\ApiV20\SalesInvoices;
use Carbon\Carbon;

// Get sales for last 30 days
$startDate = Carbon::now()->subDays(30);
$invoices = SalesInvoices::query()
    ->whereDateTime('orderDate', '>=', $startDate)
    ->select('id', 'number', 'customerId', 'totalAmountIncludingTax', 'orderDate')
    ->orderBy('orderDate', 'desc')
    ->get();

$totalRevenue = $invoices->sum('totalAmountIncludingTax');
$invoiceCount = $invoices->count();

echo "Total invoices: {$invoiceCount}\n";
echo "Total revenue: $" . number_format($totalRevenue, 2);

Example 3: Sync Inventory Levels

use Ktr\BusinessCentral\Models\ApiV20\Items;

// Get low stock items
$lowStockItems = Items::query()
    ->where('type', 'Inventory')
    ->where('inventory', '<', 10)
    ->select('id', 'number', 'displayName', 'inventory')
    ->orderBy('inventory', 'asc')
    ->get();

foreach ($lowStockItems as $item) {
    echo "{$item->displayName}: {$item->inventory} units in stock\n";

    // Your reorder logic here
    if ($item->inventory < 5) {
        // Send notification or create purchase order
    }
}

Example 4: Customer Management

use Ktr\BusinessCentral\Models\ApiV20\Customers;

// Create new customer
$customer = Customers::create([
    'displayName' => 'New Customer Inc.',
    'email' => 'contact@newcustomer.com',
    'phoneNumber' => '+1-555-0100',
    'addressLine1' => '789 Customer Blvd',
    'city' => 'Seattle',
    'state' => 'WA',
    'postalCode' => '98101',
    'countryCode' => 'US',
    'currencyCode' => 'USD',
    'blocked' => false,
    'taxLiable' => true
]);

// Update customer information
$customer->email = 'newemail@newcustomer.com';
$customer->creditLimit = 50000.00;
$customer->save();

// Find customers by city
$seattleCustomers = Customers::query()
    ->where('city', 'Seattle')
    ->where('blocked', false)
    ->select('displayName', 'email', 'phoneNumber')
    ->get();

Troubleshooting

Authentication Errors

If you receive authentication errors:

  1. Verify your credentials in .env
  2. Check that your Azure app has the correct API permissions
  3. Ensure your client secret hasn't expired
  4. Clear the token cache: php artisan cache:clear

API Limitations

  • Business Central API has rate limits - implement appropriate throttling
  • Some entities are read-only (e.g., Posted Invoices)
  • Complex calculations may need to be done in Business Central AL code first

OData Query Syntax

This SDK uses OData v4 query conventions. If you encounter filter errors:

  • Use single quotes for string values: where('city', 'Boston')
  • Use proper operators: eq, ne, gt, ge, lt, le
  • Check the OData documentation for advanced syntax

Getting Help

Testing

Run the test suite:

composer test

Run tests with coverage:

composer test-coverage

Check code style:

composer pint-test

Fix code style:

composer pint

Changelog

Please see CHANGELOG for recent changes and version history.

Contributing

We welcome contributions! Please see CONTRIBUTING for details on how to contribute to this project.

Security

If you discover any security-related issues, please email john@ktr.fo instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

Built with ❤️ for the Laravel community

ktr/business-central-sdk 适用场景与选型建议

ktr/business-central-sdk 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 346 次下载、GitHub Stars 达 0, 最近一次更新时间为 2024 年 07 月 12 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「sdk」 「laravel」 「microsoft」 「Dynamics」 「ktr」 「business-central-sdk」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 ktr/business-central-sdk 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 ktr/business-central-sdk 我们能提供哪些服务?
定制开发 / 二次开发

基于 ktr/business-central-sdk 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 346
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 15
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 1
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-07-12