picqer / exact-php-client
Exact API的PHP客户端
Requires
- php: >=7.4.0
- ext-json: *
- guzzlehttp/guzzle: ~6.0|~7.0
Requires (Dev)
- phpunit/phpunit: ^8.5|^9.3
- dev-main
- v4.4.0
- v4.3.3
- v4.3.2
- v4.3.1
- v4.3.0
- v4.2.0
- v4.1.0
- v4.0.0
- v3.52.0
- v3.51.0
- v3.50.0
- v3.49.0
- v3.48.0
- v3.47.0
- v3.46.0
- v3.45.0
- v3.44.0
- v3.43.0
- v3.42.0
- 3.41.0
- v3.40.0
- v3.39.0
- v3.38.0
- v3.37.0
- v3.36.0
- v3.35.0
- v3.34.0
- v3.33.0
- v3.32.0
- v3.31.1
- v3.31.0
- v3.30.0
- v3.29.0
- v3.28.0
- v3.27.0
- v3.26.0
- v3.25.0
- v3.24.0
- v3.23.0
- v3.22.0
- v3.21.0
- v3.20.0
- v3.19.0
- v3.18.0
- v3.17.0
- v3.16.0
- v3.15.1
- v3.15.0
- v3.14.0
- v3.13.0
- v3.12.1
- v3.12.0
- v3.11.0
- v3.10.0
- v3.9.0
- v3.8.0
- v3.7.2
- v3.7.1
- v3.7.0
- v3.6.0
- v3.5.0
- v3.4.0
- v3.3.0
- v3.2.0
- v3.1.0
- v3.0.0
- v2.15.0
- v2.14.0
- v2.13.0
- v2.12.1
- v2.12.0
- v2.11.0
- v2.10.0
- v2.9.1
- v2.9.0
- v2.8.0
- v2.7.0
- v2.6.1
- v2.6.0
- v2.5.0
- v2.4.0
- v2.3.0
- v2.2.0
- v2.1.3
- v2.1.2
- v2.1.1
- v2.1.0
- v2.0.0
- 1.x-dev
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
This package is auto-updated.
Last update: 2024-09-07 15:48:34 UTC
README
PHP客户端库,用于Exact Online API。此客户端允许您与Exact Online集成,例如
- 创建并发送发票,
- 添加日记条目,
- 或上传收到的发票。
此客户端使用与Exact API相同的命名和约定,因此了解此客户端的最佳方法是查看Exact Online文档和API参考。
此库由Picqer创建和维护。我们正在寻找PHP开发者加入我们的团队!
Composer安装
可以通过Composer安装此PHP客户端。
composer require picqer/exact-php-client
用法
- 在Exact App Center设置应用程序以获取凭据
- 从您的应用程序授权集成
- 解析回调并完成连接设置
- 使用库进行操作
步骤1-3在设置时只需执行一次。
在Exact App Center设置应用程序以获取凭据
在Exact App Center设置应用程序以获取您的Client ID
和Client Secret
。您还需要设置正确的回调URL
以使OAuth工作。
从您的应用程序授权集成
以下是一个示例authorize()
函数。
$connection = new \Picqer\Financials\Exact\Connection(); $connection->setRedirectUrl('CALLBACK_URL'); // Same as entered online in the App Center $connection->setExactClientId('CLIENT_ID'); $connection->setExactClientSecret('CLIENT_SECRET'); $connection->redirectForAuthorization();
这会将用户重定向到Exact进行登录并授权您的集成。
解析回调并完成连接设置
Exact会重定向回您提供的回调URL
。回调将接收一个code
参数。这是OAuth的授权码。存储此代码。
创建一个新的连接到Exact,以便库可以交换代码并获取accesstoken
和refreshtoken
。accesstoken
是一个临时令牌,它允许您的应用程序和Exact之间进行通信。refreshtoken
是一个用于获取新的accesstoken
的令牌,它也会刷新refreshtoken
。库将为您处理所有这些。以下代码可以是一个通用的connect()
函数,它返回API连接。
$connection = new \Picqer\Financials\Exact\Connection(); $connection->setRedirectUrl('CALLBACK_URL'); $connection->setExactClientId('CLIENT_ID'); $connection->setExactClientSecret('CLIENT_SECRET'); if (getValue('authorizationcode')) { // Retrieves authorizationcode from database $connection->setAuthorizationCode(getValue('authorizationcode')); } if (getValue('accesstoken')) { // Retrieves accesstoken from database $connection->setAccessToken(unserialize(getValue('accesstoken'))); } if (getValue('refreshtoken')) { // Retrieves refreshtoken from database $connection->setRefreshToken(getValue('refreshtoken')); } if (getValue('expires_in')) { // Retrieves expires timestamp from database $connection->setTokenExpires(getValue('expires_in')); } // Make the client connect and exchange tokens try { $connection->connect(); } catch (\Exception $e) { throw new Exception('Could not connect to Exact: ' . $e->getMessage()); } // Save the new tokens for next connections setValue('accesstoken', serialize($connection->getAccessToken())); setValue('refreshtoken', $connection->getRefreshToken()); // Optionally, save the expiry-timestamp. This prevents exchanging valid tokens (ie. saves you some requests) setValue('expires_in', $connection->getTokenExpires()); // Optionally, set the lock and unlock callbacks to prevent multiple request for acquiring a new refresh token with the same refresh token. $connection->setAcquireAccessTokenLockCallback('CALLBACK_FUNCTION'); $connection->setAcquireAccessTokenUnlockCallback('CALLBACK_FUNCTION');
关于分部(管理)
默认情况下,库将使用用户的默认管理。这意味着当用户在Exact Online中切换管理时,库也将开始使用此管理。
速率限制
Exact使用每分钟和每天的速率限制。每天可以向每个公司发送的最大请求数量有限,为了防止超出限制,他们还实施了每分钟的限制。此PR将此信息存储在Connection
中,并添加了读取速率限制的方法,以便您可以根据您的应用程序适当处理这些限制。关于速率限制的Exact文档可以在以下位置找到:https://support.exactonline.com/community/s/knowledge-base#All-All-DNO-Simulation-gen-apilimits
如果您达到速率限制,将抛出带有代码429的ApiException
。此时,您可以确定是达到每分钟限制还是每天限制。如果您达到每分钟限制,请60秒后再试。如果您达到每天限制,请在每天重置后再试。
您可以在Connection
对象上使用以下方法,这些方法将在您的第一次API调用后返回限制(基于Exact的头信息)。
$connection->getDailyLimit(); // Retrieve your daily limit $connection->getDailyLimitRemaining(); // Retrieve the remaining amount of API calls for this day $connection->getDailyLimitReset(); // Retrieve the timestamp for when the limit will reset $connection->getMinutelyLimit(); // Retrieve your limit per minute $connection->getMinutelyLimitRemaining(); // Retrieve the amount of API calls remaining for this minute $connection->getMinutelyLimitReset(); // Retrieve the timestamp for when the minutely limit will reset
请注意,当您没有更多的分钟调用可用时,Exact只会发送分钟限制头信息。因此,在这种情况下,每日限制头信息将保持为0,直到分钟重置翻滚。
在达到分钟速率限制时,提供了对sleep
的基本支持。如果您启用“在分钟速率限制命中时等待”,则客户端将休眠,直到限制重置。不考虑每日限制。
$connection->setWaitOnMinutelyRateLimitHit(true);
使用库来做事情(示例)
// Optionally set administration, otherwise use the current administration of the user $connection->setDivision(123456); // Create a new account $account = new \Picqer\Financials\Exact\Account($connection); $account->AddressLine1 = 'Customers address line'; $account->AddressLine2 = 'Customer address line 2'; $account->City = 'Customer city'; $account->Code = 'Customer code'; $account->Country = 'Customer country'; $account->IsSales = 'true'; $account->Name = 'Customer name'; $account->Postcode = 'Customer postcode'; $account->Status = 'C'; $account->save(); // Add a product in Exact $item = new \Picqer\Financials\Exact\Item($connection); $item->Code = 'product code'; $item->CostPriceStandard = 2.50; $item->Description = 'product description'; $item->IsSalesItem = true; $item->SalesVatCode = 'VH'; $item->save(); // Retrieve an item by id $item = new \Picqer\Financials\Exact\Item($connection); $id = '097A82A9-6EF7-4EDC-8036-3F7559D9EF82'; $item->find($id); // List items $item = new \Picqer\Financials\Exact\Item($connection); $item->get(); // List items with filter (using a filter always returns a collection) and loop through the result $item = new \Picqer\Financials\Exact\Item($connection); $items = $item->filter("Code eq '$item->Code'"); // Uses filters as described in Exact API docs (odata filters) foreach($items as $itemObject){ $attrs = (array) $itemObject->attributes(); // Turns the endpoint properties into an array $picture = $itemObject->download(); // Fetches an image string instead of the url // Do something with $attrs and or $picture, e.g. imagecreatefromstring($picture) } // Create new invoice with invoice lines $invoiceLines[] = [ 'Item' => $item->ID, 'Quantity' => 1, 'UnitPrice' => $item->CostPriceStandard ]; $salesInvoice = new \Picqer\Financials\Exact\SalesInvoice($connection); $salesInvoice->InvoiceTo = $account->ID; $salesInvoice->OrderedBy = $account->ID; $salesInvoice->YourRef = 'Invoice reference'; $salesInvoice->SalesInvoiceLines = $invoiceLines; $salesInvoice->save(); // Print and email the invoice $printedInvoice = new \Picqer\Financials\Exact\PrintedSalesInvoice($connection); $printedInvoice->InvoiceID = $salesInvoice->InvoiceID; $printedInvoice->SendEmailToCustomer = true; $printedInvoice->SenderEmailAddress = "from@example.com"; $printedInvoice->DocumentLayout = "401f3020-35cd-49a2-843a-d904df0c09ff"; $printedInvoice->ExtraText = "Some additional text"; $printedInvoice->save();
使用生成器以防止内存溢出
此包允许您使用PHP 生成器与Exact API交互。当您需要一次性加载到内存中的大数据集时,这可能很有用。
$item = new \Picqer\Financials\Exact\Item($connection); $item->getAsGenerator(); $item->filterAsGenerator('IsWebshopItem eq 1');
连接到荷兰以外的其他Exact国家
根据Exact开发者指南选择正确的基地址
$connection = new \Picqer\Financials\Exact\Connection(); $connection->setRedirectUrl('CALLBACK_URL'); $connection->setExactClientId('CLIENT_ID'); $connection->setExactClientSecret('CLIENT_SECRET'); $connection->setBaseUrl('https://start.exactonline.de');
检查src/Picqer/Financials/Exact以获取所有可用的实体。
Webhooks
可以通过WebhookSubscription实体管理webhook订阅。
对于验证传入的webhook调用,您可以使用Authenticatable特性。将认证方法与完整的JSON请求以及Exact提供的Webhook secret一起提供,它将返回true或false。
故障排除
'Picqer\Financials\Exact\ApiException'异常信息为'错误400:请向查询字符串添加一个$select或$a top=1语句'。
在特定情况下,遗憾的是Exact API文档中没有记录这一点,这是一个要求。可能是为了防止请求过多。遇到此错误时,您必须添加一个select或top。Select用于提供您想要提取的字段列表,$top=1将结果限制为一条项目。
示例
仅返回EntryID和FinancialYear。
$test = new \Picqer\Financials\Exact\GeneralJournalEntry($connection); var_dump($test->filter('', '', 'EntryID, FinancialYear'));
$top=1添加如下所示
$test = new \Picqer\Financials\Exact\GeneralJournalEntry($connection); var_dump($test->filter('', '', '', ['$top'=> 1]));
认证错误
'致命错误:未捕获的异常:无法连接到Exact:客户端错误:POST https://start.exactonline.nl/api/oauth2/token返回400 Bad Request响应:Bad Request in /var/www/html/oauth_call_connect.php:61 栈跟踪:#0 {main} 在/var/www/html/oauth_call_connect.php的第61行抛出`'
此错误发生是因为您在重定向URL中获得的代码仅对一次调用有效。当您再次用“已使用”的代码调用认证过程时,您将得到这个错误。请确保您只使用Exact Online提供的代码一次来获取访问令牌。
代码示例
例如查看: example/example.php
Guzzle版本
从v3开始支持Guzzle 6和7。对于Guzzle 3,请使用v1。
待办事项
- 当前实体不包含所有可用属性。如果您需要它们,请自由提交一个带有添加或扩展实体的PR。使用greasemonkey或tampermonkey中的
userscript.js
生成一致和完整的实体。