quickbooks_api-8.x-1.0-beta4/src/Form/Settings.php
src/Form/Settings.php
<?php
namespace Drupal\quickbooks_api\Form;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Url;
use Drupal\quickbooks_api\QuickbooksService;
use QuickBooksOnline\API\Core\CoreConstants;
use QuickBooksOnline\API\DataService\DataService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configuration form for the Quickbooks API.
*/
class Settings extends ConfigFormBase {
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
QuickbooksService::CONFIG_KEY,
];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'quickbooks_api_admin_form';
}
/**
* {@inheritdoc}
*/
public function __construct(ConfigFactoryInterface $config_factory, protected StateInterface $state, protected TimeInterface $time, protected QuickbooksService $quickbooksService, protected LoggerChannelInterface $log) {
parent::__construct($config_factory);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('state'),
$container->get('datetime.time'),
$container->get('quickbooks_api.QuickbooksService'),
$container->get('logger.channel.quickbooks_api'),
);
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->configFactory->get('quickbooks_api.settings');
$form['#attached']['library'][] = 'quickbooks_api/quickbooks_api';
$form['requirements'] = [
'#type' => 'fieldset',
'#title' => $this->t('Requirements'),
];
$exists = class_exists('QuickBooksOnline\API\Core\CoreConstants');
if (!$exists) {
$this->messenger()->addError($this->t("Missing Quickbooks SDK. Install via composer with `composer require quickbooks/v3-php-sdk`"));
return $form;
}
// @todo Refactor *all* of this.
$sdk_version = CoreConstants::DEFAULT_SDK_MINOR_VERSION;
$sdk_path = new \ReflectionClass('QuickBooksOnline\API\Core\CoreConstants');
$sdk_filepath = str_replace("/src/Core/CoreConstants.php", "", $sdk_path->getFileName());
$sdk_data = json_decode((string) file_get_contents($sdk_filepath . '/composer.json'), TRUE);
$authors = [];
foreach ($sdk_data['authors'] as $author) {
$authors[] = $this->t("@name Email: @email", [
'@name' => $author['name'],
'@email' => $author['email'],
]);
}
$sdk_version .= ' (' . str_replace("V3PHPSDK", "", CoreConstants::USERAGENT) . ')';
$form['requirements']['hello'] = [
'#markup' => $this->t("<p>Quickbooks SDK installed. <br />Version: @version</p><p>@name<br />@description<br />License: @license<br />@authors</p>", [
'@version' => $sdk_version,
'@name' => $sdk_data['name'],
'@description' => $sdk_data['description'],
'@license' => $sdk_data['license'],
'@authors' => implode("<br />", $authors),
]),
];
$form['connection'] = [
'#type' => 'fieldset',
'#title' => $this->t('Connection'),
];
$form['connection']['company_id'] = [
'#type' => 'textfield',
'#title' => $this->t('Company ID'),
'#description' => $this->t('@config_overrideCompany ID from Quickbooks online.', [
'@config_override' => $config->hasOverrides('company_id') ? 'CONFIGURATION_OVERRIDDEN: ' : '',
]),
'#default_value' => $config->get('company_id'),
'#required' => TRUE,
];
$form['connection']['client_id'] = [
'#type' => 'textfield',
'#title' => $this->t('Client ID'),
'#description' => $this->t('@config_overrideClient ID for the Quickbooks Online App', [
'@config_override' => $config->hasOverrides('company_id') ? 'CONFIGURATION_OVERRIDDEN: ' : '',
]),
'#default_value' => $config->get('client_id'),
'#required' => TRUE,
];
$form['connection']['client_secret'] = [
'#type' => 'textfield',
'#title' => $this->t('Client secret'),
'#description' => $this->t('@config_overrideClient secret for the Quickbooks Online App', [
'@config_override' => $config->hasOverrides('company_id') ? 'CONFIGURATION_OVERRIDDEN: ' : '',
]),
'#default_value' => $config->get('client_secret'),
'#required' => TRUE,
];
// Here we need more fields to actually connect to Quickbooks.
$form['connection']['oauth'] = [
'#type' => 'fieldset',
'#title' => $this->t('OAuth connection'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#access' => ($config->get('company_id') && $config->get('client_id') && $config->get('client_secret')),
];
// Oauth connection logic here.
// Show the data, but only if we are connected already.
$access_token = $this->state->get(QuickbooksService::STATE_ACCESS_TOKEN);
$refresh_expiry = $this->state->get(QuickbooksService::STATE_REFRESH_EXPIRY);
// @todo Quickbooks error thing.
$api_error = FALSE;
if ($access_token && ($refresh_expiry > $this->time->getCurrentTime())) {
// We get the textual info.
try {
$company_info = $this->quickbooksService->dataService()->getCompanyInfo();
if ($company_info) {
$company_name = $company_info->CompanyName;
}
else {
$company_name = 'unknown';
$api_error = TRUE;
}
$form['connection']['oauth']['refresh_expiry'] = [
'#markup' => $this->t("<p><strong>Connected to Quickbooks Online company:</strong> @company<br /><strong>Refresh token expires on:</strong> @date</p>", [
'@company' => $company_name,
'@date' => date('m-d-Y', $refresh_expiry),
]),
];
}
catch (\Exception $e) {
$this->log->error('Connection to Quickbooks failed: ' . $e->getMessage());
$api_error = TRUE;
}
}
// This is our connect button. This needs to use JS!
$form['connection']['oauth']['button'] = [
'#access' => ($access_token && ($refresh_expiry < $this->time->getCurrentTime()) || !$access_token || $api_error),
'#children' => '<ipp:connectToIntuit></ipp:connectToIntuit>',
];
// Show the disconnect button when the refresh token is not expired.
$form['connection']['oauth']['disconnect'] = [
'#type' => 'submit',
'#value' => $this->t('Disconnect'),
'#limit_validation_errors' => [],
'#submit' => ['quickbooks_api_config_form_oauth_disconnect'],
'#access' => ($this->state->get(QuickbooksService::STATE_ACCESS_TOKEN) && $this->state->get(QuickbooksService::STATE_ACCESS_TOKEN_EXPIRY) > $this->time->getCurrentTime() && !$api_error),
];
// Here we have additional fields.
$connection_types = [
'Production' => 'Production',
'Development' => 'Development',
];
$form['connection']['environment'] = [
'#type' => 'select',
'#options' => $connection_types,
'#title' => $this->t('Connection Type'),
'#description' => $this->t('@config_overrideChoose the environment: <strong>Production</strong>: full functionality<strong>Production test</strong>: uses production environment but does not save data, <strong>Development</strong>: development environment', [
'@config_override' => $config->hasOverrides('company_id') ? 'CONFIGURATION_OVERRIDDEN: ' : '',
]),
'#default_value' => $config->get('environment'),
'#required' => TRUE,
];
// Needed for authentication, but only possible if we have no connection.
$oauth_route = Url::fromRoute('quickbooks_api.oauth');
$environment = $config->get('environment');
if ($environment) {
// Prepare Data Services.
try {
$data_service = DataService::Configure([
'auth_mode' => 'oauth2',
'ClientID' => $config->get('client_id'),
'ClientSecret' => $config->get('client_secret'),
'RedirectURI' => $oauth_route->setAbsolute(TRUE)->toString(),
'scope' => "com.intuit.quickbooks.accounting",
'baseUrl' => $environment,
]);
}
catch (\Throwable $e) {
$this->log->error('Error creating Quickbooks data service.');
$data_service = NULL;
// We can't connect without the dataService.
unset($form['connection']['oauth']['button']);
}
if ($data_service) {
$helper = $data_service->getOAuth2LoginHelper();
// Add the state key to the database for better oauth route security.
$this->state->set(QuickbooksService::STATE_OAUTH_SECURITY, $helper->getState());
$authorization_url = $helper->getAuthorizationCodeURL();
// Attach JS and Drupal Settings to the form.
$form['#attached']['drupalSettings']['quickbooks_api']['quickbooks_api'] = [
'oauthUrl' => $authorization_url,
];
}
}
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$this->config('quickbooks_api.settings')
->set('company_id', $form_state->getValue('company_id'))
->set('client_id', $form_state->getValue('client_id'))
->set('client_secret', $form_state->getValue('client_secret'))
->set('environment', $form_state->getValue('environment'))
->save();
}
}
