freee/freee-accounting-sdk

此包已被废弃,不再维护。未建议替代包。

会计freee PHP SDK


README

会计freee PHP SDK

会计freee API 的 PHP SDK。

关于会计freee API的详细信息,请参阅会计API概要 | freee开发者社区

此SDK根据不同的版本,内部使用的API版本可能不同。

  • 2.0.0及以后 - 支持会计freee API的新API版本(v2020-06-15)。
  • 2.0.0以下 - 使用会计freee API的旧API版本。由于旧API的终止提供,2020年12月以后将不可用。

目录

教程

以下将介绍使用会计freee PHP SDK的步骤。

前提条件

在利用此SDK之前,请确认以下事项。

  • 拥有freee本体账户
  • 理解PHP基础知识

freee本体账户是后续freee应用商店应用程序注册所必需的。

关于freee API,请参阅教程指南

关于PHP基础知识,请参阅PHP: PHP手册 - Manual

运行环境

此存储库针对以下环境进行设计。

  • PHP 7.2以上
  • composer

此存储库针对PHP 7.1以上进行设计。如果您没有PHP运行环境,请参考PHP: 安装和配置 - Manual准备环境。同时,请从composer安装composer。

freee应用商店应用程序注册

为了获取本SDK中使用的client_idclient_secret,请在freee应用商店的开发者页面中注册应用程序。

请参考教程 | freee应用商店进行应用程序注册。

为了与此SDK连接,请将回调URL设置为http://localhost:8000/auth-callback

示例执行方法

WebApp的示例

WebApp示例的运行环境

示例基于Laravel 7.x构建。在执行示例时,除了上述运行环境外,还需准备以下内容。

  • PHP 7.2.5以上
    • BCMath PHP扩展
    • Ctype PHP扩展
    • JSON PHP扩展
    • Mbstring PHP扩展
    • OpenSSL PHP扩展
    • PDO PHP扩展
    • Tokenizer PHP扩展
    • XML PHP扩展
  • composer
  • Node.js(UI生成时使用npm
WebApp示例的运行环境(Docker)

此外,还包括了适用于Docker的Dockerfile和docker-compose.yaml,以便于使用Docker。在需要时,请参考以下内容。

cd <本リポジトリのクローン先ディレクトリ>
cd samples
docker-compose build
docker-compose up -d
docker exec -it samples_webapp_1 /bin/bash

在上述操作后,您可以在docker容器的/usr/src/app目录中进行登录。此目录是挂载了本存储库的samples/BasicWebApp目录。请根据以下步骤适当修改并使用。

WebApp 的示例执行步骤

克隆此存储库后,在 PowerShell 或 bash 等终端中进入目录。

cd <本リポジトリのクローン先ディレクトリ>
cd samples/BasicWebApp
cp .env.example .env

打开复制的 .env 文件,设置以下部分。<client_id><client_secret> 分别为从 freee 应用商店中的应用程序注册 获得的值。

FREEE_ACCOUNTING_CLIENT_ID=<client_id>
FREEE_ACCOUNTING_CLIENT_SECRET=<client_secret>

在终端中执行以下操作。

# パッケージをインストールする
composer install

# Application encryption key を発行する
php artisan key:generate

# sqlite ファイルを作成し、マイグレーションを実行する
touch database/database.sqlite
php artisan migrate

# Laravel の内蔵サーバーを実行する
php artisan serve

# ※ Docker で動かしている場合は、下記のように host を指定する
php artisan serve --host 0.0.0.0

打开 http://localhost:8000,如果页面可以打开,则表示启动正常。

点击右上角的“登录”,则会对 freee 应用商店中的应用程序进行身份验证。首次会显示“开始应用程序连接”的屏幕,请确认内容并点击“允许”按钮。

成功验证后,将被重定向到 http://localhost:8000/home。如果顶部栏中显示 freee 用户名,则表示成功。此外,选择用户名,然后从下拉菜单中选择“Me”,如果显示用户信息和交易信息,则表示已正确获取信息。

要停止内置服务器,请按 Ctrl + c。

Console 示例

Console 示例的执行环境 (Docker)

此外,还包括了适用于Docker的Dockerfile和docker-compose.yaml,以便于使用Docker。在需要时,请参考以下内容。

cd <本リポジトリのクローン先ディレクトリ>
cd samples
docker-compose build
docker-compose up -d
docker exec -it samples_console_1 /bin/bash

执行上述操作后,可以登录到 docker 容器的 /usr/src/app。此目录已挂载了本存储库的 samples/BasicConsole。请根据需要适当修改以下步骤。

Console 示例的执行步骤

克隆此存储库后,在 PowerShell 或 bash 等终端中进入目录。

cd <本リポジトリのクローン先ディレクトリ>
cd samples/BasicConsole
cp .env.example .env

打开复制的 .env 文件,设置以下部分。<client_id><client_secret> 分别为从 freee 应用商店中的应用程序注册 获得的值。

FREEE_ACCOUNTING_CLIENT_ID=<client_id>
FREEE_ACCOUNTING_CLIENT_SECRET=<client_secret>

在终端中执行以下操作。

# パッケージをインストールする
composer install

# php を interactive modeで実行する
php -a
php >require_once(__DIR__ . '/vendor/autoload.php');
php >$token = {対象のアクセストークン}
php >$cid = {対象の事業所ID}
php >$config = Freee\Accounting\Configuration::getDefaultConfiguration()->setAccessToken($token);
php >$partnersApiInstance = new Freee\Accounting\Api\PartnersApi(null, $config);
php >echo $partnersApiInstance->getPartners($cid);

SDK 的导入方法

在此部分中,描述了在 Laravel 中使用此 SDK 的方法,作为导入的参考。

首先,创建 Laravel 项目。如果要在现有项目中导入,请跳过。首先,创建 Laravel 项目,请根据 安装 Laravel 参考安装 Laravel。另外,如果使用前面提到的 Dockerfile,则已安装。

# Laravel のプロジェクトを新規作成し、そのディレクトリに移動する
laravel new sampleapp
cd sampleapp

# 確認のため、Laravel の内蔵サーバーを実行する
php artisan serve

# ※ Docker で動かしている場合は、下記のように host を指定する
php artisan serve --host 0.0.0.0

# 内蔵サーバーを停止するには、 Ctrl + c を押下します

将以下内容添加到 .env 中,并按照 WebApp 的示例执行步骤 中的说明设置 <client_id><client_secret>

FREEE_ACCOUNTING_CLIENT_ID=<client_id>
FREEE_ACCOUNTING_CLIENT_SECRET=<client_secret>

然后,将数据库设置更改为 sqlite。将 .env 编辑如下。DB_DATABASE 是指向项目内 database/database.sqlite 的绝对路径。请适当调整。

#DB_CONNECTION=mysql
DB_CONNECTION=sqlite
...
#DB_DATABASE=laravel
DB_DATABASE=/usr/src/app/database/database.sqlite

然后,创建 sqlite 文件并执行迁移。

# 自動作成されたマイグレーションファイルを削除する
rm database/migrations/2014_10_12_000000_create_users_table.php
# マイグレーションを作成する
php artisan make:migration create_users_table --create=users

编辑创建的迁移文件如下。

        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            // ↓↓ ここから ↓↓
            $table->unsignedBigInteger('freee_id')->unique();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('first_name')->nullable();
            $table->string('last_name')->nullable();
            $table->string('token')->nullable();
            $table->rememberToken();
            // ↑↑ ここまで編集 ↑↑
            $table->timestamps();
        });
# sqlite ファイルを作成し、マイグレーションを実行する
touch database/database.sqlite
php artisan migrate

编辑 app/User.php

    protected $fillable = [
        // ↓↓ ここから ↓↓
        // 'name', 'email', 'password',
        'name', 'email', 'freee_id', 'first_name', 'last_name', 'token'
        // ↑↑ ここまで編集 ↑↑
    ];

准备项目后,进行包的安装。本 SDK 的核心是会计 freee API,它使用 OAuth2 进行身份验证,因此还使用了 Laravel 官方包 Socialite

  • freee/freee-accounting-sdk: 本 SDK
  • socialiteproviders/generators: 生成 Socialite 的自定义提供者基础代码的包(参考: https://github.com/SocialiteProviders/Generators)
  • socialiteproviders/manager: 处理 Socialite 的自定义提供者的包
composer require freee/freee-accounting-sdk
composer require socialiteproviders/generators
composer require socialiteproviders/manager

然后,在 config/app.phpproviders 中添加以下内容,作为参考。

    'providers' => [
        // ... 中略 ...
        SocialiteProviders\Generators\GeneratorsServiceProvider::class,
        SocialiteProviders\Manager\ServiceProvider::class,
        // ... 中略 ...
    ],

使用 socialiteproviders/generators 的 artisan 命令创建基础代码。

# freee の OAuth2 認証を処理するコードを作成する
php artisan make:socialite FreeeAccounting --spec=oauth2 --authorize_url=https://accounts.secure.freee.co.jp/public_api/authorize --access_token_url=https://accounts.secure.freee.co.jp/public_api/token --user_details_url=https://api.freee.co.jp/api/1/users/me

# 作成したファイルを読み込む
composer dumpautoload

然后,准备认证页面。这次我们导入 laravel/ui 并使用其页面。有关详细信息,请参阅 Authentication - Laravel - The PHP Framework For Web Artisans

composer require laravel/ui
php artisan ui vue --auth
npm install && npm run dev

此时,routes/web.php 中已添加 Auth::routes();,设置了认证相关的路由。这次,我们不使用新注册和密码重置,因此进行以下编辑。

// Auth::routes();
Auth::routes([
    'register' => false,
    'reset' => false,
]);

通过这些操作,Laravel 内部具有用户数据的认证机制的基座已经建立。但是,会计 freee API 需要向 freee 进行身份验证和授权查询,因此需要进行更多更改。

首先,在 routes/web.php 中添加以下路由。

Route::get('login', 'Auth\LoginController@redirectToProvider')->name('login');
Route::get('auth-callback', 'Auth\LoginController@handleProviderCallback')->name('authCallback');

然后,修改配置值。首先,在 config/services.php 中添加以下内容。

<?php

return [

    // ... 中略 ...

    // ↓↓ ここから ↓↓
    'freeeaccounting' => [
        'client_id' => env('FREEE_ACCOUNTING_CLIENT_ID'),
        'client_secret' => env('FREEE_ACCOUNTING_CLIENT_SECRET'),
        'redirect' => 'http://localhost:8000/auth-callback',
    ],
    // ↑↑ ここまで編集 ↑↑
];

然后,稍微修改 SocialiteProviders 下的代码。

SocialiteProviders/src/FreeeAccounting/Provider.php

    protected function getUserByToken($token)
    {
        // ... 中略 ...

        // ↓↓ ここから ↓↓
        // return json_decode($response->getBody(), true);
        $body = json_decode($response->getBody(), true);
        return $body['user'];
        // ↑↑ ここまで編集 ↑↑
    }
    protected function mapUserToObject(array $user)
    {
        // ↓↓ ここから ↓↓
        $user['name'] = $user['last_name'] . ' ' . $user['first_name'];
        // ↑↑ ここまで追加 ↑↑

        return (new User())->setRaw($user)->map([
            'id'       => $user['id'],
            // 'nickname' => $user['username'],
            'name'     => $user['name'],
            'email'    => $user['email'],
            // 'avatar'   => $user['avatar'],
            // ↓↓ ここから ↓↓
            'display_name' => $user['display_name'],
            'first_name' => $user['first_name'],
            'last_name' => $user['last_name'],
            'first_name_kana' => $user['first_name_kana'],
            'last_name_kana' => $user['last_name_kana'],
            // ↑↑ ここまで追加 ↑↑
        ]);
    }

那么,接下来整理控制器。首先,编辑 app/Http/Auth/LoginController.php,使其能够对会计 freee API 进行登录。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
// ↓↓ ここから ↓↓
// use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use App\User;
// ↑↑ ここまで編集 ↑↑

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    // ↓↓ ここから ↓↓
    // use AuthenticatesUsers;
    // ↑↑ ここまで編集 ↑↑

    // ... 中略 ...

    // ↓↓ ここから ↓↓
    /**
     * Redirect the user to the Freee Accounting authentication page.
     *
     * @return \Illuminate\Http\Response
     */
    public function redirectToProvider()
    {
        return Socialite::driver('freeeaccounting')->redirect();
    }

    /**
     * Obtain the user information from Freee Accounting.
     *
     * @return \Illuminate\Http\Response
     */
    public function handleProviderCallback()
    {
        $user = Socialite::driver('freeeaccounting')->user();

        $loggedInUser = User::updateOrCreate(
            [
                'freee_id' => $user->id,
            ],
            [
                'name' => $user->name,
                'email' => $user->email,
                'first_name' => $user->first_name,
                'last_name' => $user->last_name,
                'token' => $user->token,
            ]
        );

        Auth::login($loggedInUser);
        return redirect($this->redirectTo);
    }

    public function logout()
    {
        Auth::logout();
        return redirect()->intended('/');
    }
    // ↑↑ ここまで追加 ↑↑
}

编辑 app/Providers/EventServiceProvider.php 如下。

<?php

namespace App\Providers;

// ... 中略 ...

// ↓↓ ここから ↓↓
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\FreeeAccounting\FreeeAccountingExtendSocialite;
// ↑↑ ここまで追加 ↑↑

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        // ↓↓ ここから ↓↓
        SocialiteWasCalled::class => [
            FreeeAccountingExtendSocialite::class,
        ],
        // ↑↑ ここまで追加 ↑↑
    ];

    // ... 略 ...
}

通过这些步骤,Laravel 项目已经能够对会计 freee API 进行登录了。

接下来,尝试创建使用本 SDK 获取信息的部分。

创建用于显示信息的控制器和视图。首先,创建控制器 AccountController

php artisan make:controller AccountController

app/Http/Controllers/AccountController.php 将被创建,在那里编写处理程序。

<?php

namespace App\Http\Controllers;

// ↓↓ ここから ↓↓
// use Illuminate\Http\Request;
use Freee\Accounting\Configuration;
use Freee\Accounting\Api\CompaniesApi;
use Freee\Accounting\Api\DealsApi;
use Illuminate\Support\Facades\Auth;
// ↑↑ ここまで編集 ↑↑

class AccountController extends Controller
{
    //

    // ↓↓ ここから ↓↓
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Display information of current user.
     *
     * @return \Illuminate\View\View
     */
    public function me()
    {
        $user = Auth::user();

        $config = Configuration::getDefaultConfiguration()->setAccessToken($user->token);

        $companiesApiInstance = new CompaniesApi(null, $config);
        $companiesResponse = $companiesApiInstance->getCompanies();

        $dealsApiInstance = new DealsApi(null, $config);
        $targetCompanyId = $companiesResponse->getCompanies()[0]->getId();
        $dealsNumberlimit = 5;
        $dealsResponse = $dealsApiInstance->getDeals(
            $targetCompanyId,
            null, null, null, null, null, null, null, null, null, null, null, null,
            $dealsNumberlimit);
        $deals = $dealsResponse->getDeals();

        $invoicesApiInstance = new InvoicesApi(null, $config);
        $invoicesResponse = $invoicesApiInstance->getInvoices($targetCompanyId);
        $invoices = $invoicesResponse->getInvoices();

        return view('account.me', compact('user', 'deals', 'invoices'));
    }
    // ↑↑ ここまで追加 ↑↑
}

然后,在 routes/web.php 中添加以下路由,以通过路由将 AccountController 传递。

Route::get('/account/me', 'AccountController@me')->name('me');

然后准备视图。创建 resources/views/account 目录,并复制本存储库 samples/BasicWebApp/resources/views/account 目录下的文件。

mkdir -p resources/views/account

# 前述のようにファイルをコピーする

添加导航到创建的页面的菜单。将 resources/views/layouts/app.blade.php 更新如下。

<!-- ... 中略 ... -->

<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
    <!-- Authentication Links -->
    @guest
        <li class="nav-item">
            <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
        </li>
        @if (Route::has('register'))
            <li class="nav-item">
                <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
            </li>
        @endif
    @else
        <li class="nav-item dropdown">
            <a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
                {{ Auth::user()->name }} <span class="caret"></span>
            </a>

            <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
                <!-- ↓↓ ここから ↓↓ -->
                <a class="dropdown-item" href="{{ route('me') }}">
                    {{ __('Me') }}
                </a>
                <!-- ↑↑ ここまで追加 ↑↑ -->
                <a class="dropdown-item" href="{{ route('logout') }}"
                    onclick="event.preventDefault();
                                  document.getElementById('logout-form').submit();">
                    {{ __('Logout') }}
                </a>

<!-- ... 略 ... -->

至此,本步骤结束。如果确认可以按照 示例的执行方法 中显示的操作进行,则表示导入成功。

关于贡献

欢迎对此项目做出贡献。有关详细信息,请参阅 贡献指南

许可证

有关许可证,请参考以下内容。

MIT许可证