fakturoid / fakturoid-php
Fakturoid PHP 库
Requires
- php: >=8.1
- ext-json: *
- nyholm/psr7: ^1.8
- psr/http-client: ^1.0
Requires (Dev)
- ext-dom: *
- ext-mbstring: *
- guzzlehttp/guzzle: ^7.8
- phpstan/phpstan: ^1.11
- phpunit/phpunit: ^10.5
- rector/rector: ^1.0
- squizlabs/php_codesniffer: ^3.7
Suggests
- guzzlehttp/guzzle: for usage with guzzle
- symfony/http-client: for usage with symfony
README
PHP 库用于 Fakturoid.cz。请参阅 API 获取更多文档。强烈建议为测试 API 和使用独立用户(通过“设置 > 用户帐户”创建)进行生产使用创建新账户。
内容
版本
安装
推荐的安装方法是使用 Composer
composer require fakturoid/fakturoid-php
库需要 PHP 8.1(或更高版本)以及 ext-json
、nyholm/psr7
和 psr/http-client
扩展。
OAuth 2.0 授权
授权码流
使用 OAuth 进行授权涉及多个步骤。我们使用从开发者门户获得的数据作为客户端 ID 和客户端密钥(设置 → 连接其他应用 → 应用开发者 OAuth 2.0)。
首先,我们提供一个用户输入其登录信息的 URL 地址。我们使用以下方法获取此地址
$fManager = new \Fakturoid\FakturoidManager( new ClientInterface(), // PSR-18 client '{fakturoid-client-id}', '{fakturoid-client-secret}', 'PHPlib <your@email.cz>', null, '{your-redirect-uri}' ); echo '<a href="' . $fManager->getAuthenticationUrl() . '">Link</a>';
输入登录信息后,用户将被重定向到指定的重定向 URI,并带有我们获取其凭据的代码。我们按以下方式处理代码
$fManager->requestCredentials($_GET['code']);
凭据现在已建立在与对象实例相关联的对象中,我们可以向 Fakturoid API 发送查询。凭据可以通过两种方式获取。直接从对象中获取凭据
$credentials = $fManager->getCredentials(); echo $credentials->toJson();
客户端凭据流
$fManager = new \Fakturoid\FakturoidManager( new ClientInterface(), // PSR-18 client '{fakturoid-client-id}', '{fakturoid-client-secret}', 'PHPlib <your@email.cz>' ); $fManager->authClientCredentials();
使用凭据回调处理凭据
回调函数的工作方式是库在凭据更改时调用回调函数。这很有用,因为令牌在过期后自动刷新。
$fManager->setCredentialsCallback(new class implements \Fakturoid\Auth\CredentialCallback { public function __invoke(?\Fakturoid\Auth\Credentials $credentials = null): void { // Save credentials to database or another storage } });
使用方法
将凭据设置到 Fakturoid 管理器
如果您运行的是多租户应用程序或并行处理文档的应用程序,您需要正确设置凭据。每次获取新的访问令牌时,之前的令牌都会被无效化。为此,有 AuthProvider::setCredentials()
和 CredentialCallback
。
$fManager = new \Fakturoid\FakturoidManager( new ClientInterface(), // PSR-18 client '{fakturoid-client-id}', '{fakturoid-client-secret}', 'PHPlib <your@email.cz>' ); // restore credentials from storage $credentials = new \Fakturoid\Auth\Credentials( 'refreshToken', 'accessToken', (new DateTimeImmutable())->modify('-2 minutes'), \Fakturoid\Enum\AuthTypeEnum::AUTHORIZATION_CODE_FLOW // or \Fakturoid\Enum\AuthTypeEnum:CLIENT_CREDENTIALS_CODE_FLOW ); $fManager->getAuthProvider()->setCredentials($credentials); $fManager->setCredentialsCallback(new class implements \Fakturoid\Auth\CredentialCallback { public function __invoke(?\Fakturoid\Auth\Credentials $credentials = null): void { // Save credentials to database or another storage } });
切换账户
$fManager = new \Fakturoid\FakturoidManager( new ClientInterface(), // PSR-18 client '{fakturoid-client-id}', '{fakturoid-client-secret}', 'PHPlib <your@email.cz>' '{fakturoid-account-slug}', ); $fManager->authClientCredentials(); $fManager->getBankAccountsProvider()->list(); // switch account and company $fManager->setAccountSlug('{fakturoid-account-slug-another}'); $fManager->getBankAccountsProvider()->list();
基本使用
require __DIR__ . '/vendor/autoload.php'; $fManager = new \Fakturoid\FakturoidManager( new ClientInterface(), // PSR-18 client '{fakturoid-client-id}', '{fakturoid-client-secret}', 'PHPlib <your@email.cz>' ); $fManager->authClientCredentials(); // get current user $user = $fManager->getUsersProvider()->getCurrentUser(); $fManager->setAccountSlug($user->getBody()->accounts[0]->slug); // or you can set account slug manually $fManager->setAccountSlug('{fakturoid-account-slug}'); // create subject $response = $fManager->getSubjectsProvider()->create(['name' => 'Firma s.r.o.', 'email' => 'aloha@pokus.cz']); $subject = $response->getBody(); // create invoice with lines $lines = [['name' => 'Big sale', 'quantity' => 1, 'unit_price' => 1000]]; $response = $fManager->getInvoicesProvider()->create(['subject_id' => $subject->id, 'lines' => $lines]); $invoice = $response->getBody(); // send by mail $fManager->getInvoicesProvider()->createMessage($invoice->id, ['email' => 'aloha@pokus.cz']); // to mark invoice as paid and send thank you email $fManager->getInvoicesProvider()->createPayment($invoice->id, ['paid_on' => (new \DateTime())->format('Y-m-d'), 'send_thank_you_email' => true]); // lock invoice (other fire actions are described in the API documentation) $fManager->getInvoicesProvider()->fireAction($invoice->id, 'lock');
下载发票 PDF
$invoiceId = 123; $response = $fManager->getInvoicesProvider()->getPdf($invoiceId); $data = $response->getBody(); file_put_contents("{$invoiceId}.pdf", $data);
如果您在创建发票后立即调用 $fManager->getInvoicesProvider()->getPdf()
,您将获得状态码 204
(无内容
),正文为空,这意味着发票 PDF 尚未生成,您应该稍后再试。
更多详细信息请参阅 API 文档。
$invoiceId = 123; // This is just an example, you may want to do this in a background job and be more defensive. while (true) { $response = $fManager->getInvoicesProvider()->getPdf($invoiceId); if ($response->getStatusCode() == 200) { $data = $response->getBody(); file_put_contents("{$invoiceId}.pdf", $data); break; } sleep(1); }
使用 custom_id
您可以使用 custom_id
属性将应用程序记录 ID 存储到我们的记录中。可以通过特定记录来过滤发票和主题
$response = $fManager->getSubjectsProvider()->list(['custom_id' => '10']); $subjects = $response->getBody(); $subject = null; if (count($subjects) > 0) { $subject = $subjects[0]; }
就主题而言,Fakturoid 不会允许您创建具有相同 custom_id
的两个记录,因此您不必担心多个结果。另外请注意,该字段总是返回字符串。
库存项资源
要获取所有库存项
$fManager->getInventoryItemsProvider()->list();
通过特定 SKU 代码或文章号过滤库存项
$fManager->getInventoryItemsProvider()->list(['sku' => 'SKU1234']); $fManager->getInventoryItemsProvider()->list(['article_number' => 'IAN321']);
搜索库存项(在 name
、article_number
和 sku
中搜索)
$fManager->getInventoryItemsProvider()->listArchived(['query' => 'Item name']);
获取所有存档库存项
$fManager->getInventoryItemsProvider()->listArchived();
获取单个库存项
$fManager->getInventoryItemsProvider()->get($inventoryItemId);
创建库存项
$data = [ 'name' => 'Item name', 'sku' => 'SKU12345', 'track_quantity' => true, 'quantity' => 100, 'native_purchase_price' => 500, 'native_retail_price' => 1000 ]; $fManager->getInventoryItemsProvider()->create($data)
更新库存项
$fManager->getInventoryItemsProvider()->update($inventoryItemId, ['name' => 'Another name']);
存档库存项
$fManager->getInventoryItemsProvider()->archive($inventoryItemId);
恢复库存项
$fManager->getInventoryItemsProvider()->unArchive($inventoryItemId);
删除库存项
$fManager->getInventoryItemsProvider()->delete($inventoryItemId);
库存移动资源
获取所有库存项的所有库存移动
$fManager->getInventoryMovesProvider()->list()
获取单个库存项的库存移动
$fManager->getInventoryMovesProvider()->list(['inventory_item_id' => $inventoryItemId]);
获取单个库存移动
$fManager->getInventoryMovesProvider()->get($inventoryItemId, $inventoryMoveId);
创建入库库存移动
$fManager->getInventoryMovesProvider()->create( $inventoryItemId, [ 'direction' => 'in', 'moved_on' => '2023-01-12', 'quantity_change' => 5, 'purchase_price' => '249.99', 'purchase_currency' => 'CZK', 'private_note' => 'Bought with discount' ] )
创建出库库存移动
$fManager->getInventoryMovesProvider()->create( $inventoryItemId, [ 'direction' => 'out', 'moved_on' => '2023-01-12', 'quantity_change' => '1.5', 'retail_price' => 50, 'retail_currency' => 'EUR', 'native_retail_price' => '1250' ] );
更新库存移动
$fManager->getInventoryMovesProvider()->update($inventoryItemId, $inventoryMoveId, ['moved_on' => '2023-01-11']);
删除库存移动
$fManager->getInventoryMovesProvider()->update($inventoryItemId, $inventoryMoveId);
处理错误
当状态为4xx
时,库将抛出Fakturoid\Exception\ClientErrorException
,当状态为5xx
时,将抛出Fakturoid\Exception\ServerErrorException
。您可以通过调用getCode()
或getResponse()->getBody()
来获取响应代码和响应体。
try { $response = $fManager->getSubjectsProvider()->create(['name' => '', 'email' => 'aloha@pokus.cz']); $subject = $response->getBody(); } catch (\Fakturoid\Exception\ClientErrorException $e) { $e->getCode(); // 422 $e->getMessage(); // Unprocessable entity $e->getResponse()->getBody()->getContents(); // '{"errors":{"name":["je povinná položka","je příliš krátký/á/é (min. 2 znaků)"]}}' } catch (\Fakturoid\Exception\ServerErrorException $e) { $e->getCode(); // 503 $e->getMessage(); // Fakturoid is in read only state }
常见问题
- 如果遇到问题,请联系我们的发票机器人podpora@fakturoid.cz。
开发
- 要运行测试,PHPUnit需要
ext-dom
扩展(通常在Debian上为php-xml
包)和ext-mbstring
扩展(php-mbstring
包)。 - 如果您想生成代码覆盖率(并且有更智能的堆栈跟踪),则需要Xdebug(
php-xdebug
包),它将自动将其钩入PHPUnit。
Docker
$ docker-compose up -d $ docker-compose exec php composer install $ docker-compose exec php bash
测试
这两个命令做的是同一件事,但第二个版本要快一些。
$ docker-compose exec php composer test:phpunit $ docker-compose exec php composer coverage:phpunit # or locally $ composer test:phpunit $ composer coverage:phpunit
代码风格检查
这两个命令做的是同一件事,但第二个版本看起来输出更智能。
$ docker-compose exec php composer check:cs # or locally $ composer check:cs
检查所有 PR 的要求
$ docker-compose exec php composer check:all # or locally $ composer check:all
或者您可以自动修复CS和Rector问题。
$ docker-compose exec php composer fix:all # or locally $ composer fix:all