fernleafsystems/apiwrappers-freeagent

FreeAgent API 的 PHP 包装器

1.0.7 2023-10-23 08:38 UTC

README

FreeAgent 财务 API 的 PHP 包装器。

当前版本 0.2.x 为测试版。请使用严格的 Composer 版本。

安装

要开始使用,请通过以下命令将包添加到您的项目中

composer require fernleafsystems/apiwrappers-freeagent

当前版本 0.2.x 为测试版。请使用严格的 Composer 版本。

入门

此包包含两个部分

  1. OAuth2 授权
  2. FreeAgent API

OAuth2 主要作为 'The League of Extraordinary Packages' OAuth2 实现的提供者。它使用它们的最新版本,并确保此包仅与 PHP 5.6+ 兼容

1) OAuth2 授权

OAuth2 是一个很大的话题,超出了本说明书的范围,但以下是如何使用此包实现它的基本步骤。

阶段 1 - "预授权":构建并将用户重定向到授权 URL

	$OauthProvider = ( new Connection() )
    		->setClientId( $freeagentAppClientId )
    		->setIsSandbox( $isSandbox )
    		->getOAuthProvider();
    		
	$redirectUrlBase = $OauthProvider->getBaseAuthorizationUrl();
	
	$authUrlParams = array(
    	'redirect_uri'  => 'https://www.theUrlForMyApp.com/To/Receive/Redirection/From/OAuth',
    	'client_id'     => $freeagentAppClientId,
    	'response_type' => 'code'
	);
    
	$authorizationUrl = $redirectUrlBase.'?'.http_build_query( $authUrlParams );
	
	header( 'Location: '. $authorizationUrl );

假设构建正确,用户将授权您的集成并被重定向回您的应用程序,基于 redirect_uri 参数。

此时,您的应用程序必须捕获附加到重定向的 OAuth 代码,键为 code。然后您需要将此信息存储在您的应用程序中。

阶段 2 - "预令牌":请求访问令牌

要执行 API 的操作,您发送一个访问令牌 - 而不是上一阶段获得的 OAuth 代码。为此,您的应用程序将发送一个请求以获取新令牌,如下所示

	$tokenRequestParameters = array(
    	'code'          => $OauthCodeFromThePreviousStage,
    	'client_id'     => $freeagentAppClientId,
    	'client_secret' => $freeagentAppClientSecret,
    	'redirect_uri'  => 'https://www.theUrlForMyApp.com/To/Receive/Redirection/From/OAuth'
	);
	
	$OauthProvider = ( new Connection() )
    		->setClientId( $freeagentAppClientId )
    		->setIsSandbox( $isSandbox )
    		->getOAuthProvider();
	
	$accessToken = $OauthProvider->getAccessToken( 'authorization_code', $aTokenRequestParameters );
	
	// Store the Access Token $accessToken. 

以下是一些 关键 点需要注意。

redirect_uri 参数在这个请求中实际上并不严格使用。但您必须包括它。如果在此阶段使用的 redirect_uri 值与上一阶段使用的值不严格相同,FreeAgent 会非常痛苦。请再次阅读 - 它必须包含,并且必须完全相同。

访问令牌 $accessToken 是一个 \League\OAuth2\Client\Token\AccessToken,具有所有需要的访问方法。您应该存储访问令牌值以供将来使用,其过期时间,以及刷新令牌值 - 您将在令牌过期后使用此值请求新的访问令牌

阶段 3 - "过期令牌":请求新的访问令牌

	$tokenRequestParameters = array(
    	'client_id'     => $freeagentAppClientId,
    	'client_secret' => $freeagentAppClientSecret,
    	'refresh_token' => $OAuth2RefreshTokenStoredFromPreviousStage
	);
	
	$OauthProvider = ( new Connection() )
    		->setClientId( $freeagentAppClientId )
    		->setIsSandbox( $isSandbox )
    		->getOAuthProvider();
	
	$accessToken = $OauthProvider->getAccessToken( 'refresh_token', $tokenRequestParameters );
	
	// Store the Access Token $accessToken. 

2) 查询 FreeAgent API

现在您已经从上面的阶段 3 获得了 AccessToken,您可以轻松地对 FreeAgent API 进行请求。以下是一个如何请求您的公司信息的示例。

示例:简单数据检索

	$connection = ( new Connection() )
    	->setIsSandbox( $isSandbox )
    	->setAccessToken( $accessTokenFromStage3 );
	
	$oCompany = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Company\Retrieve() )
	    ->setConnection( $connection )
	    ->retrieve();

在此示例中,我们简单地创建一个连接对象,并用访问令牌填充它,然后将其馈送到我们想要使用的 API 实体类。在这种情况下,它是公司实体。这将返回一个 CompanyVO,它提供了许多有用的访问方法,您可以从中获取您喜欢的特定信息,例如。

	$oCompany = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Company\Retrieve() )
	    ->setConnection( $connection )
	    ->retrieve();
	    
	echo $oCompany->getName();

这将打印,例如,Acme Inc. 如果您的公司是这样的话。

所有 API 类都是这样构建的,要执行任何操作,您只需将其馈送到连接对象,系统就会完成剩余的工作。

注意:如果您不设置沙箱标志,则假定它不是沙箱,因此在实际操作时可以省略此标志。

示例:通过其已知的 FreeAgent ID 获取联系信息

	$oContact = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Contacts\Retrieve() )
	    ->setConnection( $connection )
	    ->setEntityId( 12345 )
	    ->retrieve();

setEntityId() 是检索和更新实体的主要方法。您必须在尝试检索或更新它之前知道其 ID。

如果您没有提供 ID,系统将在请求之前抛出一个 Exception

在这个特定的情况下,返回的对象将是一个 ContactVO。它类似于之前示例中提供的 CompanyVO,并且具有有用的访问方法,这样您就不需要从API文档中查找详细信息。

获取刚刚检索到的 ContactVO 对象,您可以为它创建一个新的账单...

示例:创建一个新的账单

	$connection = ( new Connection() )->setAccessToken( $accessTokenFromStage3 );
	
	$oNewBill = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Bills\Create() )
	    ->setConnection( $connection )
	    ->setContact( $freeagentContact ) // a Freeagent ContactVO
	    ->setReference( 'My Bill Reference' )
	    ->setTotalValue( '12.34' )  // a float
	    ->setCategory( $freeagentContegory ) // a Freeagent CategoryVO
	    ->setDatedOn( '2018-12-18' ) // or unix timestamp
	    ->setDueOn( '2018-12-25' )  // or unix timestamp
	    ->create();

这是创建账单所需的最小内容。如果这些项目中任何一项不存在,API在发出请求之前将抛出 Exception

您可以通过查看每个API实体上的 getCriticalRequestItems() 方法来找出哪些是关键的。

如果您想查找某些内容,但不知道实体ID怎么办?

基于特定属性进行搜索/查找实体

FreeAgent API非常不一致,这使得搜索/过滤变得相当棘手。我猜测这仅仅是因为他们如何构建数据以及他们的内部函数,他们将这些内部不一致映射到了他们的API上。不管怎样,我们已经提供了过滤和搜索的方法。

根据您要过滤和搜索的内容,我们可以使用API提供的内置过滤器,如果不行,我们将批量请求并遍历结果,直到找到匹配的内容。这会加大他们的API负载,但我们别无选择。

以下是一些搜索示例。

根据给定的引用查找账单

	$oFoundBill = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Bills\Find() )
	    ->setConnection( $connection )
	    ->filterByReference( 'My Bill Reference' )
	    ->first();

使用 first() 假设您只有一张给定引用的账单。这个示例的问题在于,您没有设置这个账单可能创建的时间边界,因此这可能会在寻找账单时进行相当大的API操作。

相反,您可以按日期限制,甚至使用带半径的范围。

在日期范围内查找给定引用的账单

	$oFoundBill = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Bills\Find() )
	    ->setConnection( $connection )
	    ->filterByDateRange( 123123123, 5 )
	    ->filterByReference( 'My Bill Reference' )
	    ->first();

现在将搜索这个账单的范围限制在特定的日期范围内。第一个参数 必须是UNIX时间戳,第二个参数是相对于时间戳的半径天数,因此在这种情况下,5天前,5天后 - 总共10天的时间窗口。

注意:如果没有找到符合此标准的账单,将返回 null

在这个示例中,我们正在寻找具有给定引用的账单。但如果我们想查找那个时间段内的所有账单怎么办。

在给定日期范围内查找所有账单

	$aAllBills = ( new \FernleafSystems\ApiWrappers\Freeagent\Entities\Bills\Find() )
	    ->setConnection( $connection )
	    ->filterByDateRange( 123123123, 5 )
	    ->all();

我们移除了引用过滤器,现在使用 all() 进行调用。这将返回一个 BillVO 对象数组。它可能是空的,也可能不是,但它将是一个 array

其余的...

每种实体类型都有自己的方法、参数和过滤器选项。您必须查看每个以确定您的选项。

上述示例特定于那些特定实体。当然有一些重叠,但所有实体都遵循FreeAgent API的文档和规范。

错误和异常

在检索、创建和更新时,有一些基本的数据检查以确保在发出请求之前提供了绝对最小内容。如果这些检查失败,将抛出 Exception

如果这些检查没有失败,并且请求失败,您有几种选择。这可能会在未来发生变化,因为当前实现有缺陷且不满意。

目前,您可以在所有API实体上执行以下操作

	$oCreator = new \FernleafSystems\ApiWrappers\Freeagent\Entities\Invoices\Create();
    /** creation code parameters*/
	$oNewInvoice = $oCreator->create();
	
	if ( is_null( $oNewInvoice ) ) {
	    $sErrorMessageFromFreeAgent = $oCreator->getLastError()->getMessage();
	}

如果您发现错误、改进建议等,请告诉我们。