Skip to content

Instantly share code, notes, and snippets.

@nikathone
Last active January 8, 2019 15:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikathone/a771b707d447200e9c6f0b7389042444 to your computer and use it in GitHub Desktop.
Save nikathone/a771b707d447200e9c6f0b7389042444 to your computer and use it in GitHub Desktop.
Report drupal commerce order to administrate
<?php
namespace Drupal\administrate_esr;
use Drupal\address\AddressInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Driver\Exception\Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
/**
* The report service.
*/
class ReportOrderToAdministrate {
/**
* The guzzle http client service.
*
* @var \GuzzleHttp\Client
*/
protected $httpClient;
/**
* The administrate api configurations.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $apiConfig;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The administrate esr module logger channel.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
/**
* The variable to hold a loaded contact if any.
*
* @var \Object
*/
protected $contact;
/**
* Constructs Report object.
*
* @param \GuzzleHttp\Client $http_client
* The http guzzle client.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The config factory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger
* The logger.
*/
public function __construct(Client $http_client, ConfigFactoryInterface $config, EntityTypeManagerInterface $entity_type_manager, LoggerChannelFactoryInterface $logger) {
$this->httpClient = $http_client;
$this->apiConfig = $config->get('administrate_api.config');
$this->entityTypeManager = $entity_type_manager;
$this->logger = $logger->get('administrate_esr');
}
/**
* Send a drupal commerce order to administrate.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* The commerce order.
*
* @return bool|void
* The feedback.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function order(OrderInterface $order) {
// It's an order to report in administrate.
$administrate_order = $order->hasField('administrate_id');
// If an order is already associated with an administrate id we skip it.
$administrate_id = $order->get('administrate_id')->remote_id;
if (!$administrate_order || ($administrate_id > 0)) {
return;
}
$order_email = $order->getEmail();
$contact_id = $this->getContactId($order_email, TRUE);
if (is_null($contact_id) || $contact_id === FALSE) {
/** @var \Drupal\address\AddressInterface $address */
$address = $order->getBillingProfile()->address->first();
$account_id = $this->getAccountId($address->getOrganization(), $order_email);
if (is_null($account_id) || $account_id === FALSE) {
$account_id = $this->addAccount($address, $order_email);
}
$contact_id = $this->addContact($address, $order_email, [], $account_id);
}
else {
$account_id = $this->contact->account_id;
}
$students = [];
foreach ($order->getItems() as $order_item) {
if (!$order_item->hasField('administrate_learner_details')) {
continue;
}
/** @var \Drupal\commerce_product\Entity\ProductVariationInterface $purchased_entity */
$event_pricing = $order_item->getPurchasedEntity();
$event = $event_pricing->getProduct();
// Getting learner details from order_items.
$learner_details = $order_item->get('administrate_learner_details');
foreach ($learner_details as $learner_detail) {
/** @var \Drupal\administrate_commerce\Entity\LearnerInterface $learner */
$learner = $learner_detail->entity;
$learner_email = $learner->getEmail();
$student_id = $this->getContactId($learner_email);
if (is_null($student_id) || $student_id === FALSE) {
$name = [
'given' => $learner->getName()->given,
'family' => $learner->getName()->family,
];
$student_id = $this->addContact(
$learner->getAddress(),
$learner_email,
$name,
$account_id,
$learner->getName()->title,
$learner->getPhone()
);
}
$students[] = [
'event_id' => $event->get('administrate_id')->remote_id,
'price' => floatval($order_item->getUnitPrice()->getNumber()),
'contact_id' => $student_id,
];
}
}
// For payment transaction code use one payment method from the order.
/** @var \Drupal\commerce_payment\PaymentStorageInterface $commerce_payment_storage */
$commerce_payment_storage = $this->entityTypeManager->getStorage('commerce_payment');
$transaction_code = $order->getOrderNumber();
foreach ($commerce_payment_storage->loadMultipleByOrder($order) as $commerce_payment) {
$state = $commerce_payment->getState()->value;
if ($state == 'completed') {
$transaction_code = $commerce_payment->getPaymentGateway()->id();
$transaction_code .= '--' . $commerce_payment->getRemoteId();
break;
}
}
$administrate_order = [
'contact_id' => $contact_id,
'currency_id' => $order->getTotalPrice()->getCurrencyCode(),
'source_type_id' => 16,
'external_id' => $order->id(),
'items' => $students,
'payment' => [
'amount' => floatval($order->getTotalPrice()->getNumber()),
'type' => 'Card',
'currency' => $order->getTotalPrice()->getCurrencyCode(),
'transaction_code' => $transaction_code,
],
];
if (!($data = $this->postBody('/orders', $administrate_order))) {
return FALSE;
}
$order->set('administrate_id', ['remote_id' => $data->order_id]);
// Log this on the order.
/** @var \Drupal\commerce_log\LogStorageInterface $log_storage */
$log_storage = $this->entityTypeManager->getStorage('commerce_log');
$params = ['administrate_id' => $data->order_id];
$log = $log_storage->generate($order, 'order_administrate_reported', $params);
$log->save();
}
/**
* Gets an administrate contact id.
*
* @param string $email
* The email.
* @param bool $primary
* Whether contact is primary.
*
* @return bool|int
* The contact id or false.
*/
private function getContactId($email, $primary = FALSE) {
if (!($data = $this->getQuery('/crm/contacts', ['email__eq' => $email]))) {
return FALSE;
}
if ($primary) {
$this->contact = $data[0];
}
return $data[0]->id;
}
/**
* Adding an administrate contact.
*
* @param \Drupal\address\AddressInterface $address
* The address.
* @param string $email
* The email.
* @param array $name
* The name components.
* @param int $account_id
* The account id.
* @param string $salutation
* The salutation.
* @param string $telephone
* The telephone.
*
* @return bool|int
* The account id or false.
*/
private function addContact(AddressInterface $address, $email, array $name, $account_id, $salutation = '', $telephone = '') {
if (!$name) {
$name = [
'given' => $address->getGivenName(),
'family' => $address->getFamilyName()
];
}
$user = [
'first_name' => $name['given'],
'last_name' => $name['family'],
'account_id' => $account_id,
'address_unit' => $address->getAddressLine1(),
'address_town' => $address->getLocality(),
'address_postcode' => $address->getPostalCode(),
'address_region' => $address->getAdministrativeArea(),
'address_country_id' => $address->getCountryCode(),
'organisation' => $address->getOrganization(),
'email' => $email
];
if (!empty($telephone)) {
$user['tel'] = $telephone;
}
if (!empty($salutation)) {
$user['salutation'] = $salutation;
}
if (!($data = $this->postBody('/crm/contacts', $user))) {
return FALSE;
}
return $data->id;
}
/**
* Gets an administrate account id.
*
* @param string $name
* The account name.
* @param string $email
* The account email.
*
* @return bool|int
* The account id or false.
*/
private function getAccountId($name, $email) {
if (!($data = $this->getQuery('/crm/accounts', ['name__eq' => $name, 'email__eq' => $email]))) {
return FALSE;
}
return $data[0]->id;
}
/**
* Adding an administrate account.
*
* @param \Drupal\address\AddressInterface $address
* The address.
* @param string $email
* The email.
*
* @return bool|int
* The account id or false.
*/
private function addAccount(AddressInterface $address, $email) {
$account = [
'name' => $address->getOrganization(),
'email' => $email,
'address_unit' => $address->getAddressLine1(),
'address_town' => $address->getLocality(),
'address_postcode' => $address->getPostalCode(),
'address_region' => $address->getAdministrativeArea(),
'address_country' => $address->getCountryCode(),
'company_id' => 1,
];
if (!($data = $this->postBody('/crm/accounts', $account))) {
return FALSE;
}
return $data->id;
}
/**
* Gets guzzle request with query.
*
* @param string $endpoint
* The request endpoint.
* @param string $query
* The query.
*
* @return bool|mixed
* Request status or contents.
*/
private function getQuery($endpoint, $query) {
return $this->get($endpoint, ['query' => $query]);
}
/**
* Get Guzzle request.
*
* @param string $endpoint
* The request endpoint.
* @param array $params
* The request parameters.
*
* @return bool|mixed
* Request status or contents.
*/
private function get($endpoint, array $params = []) {
if (!isset($params['auth'])) {
$params['auth'] = $this->getAuth();
}
return $this->sendRequest('get', $endpoint, $params);
}
/**
* Post request body.
*
* @param string $endpoint
* The request endpoint.
* @param mixed $body
* The request body.
*
* @return bool|mixed
* Request status or contents.
*/
private function postBody($endpoint, $body) {
return $this->post($endpoint, ['body' => $body]);
}
/**
* Make a Guzzle POST request.
*
* @param string $endpoint
* The request endpoint.
* @param array $params
* The request parameters.
*
* @return bool|mixed
* Request status or contents.
*/
private function post($endpoint, array $params = []) {
if (isset($params['body'])) {
$params['body'] = json_encode($params['body']);
}
if (!isset($params['auth'])) {
$params['auth'] = $this->getAuth();
}
if (!isset($params['headers']) || !isset($params['headers']['Content-Type'])) {
$params['headers']['Content-Type'] = 'application/json';
}
return $this->sendRequest('post', $endpoint, $params);
}
/**
* Gets Authentication credentials.
*
* @return array
* The credentials.
*/
private function getAuth() {
$user = $this->apiConfig->get('username');
$pass = $this->apiConfig->get('password');
return [$user, $pass];
}
/**
* Gets Administrate base URL.
*
* @return string
* The base URL.
*/
private function getBaseUrl() {
$hostname = $this->apiConfig->get('hostname');
if (substr($hostname, -1) == '/') {
$url = $hostname . 'api/v2';
}
else {
$url = $hostname . '/api/v2';
}
return $url;
}
/**
* Sends the guzzle request.
*
* @param string $method
* The guzzle request method.
* @param string $endpoint
* The request endpoint.
* @param array $params
* The request parameters.
*
* @return bool|mixed
* Request status or contents.
*/
private function sendRequest($method, $endpoint, array $params) {
$error_code = 0;
$error_message = 'unknown';
try {
$url = $this->getBaseUrl() . $endpoint;
$response = $method == 'post' ? $this->httpClient->post($url, $params) : $this->httpClient->get($url, $params);
if ($response->getStatusCode() == 200) {
return json_decode((string) $response->getBody());
}
else {
$resp = $response;
}
}
catch (\Exception $e) {
$error_code = $e->getCode();
$error_message = $e->getMessage();
$resp = NULL;
}
catch (ServerException $e) {
$resp = $e->getResponse();
}
catch (ClientException $e) {
$resp = $e->getResponse();
}
catch (ConnectException $e) {
$resp = $e->getResponse();
}
if ($resp) {
$this->logger->notice('STATUS CODE FROM ADMINISTRATE ' . $resp->getStatusCode() . ' ' . $resp->getBody()->getContents());
}
else {
$message = t('Exception Error code: @code <br/>Exception Error message @message', [
'@code' => $error_code,
'@message' => $error_message,
])->render();
$this->logger->notice($message);
}
return FALSE;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment