fakturoid/fakturoid-php

Fakturoid PHP 库

v2.1.0 2024-07-11 09:47 UTC

This package is auto-updated.

Last update: 2024-09-16 13:00:47 UTC


README

Tests

PHP 库用于 Fakturoid.cz。请参阅 API 获取更多文档。强烈建议为测试 API 和使用独立用户(通过“设置 > 用户帐户”创建)进行生产使用创建新账户。

内容

版本

安装

推荐的安装方法是使用 Composer

composer require fakturoid/fakturoid-php

库需要 PHP 8.1(或更高版本)以及 ext-jsonnyholm/psr7psr/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']);

搜索库存项(在 namearticle_numbersku 中搜索)

$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
}

常见问题

开发

  • 要运行测试,PHPUnit需要ext-dom扩展(通常在Debian上为php-xml包)和ext-mbstring扩展(php-mbstring包)。
  • 如果您想生成代码覆盖率(并且有更智能的堆栈跟踪),则需要Xdebugphp-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