Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
class Config
{
private $clientid;
private $orgunitid;
private $orgunitguid;
private $soapurl;
/**
* Config constructor.
*
* @param array $config
*
* @throws PostAtException
*/
public function __construct(array $config)
{
$requiredSettings = [
'soapurl',
'clientid',
'orgunitid',
'orgunitguid',
];
foreach ($requiredSettings as $setting) {
if (empty($config[$setting])) {
throw new PostAtException(
'Configuration of the Post.at module is invalid. Please verify the configuration.'
);
}
$this->$setting = $config[$setting];
}
}
/**
* @return string The URL of the SOAP API endpoint.
*/
public function getSoapUrl(): string
{
return $this->soapurl;
}
/**
* Get ClientId (a.k.a DebitorID).
*
* @return int
*/
public function getClientId(): int
{
return (int) $this->clientid;
}
/**
* Get OrganisationID; unique for a customerID.
*
* @return int
*/
public function getOrgUnitId(): int
{
return (int) $this->orgunitid;
}
/**
* Get unique GUID of the customerID.
*
* @return string
*/
public function getOrgUnitGuid(): string
{
return $this->orgunitguid;
}
}
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP\Method;
use Xentral\Modules\Postat\SOAP\MethodInterface;
use Xentral\Modules\Postat\SOAP\ParameterInterface;
use Xentral\Modules\Postat\SOAP\PostAtClient;
use Xentral\Modules\Postat\SOAP\PostAtException;
use Xentral\Modules\Postat\SOAP\Result\AllowedServicesResult;
class GetAllowedServicesForCountry implements MethodInterface
{
/** @var PostAtClient */
private $postAtClient;
/** @var array Array of ISO 3166 ALPHA-2 country codes. */
private $countries;
/**
* AllowedServicesForCountry constructor.
*
* @param PostAtClient $postAtClient
*/
public function __construct(PostAtClient $postAtClient)
{
$this->postAtClient = $postAtClient;
}
/**
* Call the API endpoint.
*
* @param ParameterInterface $countries
*
* @return AllowedServicesResult
* @throws PostAtException
*/
public function call(ParameterInterface $countries)
{
$this->countries = $countries->getData();
$response = $this->postAtClient->call($this);
return new AllowedServicesResult($response);
}
/**
* Get content for the SOAP body element.
*
* @return array[]
*/
public function getBody(): array
{
return [
'countryList' => $this->countries,
];
}
}
@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP\Method;
use Xentral\Modules\Postat\SOAP\MethodInterface;
use Xentral\Modules\Postat\SOAP\ParameterInterface;
use Xentral\Modules\Postat\SOAP\PostAtClient;
use Xentral\Modules\Postat\SOAP\PostAtException;
class ImportShipment implements MethodInterface
{
/** @var PostAtClient */
private $postAtClient;
/** @var array */
private $shipmentRow;
/**
* ImportShipment constructor.
*
* @param PostAtClient $postAtClient
*/
public function __construct(PostAtClient $postAtClient)
{
$this->postAtClient = $postAtClient;
}
/**
* Call the SOAP API with the given data.
*
* @param ParameterInterface $shipmentRow
*
* @throws PostAtException
*
* @return array $data
*/
public function call(ParameterInterface $shipmentRow)
{
$this->shipmentRow = $shipmentRow->getData();
return $this->postAtClient->call($this);
}
/**
* @return array
*/
public function getBody(): array
{
return $this->shipmentRow;
}
}
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
/**
* Each API method call should be represented by a class that implements this interface.
*
* The name of the class must be identical with the name of the API method found
* in the Post.at SOAP API documentation.
*
* See the existing API method implementations in the Postat/SOAP/Method/ directory.
*/
interface MethodInterface
{
/**
* MethodInterface constructor.
*
* @param PostAtClient $client
*/
public function __construct(PostAtClient $client);
/**
* @param ParameterInterface $data Data needed for the body of the SOAP call.
*/
public function call(ParameterInterface $data);
}
@@ -0,0 +1,25 @@
<?php
namespace Xentral\Modules\Postat\SOAP\Parameter;
use Xentral\Modules\Postat\SOAP\ParameterInterface;
use Xentral\Modules\Postat\SOAP\PostAtException;
class Countries implements ParameterInterface
{
private $countries;
public function __construct(array $countries)
{
if (!is_array($countries)) {
throw new PostAtException('The given target countries are invalid.');
}
$this->countries = $countries;
}
public function getData(): array
{
return $this->countries;
}
}
@@ -0,0 +1,26 @@
<?php
namespace Xentral\Modules\Postat\SOAP\Parameter;
use Xentral\Modules\Postat\SOAP\ParameterInterface;
use Xentral\Modules\Postat\SOAP\PostAtException;
class ShipmentRow implements ParameterInterface
{
/** var array $shipmentRow */
private $shipmentRow;
public function __construct(array $shipmentRow)
{
if (empty($shipmentRow['row'])) {
throw new PostAtException('The given shipment data is invalid');
}
$this->shipmentRow = $shipmentRow;
}
public function getData(): array
{
return $this->shipmentRow;
}
}
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
/**
* Validate the data given to the constructor.
*
* In case of validation errors, the class should throw a PostAtException.
*/
interface ParameterInterface
{
public function __construct(array $data);
public function getData(): array;
}
@@ -0,0 +1,116 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
use Xentral\Components\Logger\Logger;
class PostAtClient
{
/** @var */
private $apiConfig;
/** @var Logger */
private $logger;
/**
* PostAtClient constructor.
*
* @param $apiConfig
* @param Logger $logger
*/
public function __construct(Config $apiConfig, Logger $logger)
{
$this->apiConfig = $apiConfig;
$this->logger = $logger;
}
/**
* Make a SOAP API call.
*
* @param MethodInterface $method
*
* @throws PostAtException
*
* @return mixed
*/
public function call(MethodInterface $method)
{
$body = $method->getBody();
$body = $this->appendConfiguration($body);
try {
$client = new \SoapClient($this->apiConfig->getSoapUrl());
} catch (\SoapFault $exception) {
$this->logger->error('Cannot connect to the Post.at SOAP API.', ['exception' => $exception]);
// The exception thrown above would be too technical for the end
// user, so use a more user-friendly message instead.
throw new PostAtException(
'Configuration of the Post.at module is invalid. Please verify the configuration.'
);
}
$response = $client->__soapCall($this->getClassName($method), [$body]);
if ($response->errorCode !== null) {
// A user-friendly error such as "This package type is not available for the chosen target country".
throw new PostAtException("{$response->errorCode} - {$response->errorMessage}");
}
return $response;
}
/**
* Appends SOAP body entries that are required for every request.
*
* - clientID: DebitorID
* - orgUnitID: OrganisationID; unique for a customerID
* - orgUnitGuid: Unique GUID of the customerID
*
* For some reason the location of these entries is different within the SOAP
* body structure depending on which API method is used. This function attempts
* to cover all use cases.
*
* @param array $body
*
* @return array $body
*/
private function appendConfiguration(array $body): array
{
if (isset($body['row'])) {
$body['row']['ClientID'] = $this->apiConfig->getClientId();
$body['row']['OrgUnitID'] = $this->apiConfig->getOrgUnitId();
$body['row']['OrgUnitGuid'] = $this->apiConfig->getOrgUnitGuid();
return $body;
}
if (isset($body['addresses'])) {
// TODO Add this once one of the address API methods gets implemented.
}
// In simple requests the entries are at the root of the body.
$body['clientID'] = $this->apiConfig->getClientId();
$body['orgUnitID'] = $this->apiConfig->getOrgUnitId();
$body['orgUnitGuid'] = $this->apiConfig->getOrgUnitGuid();
return $body;
}
/**
* Gets the short name of the class (the part without the namespace).
*
* @param $method
*
* @throws \ReflectionException
*
* @return string
*/
private function getClassName($method): string
{
return (new \ReflectionClass($method))->getShortName();
}
}
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
class PostAtException extends \Exception
{
}
@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP\Result;
class AllowedServicesResult
{
/** @var The raw data received from the SOAP API. */
private $data;
/**
* AllowedServicesResult constructor.
*
* @param $data
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get two-level associative array of service codes and the service names.
*
* Can be used for example to generate options for a <select> element.
*
* [
* 45 => [
* 'name' => 'Premium Int. Outbound B2B',
* 'features' => [
* '007' => '24-Stundenpaket',
* '022' => 'Nachnahme COD International',
* '024' => 'Zerbrechlich international',
* '063' => 'Höherversicherung',
* '065' => 'Postlagernd',
* '074' => 'Gefahrgut - begrenzte Menge (LQ)',
* ],
* ],
* 46 => [
* 'name' => 'Post Express International',
* 'features' => [],
* ],
* etc...
* ]
*
* @return array $options
*/
public function toOptionsArray(): array
{
$services = $this->data->GetAllowedServicesForCountryResult->CarrierServiceRow;
$options = [];
foreach ($services as $service) {
$features = [];
foreach ($service->FeatureList->AdditionalInformationResult as $test) {
$features[$test->ThirdPartyID] = $test->Name;
}
$options[$service->ThirdPartyID] = [
'name' => $service->Name,
'features' => $features,
];
}
return $options;
}
}
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Xentral\Modules\Postat\SOAP;
use Xentral\Modules\Postat\SOAP\Method\GetAllowedServicesForCountry;
use Xentral\Modules\Postat\SOAP\Method\ImportShipment;
use Xentral\Modules\Postat\SOAP\Parameter\Countries;
use Xentral\Modules\Postat\SOAP\Parameter\ShipmentRow;
use Xentral\Modules\Postat\SOAP\Result\AllowedServicesResult;
/**
* Constructs the individual methods that the SOAP API service exposes.
*/
class SoapService
{
/** @var PostAtClient */
private $postAtClient;
/**
* Methods constructor.
*
* @param PostAtClient $postAtClient
*/
public function __construct(PostAtClient $postAtClient)
{
$this->postAtClient = $postAtClient;
}
/**
* Get available postal services for the given countries.
*
* @param array $countries Array of ISO 3166 ALPHA-2 country codes.
*
* @throws PostAtException
*
* @return AllowedServicesResult
*/
public function getAllowedServicesForCountry(array $countries): AllowedServicesResult
{
$countries = new Countries($countries);
$soapMethod = new GetAllowedServicesForCountry($this->postAtClient);
return $soapMethod->call($countries);
}
/**
* Generates a shipping label for the given package and chosen delivery type.
*
* The $shipmentRow parameter is an associative array of the delivery details:
*
* [
* 'row' => [
* 'PrinterObject' => [
* 'LabelFormatID' => '100x150',
* 'LanguageID' => 'pdf',
* 'PaperLayoutID' => '2xA5inA4'
* ],
* 'Number' => 'XEN-12345,
* 'DeliveryServiceThirdPartyID' => 28,
* etc...
* ],
* ]
*
* See the official Post.at SOAP API documentation for further details.
*
* @param array $shipmentRow
*
* @throws PostAtException
*
* @return mixed The raw SOAP API result containing ImportShipmentResult.
* See the official Post.at SOAP API documentation for details.
*/
public function importShipment(array $shipmentRow)
{
$shipmentRow = new ShipmentRow($shipmentRow);
$soapMethod = new ImportShipment($this->postAtClient);
return $soapMethod->call($shipmentRow);
}
}
@@ -0,0 +1,40 @@
<?php
namespace Xentral\Modules\Postat\SOAP;
use Xentral\Components\Logger\Logger;
/**
* Factory for new SoapService instances.
*
* A dedicated factory is needed because the configuration for the SOAP API
* service depends on the context where it is being used, and therefore the
* configuration cannot be injected directly into it by the DI container.
*/
class SoapServiceFactory
{
private $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
/**
* Create a new Post.at SOAP API service from the given config array.
*
* @param array $soapConfig
*
* @throws PostAtException
*
* @return SoapService
*/
public function fromConfigArray(array $soapConfig): SoapService
{
$soapConfig = new Config($soapConfig);
$client = new PostAtClient($soapConfig, $this->logger);
return new SoapService($client);
}
}