Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Legacy;
|
||||
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
|
||||
class DefaultController
|
||||
{
|
||||
/** @var Request $request */
|
||||
protected $request;
|
||||
|
||||
/** @var \Api $legacyApi */
|
||||
protected $legacyApi;
|
||||
|
||||
/** @var int $apiId */
|
||||
protected $apiId;
|
||||
|
||||
/**
|
||||
* @param \Api $legacyApi
|
||||
* @param Request $request
|
||||
* @param int $apiId
|
||||
*/
|
||||
public function __construct($legacyApi, $request, $apiId)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->legacyApi = $legacyApi;
|
||||
$this->apiId = $apiId;
|
||||
}
|
||||
|
||||
public function postAction()
|
||||
{
|
||||
$action = $this->request->attributes->get('action');
|
||||
$contentType = $this->request->getContentType();
|
||||
$content = $this->request->getContent();
|
||||
|
||||
if ($contentType === 'xml') {
|
||||
$this->legacyApi->app->Secure->POST['xml'] = '<xml>' . $content . '</xml>';
|
||||
}
|
||||
|
||||
if ($contentType === 'json') {
|
||||
$requestData = json_decode($content, true);
|
||||
$contentPrepared = isset($requestData['data']) ? json_encode($requestData['data']) : $content;
|
||||
$this->legacyApi->app->Secure->GET['json'] = true;
|
||||
$this->legacyApi->app->Secure->POST['json'] = $contentPrepared;
|
||||
}
|
||||
|
||||
// API-Methode aufrufen
|
||||
$this->legacyApi->setApiId($this->apiId);
|
||||
$this->legacyApi->app->Secure->GET['action'] = $action;
|
||||
$apiMethod = 'Api' . $action;
|
||||
|
||||
$actionMapping = [
|
||||
'AccountCreate' => 'ApiAdresseAccountCreate',
|
||||
'AccountEdit' => 'ApiAdresseAccountEdit',
|
||||
];
|
||||
if (isset($actionMapping[$action])) {
|
||||
$apiMethod = $actionMapping[$action];
|
||||
}
|
||||
|
||||
$this->legacyApi->$apiMethod();
|
||||
|
||||
// API-Methode liefert normalerweise selbst das Ergebnis aus und beendet die Script-Ausführung.
|
||||
// Falls aber eine nicht existierende API-Methode aufgerufen wird, läuft das Script in die Exception.
|
||||
throw new BadRequestException();
|
||||
}
|
||||
|
||||
public function readAction()
|
||||
{
|
||||
$this->legacyApi->setApiId($this->apiId);
|
||||
$action = $this->request->attributes->get('action');
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
namespace Xentral\Modules\Api\Controller\Legacy;
|
||||
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
|
||||
class GobNavConnectController
|
||||
{
|
||||
/** @var Request $request */
|
||||
protected $request;
|
||||
|
||||
/** @var LegacyApplication */
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @param LegacyApplication $app
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(LegacyApplication $app, Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
public function exampleAction()
|
||||
{
|
||||
$post = $this->request->getContent();
|
||||
$id = (int)$this->app->DB->Select(
|
||||
"SELECT id FROM uebertragungen_account WHERE aktiv = 1 AND xml_pdf = 'TransferGobNav' LIMIT 1"
|
||||
);
|
||||
if ($id > 0) {
|
||||
/** @var \Uebertragungen $transferObject */
|
||||
$transferObject = $this->app->loadModule('uebertragungen');
|
||||
if (!empty($transferObject)) {
|
||||
/** @var \TransferGobNav $transferGobnav */
|
||||
$transferGobnav = $transferObject->LoadTransferModul('TransferGobNav', $id);
|
||||
$transferGobnav->ParseRequest($post);
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,746 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Legacy;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
use Exception;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Modules\Api\Controller\Version1\AbstractController;
|
||||
use Xentral\Modules\Api\Converter\Converter;
|
||||
use Xentral\Modules\Api\Dashboard\WidgetData;
|
||||
use Xentral\Modules\Api\Dashboard\WidgetResult;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
|
||||
class MobileApiController extends AbstractController
|
||||
{
|
||||
/** @var LegacyApplication $app */
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @param LegacyApplication $app
|
||||
* @param Converter $converter
|
||||
* @param Database $database
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(LegacyApplication $app, Converter $converter, Database $database, Request $request)
|
||||
{
|
||||
parent::__construct(null, $database, $converter, $request, null);
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* controller for dashboard api call
|
||||
*
|
||||
* uses optional GET request parameter 'date'
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function dashboardAction()
|
||||
{
|
||||
$today = new DateTime('now');
|
||||
$interval = (int)$this->request->get->get('interval');
|
||||
$mode = $this->request->get->get('mode');
|
||||
if (!in_array($mode, ['month', 'week', 'year'])) {
|
||||
$mode = 'day';
|
||||
}
|
||||
if ($interval <= 0) {
|
||||
switch ($mode) {
|
||||
case 'year':
|
||||
$interval = 10;
|
||||
break;
|
||||
case 'month':
|
||||
$interval = 12;
|
||||
break;
|
||||
case 'week':
|
||||
default:
|
||||
$interval = 14;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$requestDate = $this->request->get->get('date');
|
||||
if ($requestDate !== null && !$this->isDate($requestDate)) {
|
||||
throw new BadRequestException('Bad request: parameter \'date\' expected format YYYY-mm-dd');
|
||||
}
|
||||
|
||||
if ($this->isDate($requestDate)) {
|
||||
$today = new DateTime($requestDate);
|
||||
}
|
||||
$yesterday = new DateTime($today->format('Y-m-d'));
|
||||
$yesterday = $yesterday->sub(new DateInterval('P1D'));
|
||||
$lastYear = new DateTime($today->format('Y'));
|
||||
$lastYear = $lastYear->sub(new DateInterval('P1Y'));
|
||||
|
||||
$result = new WidgetResult([]);
|
||||
//Dashboard mainpage
|
||||
$result->addData($this->getOrdersCountWidget($today, $yesterday));
|
||||
$result->addData($this->getTurnoverWidget($today, $yesterday));
|
||||
$result->addData($this->getDispatchWidget($today, $yesterday));
|
||||
$result->addData($this->getOrderValueWidget($today, $yesterday));
|
||||
$result->addData($this->getTwoWeeksTurnoverWidget($today, $interval, $mode));
|
||||
$result->addData($this->getNewCustomerWidget($today, $yesterday));
|
||||
$result->addData($this->getOpenTicketsWidget());
|
||||
//financial data page
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'turnover_current',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST_BIG,
|
||||
'Umsatz aktueller Monat (netto)',
|
||||
['current' => $this->getTurnoverThisMonth(), 'previous' => $this->getTurnoverLastMonth()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'turnover_lastmonth',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST_BIG,
|
||||
'Umsatz letzter Monat (netto)',
|
||||
['current' => $this->getTurnoverLastMonth(), 'previous' => $this->getTurnoverBeforeLastMonth()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'turnover_beforelastmonth',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Umsatz vorletzter Monat (netto)',
|
||||
['value' => $this->getTurnoverBeforeLastMonth()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'liability_open',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Offene Verbindlichkeiten (brutto)',
|
||||
['value' => $this->getOpenLiabilies()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'orders_open',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Offene Aufträge (netto)',
|
||||
['value' => $this->getOpenOrders()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'dunning_current',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Mahnwesen (brutto)',
|
||||
['value' => $this->getDunning()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'timetrack_current',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Zeit Gebucht',
|
||||
['value' => $this->getTimeTracking()],
|
||||
'customer',
|
||||
'',
|
||||
WidgetData::FORMAT_HOURS
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'subscription_nextmonth',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Abolauf nächsten Monat (brutto)',
|
||||
['value' => $this->getSubscriptionRun()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'accounts_total_current',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE_BIG,
|
||||
'Bankkonten Gesamt',
|
||||
['value' => $this->getAccountsTotal()],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
$result->addData(
|
||||
new WidgetData(
|
||||
'turnover_year_current',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST_BIG,
|
||||
'Gesamtumsatz laufendes Jahr (netto)',
|
||||
['current' => $this->getTurnoverByYear($today), 'previous' => $this->getTurnoverByYear($lastYear)],
|
||||
'cashflow',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns chart data for number of orders
|
||||
*
|
||||
* @param DateTimeInterface $currentDay today
|
||||
* @param DateTimeInterface $previousDay yesterday
|
||||
*
|
||||
* @return WidgetData chart data
|
||||
*/
|
||||
protected function getOrdersCountWidget(DateTimeInterface $currentDay, DateTimeInterface $previousDay)
|
||||
{
|
||||
$currentNumber = (int)$this->getOrdersCountByDay($currentDay);
|
||||
$previousNumber = (int)$this->getOrdersCountByDay($previousDay);
|
||||
|
||||
$widget = new WidgetData(
|
||||
'order_count',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST,
|
||||
'Aufträge',
|
||||
['current' => $currentNumber, 'previous' => $previousNumber],
|
||||
'basket'
|
||||
);
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function getTurnoverWidget(DateTimeInterface $currentDay, DateTimeInterface $previousDay)
|
||||
{
|
||||
return new WidgetData(
|
||||
'turnover_day',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST,
|
||||
'Umsatz (heute)',
|
||||
['current' => $this->getTurnoverByDay($currentDay), 'previous' => $this->getTurnoverByDay($previousDay)],
|
||||
'euro',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns chart data for new customers
|
||||
*
|
||||
* @param DateTimeInterface $currentDay today
|
||||
* @param DateTimeInterface $previousDay yesterday
|
||||
*
|
||||
* @return WidgetData chart data
|
||||
*/
|
||||
protected function getNewCustomerWidget(DateTimeInterface $currentDay, DateTimeInterface $previousDay)
|
||||
{
|
||||
$currentNumber = (int)$this->getNewCustomersByDay($currentDay);
|
||||
$previousNumber = (int)$this->getNewCustomersByDay($previousDay);
|
||||
|
||||
$widget = new WidgetData(
|
||||
'customer_new',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST,
|
||||
'Neukunden',
|
||||
['current' => $currentNumber, 'previous' => $previousNumber],
|
||||
'customer'
|
||||
);
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function getOpenTicketsWidget()
|
||||
{
|
||||
return new WidgetData(
|
||||
'tickets',
|
||||
WidgetData::WIDGET_TYPE_SIMPLE,
|
||||
'Offene Tickets',
|
||||
['value' => $this->getOpenTicketCount()],
|
||||
'ticket'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns chart data for dispatched packages
|
||||
*
|
||||
* @param DateTimeInterface $currentDay today
|
||||
* @param DateTimeInterface $previousDay yesterday
|
||||
*
|
||||
* @return WidgetData chart data
|
||||
*/
|
||||
protected function getDispatchWidget(DateTimeInterface $currentDay, DateTimeInterface $previousDay)
|
||||
{
|
||||
$currentNumber = (int)$this->getDispatchCountByDay($currentDay);
|
||||
$previousNumber = (int)$this->getDispatchCountByDay($previousDay);
|
||||
|
||||
$widget = new WidgetData(
|
||||
'dispatch_package',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST,
|
||||
'Pakete',
|
||||
['current' => $currentNumber, 'previous' => $previousNumber],
|
||||
'packages'
|
||||
);
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
protected function getOrderValueWidget(DateTimeInterface $today, DateTimeInterface $yesterday)
|
||||
{
|
||||
return new WidgetData(
|
||||
'order_value',
|
||||
WidgetData::WIDGET_TYPE_CONTRAST,
|
||||
'Aufträge Heute',
|
||||
['current' => $this->getOrderValueByDay($today), 'previous' => $this->getOrderValueByDay($yesterday)],
|
||||
'euro',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns chart data for 14 days turnover
|
||||
*
|
||||
* @param DateTimeInterface $currentDay
|
||||
* @param int $interval
|
||||
* @param string $mode
|
||||
*
|
||||
* @throws Exception
|
||||
* @return WidgetData chart data
|
||||
*/
|
||||
protected function getTwoWeeksTurnoverWidget(DateTimeInterface $currentDay, $interval = 0, $mode = 'day')
|
||||
{
|
||||
|
||||
$dateString = $currentDay->format('Y-m-d');
|
||||
switch ($mode) {
|
||||
case 'year':
|
||||
$modeName = 'Jahre';
|
||||
if ($interval <= 0) {
|
||||
$interval = 10;
|
||||
}
|
||||
$dayTo = new DateTime((new DateTime($dateString))->format('Y-12-31'));
|
||||
$dayFrom = new DateTime((new DateTime($dateString))->format('Y-01-01'));
|
||||
$dayFrom = $dayFrom->sub(new DateInterval(sprintf('P%dY', $interval - 1)));
|
||||
break;
|
||||
case 'month':
|
||||
$modeName = 'Monate';
|
||||
if ($interval <= 0) {
|
||||
$interval = 12;
|
||||
}
|
||||
$dayTo = (new DateTime((new DateTime($dateString))
|
||||
->format('Y-m-01')))
|
||||
->add(new DateInterval('P1M'))
|
||||
->sub(new DateInterval('P1D'));
|
||||
$dayFrom = new DateTime((new DateTime($dateString))->format('Y-m-01'));
|
||||
$dayFrom = $dayFrom->sub(new DateInterval(sprintf('P%dM', $interval - 1)));
|
||||
break;
|
||||
case 'week':
|
||||
$modeName = 'Wochen';
|
||||
if ($interval <= 0) {
|
||||
$interval = 14;
|
||||
}
|
||||
$dayTo = new DateTime($dateString);
|
||||
$weekDay = $dayTo->format('N');
|
||||
if ($weekDay < 7) {
|
||||
$dayTo->add(new DateInterval((sprintf('P%dD', 7 - $weekDay))));
|
||||
}
|
||||
$dayFrom = new DateTime($dayTo->format('Y-m-d'));
|
||||
$dayFrom = $dayFrom->sub(new DateInterval(sprintf('P%dD', $interval * 7 - 1)));
|
||||
break;
|
||||
default:
|
||||
$modeName = 'Tage';
|
||||
if ($interval <= 0) {
|
||||
$interval = 14;
|
||||
}
|
||||
$dayTo = new DateTime($dateString);
|
||||
$dayFrom = new DateTime($dateString);
|
||||
$dayFrom = $dayFrom->sub(new DateInterval(sprintf('P%dD', $interval - 1)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$data = $this->getTrunoverByDays($dayFrom, $dayTo, $mode);
|
||||
|
||||
$widget = new WidgetData(
|
||||
'turnover_period',
|
||||
WidgetData::WIDGET_TYPE_BARCHART,
|
||||
sprintf('Umsatz (%d %s)', $interval, $modeName),
|
||||
$data,
|
||||
'euro',
|
||||
'€',
|
||||
WidgetData::FORMAT_CURRENCY
|
||||
);
|
||||
|
||||
return $widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of orders created on specific date
|
||||
*
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function getOrdersCountByDay(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
if (!$this->isDate($dateFormatted)) {
|
||||
throw new InvalidArgumentException('Invalid date format.');
|
||||
}
|
||||
$sql = 'SELECT COUNT(a.id) AS anzahl FROM auftrag AS a WHERE a.datum = :dateFormatted';
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
|
||||
return (int)$result['anzahl'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns total revenue of specific day
|
||||
*
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return double
|
||||
*/
|
||||
protected function getOrderValueByDay(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
$sql = "SELECT SUM(a.gesamtsumme) AS `ordervalue`
|
||||
FROM auftrag AS a
|
||||
WHERE a.datum = :dateFormatted AND a.status!='angelegt'";
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
|
||||
return (float)$result['ordervalue'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of customers who placed their first order on specific date
|
||||
*
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function getNewCustomersByDay(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
if (!$this->isDate($dateFormatted)) {
|
||||
throw new InvalidArgumentException('Invalid date format.');
|
||||
}
|
||||
|
||||
$sql = "SELECT Count(DISTINCT adr.name) AS neukunden
|
||||
FROM adresse AS adr JOIN auftrag AS auf
|
||||
ON adr.id = auf.adresse
|
||||
WHERE adr.id NOT IN
|
||||
(SELECT DISTINCT a.id
|
||||
FROM adresse AS a RIGHT JOIN auftrag AS au
|
||||
ON a.id = au.adresse
|
||||
WHERE au.status<>'angelegt' AND au.datum <> :dateFormatted AND au.id IS NOT NULL
|
||||
);";
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
|
||||
return (int)$result['neukunden'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of packeges dispatched on specific date
|
||||
*
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
protected function getDispatchCountByDay(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
if (!$this->isDate($dateFormatted)) {
|
||||
throw new InvalidArgumentException('Invalid date format.');
|
||||
}
|
||||
$sql = 'SELECT COUNT(v.id) AS anzahlpakete FROM versand AS v WHERE v.versendet_am = :dateFormatted';
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
|
||||
return (int)$result['anzahlpakete'];
|
||||
}
|
||||
|
||||
protected function getOpenTicketCount()
|
||||
{
|
||||
return (float)$this->app->erp->AnzahlOffeneTickets(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if specific string represents a date.
|
||||
*
|
||||
* Accepted date format 'Y-m-d'
|
||||
*
|
||||
* @example isDate('2019-08-23') -> true
|
||||
*
|
||||
* @param string $dateString
|
||||
*
|
||||
* @return bool true=string represents a date
|
||||
*/
|
||||
protected function isDate($dateString)
|
||||
{
|
||||
$date = (string)$dateString;
|
||||
if (preg_match('/^[1-9]\d{3}-\d{2}-\d{2}$/', $date)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
protected function getCashValues($key)
|
||||
{
|
||||
$obj = $this->app->loadModule('managementboard');
|
||||
if (empty($obj)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = $obj->getCashValues($key);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $dateFrom
|
||||
* @param DateTimeInterface $dateTo
|
||||
* @param string $mode
|
||||
*
|
||||
* @throws Exception
|
||||
* @return array
|
||||
*/
|
||||
private function getTrunoverByDays(DateTimeInterface $dateFrom, DateTimeInterface $dateTo, $mode = 'day')
|
||||
{
|
||||
if ($dateFrom > $dateTo) {
|
||||
throw new BadRequestException('Bad request: parameter \'dateFrom\' is later than parameter \'dateTo\'');
|
||||
}
|
||||
|
||||
switch ($mode) {
|
||||
case 'year':
|
||||
$formatDb = '%Y';
|
||||
$formatPhp = 'Y';
|
||||
break;
|
||||
case 'month':
|
||||
$formatDb = '%m/%Y';
|
||||
$formatPhp = 'm/Y';
|
||||
break;
|
||||
case 'week':
|
||||
$formatDb = '%v/%x';
|
||||
$formatPhp = 'W/o';
|
||||
break;
|
||||
default:
|
||||
$formatDb = '%Y-%m-%d';
|
||||
$formatPhp = 'Y-m-d';
|
||||
break;
|
||||
}
|
||||
|
||||
$dateFormattedFrom = $dateFrom->format('Y-m-d');
|
||||
$dateFormattedTo = $dateTo->format('Y-m-d');
|
||||
$values = [
|
||||
'dateFormattedFrom' => $dateFormattedFrom,
|
||||
'dateFormattedTo' => $dateFormattedTo,
|
||||
];
|
||||
|
||||
$sqlInvoices = sprintf(
|
||||
"SELECT DATE_FORMAT(r.datum,'%s') AS `date`, sum(r.umsatz_netto) AS `commitment`
|
||||
FROM rechnung AS r
|
||||
WHERE DATE_FORMAT(r.datum,'%%Y-%%m-%%d') >= :dateFormattedFrom
|
||||
AND DATE_FORMAT(r.datum,'%%Y-%%m-%%d') <= :dateFormattedTo
|
||||
AND r.status!='angelegt'
|
||||
GROUP BY DATE_FORMAT(r.datum,'%s')",
|
||||
$formatDb, $formatDb
|
||||
);
|
||||
$resultInvoices = $this->db->fetchPairs($sqlInvoices, $values);
|
||||
$sqlReturnOrders = sprintf(
|
||||
"SELECT DATE_FORMAT(g.datum,'%s') AS `date`, sum(g.umsatz_netto) AS `credit`
|
||||
FROM gutschrift AS g
|
||||
WHERE DATE_FORMAT(g.datum,'%%Y-%%m-%%d') >= :dateFormattedFrom
|
||||
AND DATE_FORMAT(g.datum,'%%Y-%%m-%%d') <= :dateFormattedTo
|
||||
AND g.status!='angelegt'
|
||||
GROUP BY DATE_FORMAT(g.datum,'%s')",
|
||||
$formatDb, $formatDb
|
||||
);
|
||||
$resultReturnOrders = $this->db->fetchPairs($sqlReturnOrders, $values);
|
||||
|
||||
$day = new DateTime($dateFormattedFrom);
|
||||
$return = [];
|
||||
while ($day <= $dateTo) {
|
||||
$dayFormated = $day->format($formatPhp);
|
||||
$return[$dayFormated] =
|
||||
(empty($resultInvoices[$dayFormated]) ? 0.0 : $resultInvoices[$dayFormated])
|
||||
- (empty($resultReturnOrders[$dayFormated]) ? 0.0 : $resultReturnOrders[$dayFormated]);
|
||||
|
||||
switch ($mode) {
|
||||
case 'year':
|
||||
$day = $day->add(new DateInterval('P1Y'));
|
||||
break;
|
||||
case 'month':
|
||||
$day = $day->add(new DateInterval('P1M'));
|
||||
break;
|
||||
case 'week':
|
||||
$day = $day->add(new DateInterval('P7D'));
|
||||
break;
|
||||
default:
|
||||
$day = $day->add(new DateInterval('P1D'));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getTurnoverByDay(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y-m-d');
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$sql = "SELECT sum(r.umsatz_netto) AS `commitment`
|
||||
FROM rechnung AS r
|
||||
WHERE DATE_FORMAT(r.datum,'%Y-%m-%d')=:dateFormatted AND r.status!='angelegt'";
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
if (empty($result)) {
|
||||
return 0.0;
|
||||
}
|
||||
$commitment = (float)$result['commitment'];
|
||||
|
||||
$sql = "SELECT sum(g.umsatz_netto) AS `credit`
|
||||
FROM gutschrift AS g
|
||||
WHERE DATE_FORMAT(g.datum,'%Y-%m-%d')=:dateFormatted AND g.status!='angelegt'";
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
if (empty($result)) {
|
||||
return 0.0;
|
||||
}
|
||||
$credit = (float)$result['credit'];
|
||||
|
||||
return $commitment - $credit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTimeInterface $date
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private function getTurnoverByYear(DateTimeInterface $date)
|
||||
{
|
||||
$dateFormatted = $date->format('Y');
|
||||
$values = ['dateFormatted' => $dateFormatted];
|
||||
$sql = "SELECT sum(r.umsatz_netto) AS `commitment`
|
||||
FROM rechnung AS r
|
||||
WHERE DATE_FORMAT(r.datum,'%Y')=:dateFormatted AND r.status!='angelegt'";
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
if (empty($result)) {
|
||||
return 0.0;
|
||||
}
|
||||
$commitment = (float)$result['commitment'];
|
||||
|
||||
$sql = "SELECT sum(g.umsatz_netto) AS `credit`
|
||||
FROM gutschrift AS g
|
||||
WHERE DATE_FORMAT(g.datum,'%Y')=:dateFormatted AND g.status!='angelegt'";
|
||||
$result = $this->db->fetchRow($sql, $values);
|
||||
if (empty($result)) {
|
||||
return 0.0;
|
||||
}
|
||||
$credit = (float)$result['credit'];
|
||||
|
||||
return $commitment - $credit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getTurnoverThisMonth()
|
||||
{
|
||||
return (float)$this->getCashValues('13.1') - (float)$this->getCashValues('13.2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getTurnoverLastMonth()
|
||||
{
|
||||
return (float)$this->getCashValues('17.1') - (float)$this->getCashValues('17.2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getTurnoverBeforeLastMonth()
|
||||
{
|
||||
return (float)$this->getCashValues('21.1') - (float)$this->getCashValues('21.2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getOpenLiabilies()
|
||||
{
|
||||
return (float)$this->getCashValues(9);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getOpenOrders()
|
||||
{
|
||||
return (float)$this->getCashValues(10);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getDunning()
|
||||
{
|
||||
return (float)$this->getCashValues(11);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getTimeTracking()
|
||||
{
|
||||
return (float)$this->app->DB->Select(
|
||||
"SELECT sum(TIMESTAMPDIFF(HOUR,von,bis))
|
||||
FROM zeiterfassung
|
||||
WHERE DATE_FORMAT(von,'%m-%Y') = DATE_FORMAT(NOW(),'%m-%Y')"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getSubscriptionRun()
|
||||
{
|
||||
$obj = $this->app->erp->LoadModul('rechnungslauf');
|
||||
$value = 0.0;
|
||||
if ($obj) {
|
||||
$value = (float)$obj->RechnungslaufRechnungslauf(true);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getAccountsTotal()
|
||||
{
|
||||
return (float)$this->getCashValues(25);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Legacy;
|
||||
|
||||
use TransferOpentrans;
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Converter\OpenTransConverter;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
|
||||
class OpenTransConnectController
|
||||
{
|
||||
/** @var Request $request */
|
||||
protected $request;
|
||||
|
||||
/** @var LegacyApplication $app */
|
||||
protected $app;
|
||||
|
||||
/** @var int $accountId */
|
||||
protected $accountId;
|
||||
|
||||
/**
|
||||
* @param LegacyApplication $app
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(LegacyApplication $app, OpenTransConverter $converter, Request $request, $accountId)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->converter = $converter;
|
||||
$this->app = $app;
|
||||
$this->accountId = $accountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteOrder()
|
||||
{
|
||||
$orderId = $this->getDoctypeIdByRequestAttributes('order');
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
list($result, $statusCode, $rootNode) = $transferOpenTrans->deleteOrder($orderId);
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml($result, $rootNode);
|
||||
}
|
||||
if(empty($result)) {
|
||||
throw new ResourceNotFoundException('Auftrag konnte nicht gelöscht werden');
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $doctype
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getDoctypeIdByRequestAttributes($doctype = 'deliverynote')
|
||||
{
|
||||
$id = (int)$this->request->attributes->get('id');
|
||||
$orderId = $this->request->attributes->get('orderid');
|
||||
$ordernumber = $orderId > 0?'':$this->request->attributes->get('ordernumber');
|
||||
$extOrder = $orderId > 0 || !empty($ordernumber)?'':$this->request->attributes->get('extorder');
|
||||
if($id > 0) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
if(!empty($ordernumber)) {
|
||||
$orderId = $this->app->DB->Select(
|
||||
sprintf(
|
||||
"SELECT id FROM auftrag WHERE belegnr = '%s' AND belegnr <> '' LIMIT 1",
|
||||
$this->app->DB->real_escape_string($ordernumber)
|
||||
)
|
||||
);
|
||||
if(empty($orderId)) {
|
||||
throw new ResourceNotFoundException(sprintf('Auftrag mit Belegnr \'%s\' nicht gefunden', $ordernumber));
|
||||
}
|
||||
}
|
||||
if(!empty($extOrder)) {
|
||||
$orderId = $this->app->DB->Select(
|
||||
sprintf(
|
||||
"SELECT id FROM auftrag WHERE internet = '%s' AND internet <> '' LIMIT 1",
|
||||
$this->app->DB->real_escape_string($extOrder)
|
||||
)
|
||||
);
|
||||
if(empty($orderId)) {
|
||||
throw new ResourceNotFoundException(sprintf('Auftrag mit Externer Belegnr \'%s\' nicht gefunden', $extOrder));
|
||||
}
|
||||
}
|
||||
|
||||
if(!empty($orderId)) {
|
||||
switch($doctype) {
|
||||
case 'order':
|
||||
return $orderId;
|
||||
break;
|
||||
case 'invoice':
|
||||
$id = $this->app->DB->Select(
|
||||
sprintf(
|
||||
"SELECT id FROM rechnung WHERE auftragid = %d ORDER BY status = 'storniert' LIMIT 1",
|
||||
$orderId
|
||||
)
|
||||
);
|
||||
if(!empty($id)) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException(
|
||||
sprintf('Rechnung mit Order-ID \'%s\' nicht gefunden',
|
||||
$orderId
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'deliverynote':
|
||||
default:
|
||||
$id = $this->app->DB->Select(
|
||||
sprintf(
|
||||
"SELECT id FROM lieferschein WHERE auftragid = %d ORDER BY status = 'storniert' LIMIT 1",
|
||||
$orderId
|
||||
)
|
||||
);
|
||||
if(!empty($id)) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
throw new ResourceNotFoundException(
|
||||
sprintf('Lieferschein mit Order-ID \'%s\' nicht gefunden',
|
||||
$orderId
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function readDispatchnotification()
|
||||
{
|
||||
$deliveryNoteId = $this->getDoctypeIdByRequestAttributes('deliverynote');
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
|
||||
list($result, $statusCode, $rootNode) = $transferOpenTrans->getDispatchnotification($deliveryNoteId);
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml($result, $rootNode);
|
||||
}
|
||||
if(empty($result)) {
|
||||
throw new ResourceNotFoundException(
|
||||
sprintf('Lieferschein mit ID \'%s\' nicht gefunden',
|
||||
$deliveryNoteId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $apiId
|
||||
* @param string $request
|
||||
* @param string $type
|
||||
* @param bool $isIncoming
|
||||
* @param string $doctype
|
||||
* @param string $status
|
||||
* @param int $doctypeId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function insertApiRequestLog(
|
||||
$apiId, $request, $type, $isIncoming, $doctype, $status = '', $doctypeId = 0
|
||||
)
|
||||
{
|
||||
$this->app->DB->Insert(
|
||||
sprintf(
|
||||
"INSERT INTO `api_request_response_log`
|
||||
(api_id, raw_request, raw_response, type, status, doctype, doctype_id, is_incomming, created_at)
|
||||
VALUES (%d, '%s', '%s', '%s', '%s','%s',%d,%d,NOW()) ",
|
||||
$apiId,
|
||||
($isIncoming?$this->app->DB->real_escape_string($request):''),
|
||||
(!$isIncoming?$this->app->DB->real_escape_string($request):''),
|
||||
$this->app->DB->real_escape_string($type),
|
||||
$this->app->DB->real_escape_string($status),
|
||||
$this->app->DB->real_escape_string($doctype),
|
||||
$doctypeId,
|
||||
$isIncoming
|
||||
)
|
||||
);
|
||||
|
||||
return (int)$this->app->DB->GetInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $logId
|
||||
* @param string $status
|
||||
*/
|
||||
protected function setLogStatus($logId, $status)
|
||||
{
|
||||
$this->app->DB->Update(
|
||||
sprintf(
|
||||
"UPDATE `api_request_response_log` SET `status` = '%s' WHERE `id` = %d",
|
||||
$this->app->DB->real_escape_string($status),
|
||||
$logId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $logId
|
||||
* @param int $doctypeId
|
||||
*/
|
||||
protected function setLogDoctypeId($logId, $doctypeId)
|
||||
{
|
||||
$this->app->DB->Update(
|
||||
sprintf(
|
||||
'UPDATE `api_request_response_log` SET `doctype_id` = %d WHERE `id` = %d',
|
||||
$doctypeId,
|
||||
$logId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function createOrder()
|
||||
{
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
if(!empty($this->accountId)) {
|
||||
$transferOpenTrans->setApiId($this->accountId);
|
||||
}
|
||||
$post = $this->request->getContent();
|
||||
|
||||
if(empty($post)) {
|
||||
throw new ResourceNotFoundException('Data is empty');
|
||||
}
|
||||
|
||||
$logId = $this->insertApiRequestLog($this->accountId, $post, 'create_order',true,'auftrag');
|
||||
|
||||
$xml = $this->converter->getXmlFromString($post);
|
||||
if(empty($xml)) {
|
||||
$this->setLogStatus($logId, 'error');
|
||||
throw new ResourceNotFoundException('Data is no valid Xml');
|
||||
}
|
||||
|
||||
list($result, $statusCode, $rootNode, $orderId) = $transferOpenTrans->createOrder($xml);
|
||||
if(!empty($orderId)) {
|
||||
$this->setLogDoctypeId($logId, $orderId);
|
||||
}
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml($result, $rootNode);
|
||||
}
|
||||
if(empty($result)) {
|
||||
$this->setLogStatus($logId, 'error');
|
||||
throw new ResourceNotFoundException('Auftrag konnte nicht erstellt werden');
|
||||
}
|
||||
|
||||
if($statusCode === Response::HTTP_CREATED) {
|
||||
$this->setLogStatus($logId, 'ok');
|
||||
}
|
||||
else {
|
||||
$this->setLogStatus($logId, 'error');
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function updateDispatchnotification()
|
||||
{
|
||||
$deliveryNoteId = $this->getDoctypeIdByRequestAttributes('deliverynote');
|
||||
$post = $this->request->getContent();
|
||||
if(empty($post)) {
|
||||
throw new ResourceNotFoundException('Data is empty');
|
||||
}
|
||||
$logId = $this->insertApiRequestLog(
|
||||
$this->accountId, $post, 'update_dispatchnotification',true,'lieferschein','', $deliveryNoteId
|
||||
);
|
||||
|
||||
$xml = $this->converter->getXmlFromString($post);
|
||||
if(empty($xml)) {
|
||||
$this->setLogStatus($logId, 'error');
|
||||
throw new ResourceNotFoundException('Data is no valid Xml');
|
||||
}
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
list($result, $statusCode, $rootNode) = $transferOpenTrans->updateDispatchnotification($deliveryNoteId, $xml);
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml(
|
||||
$result,
|
||||
$rootNode
|
||||
);
|
||||
}
|
||||
|
||||
if($statusCode === Response::HTTP_OK) {
|
||||
$this->setLogStatus($logId, 'ok');
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function readInvoice()
|
||||
{
|
||||
$invoiceId = $this->getDoctypeIdByRequestAttributes('invoice');
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
|
||||
list($result, $statusCode, $rootNode) = $transferOpenTrans->getInvoice($invoiceId);
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml(
|
||||
$result,
|
||||
$rootNode
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($result)) {
|
||||
throw new ResourceNotFoundException(sprintf('Rechnung mit ID \'%s\' nicht gefunden', $invoiceId));
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function readOrder()
|
||||
{
|
||||
$orderId = $this->getDoctypeIdByRequestAttributes('order');
|
||||
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
|
||||
list($result,$statusCode, $rootNode) = $transferOpenTrans->getOrder($orderId);
|
||||
if(is_array($result)) {
|
||||
$result = $this->converter->arrayToXml
|
||||
(
|
||||
$result,
|
||||
$rootNode
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($result)) {
|
||||
throw new ResourceNotFoundException(sprintf('Auftrag mit ID \'%s\' nicht gefunden', $orderId));
|
||||
}
|
||||
|
||||
return $this->sendResponse($result,$statusCode);
|
||||
}
|
||||
|
||||
public function updateOrder()
|
||||
{
|
||||
$orderId = $this->getDoctypeIdByRequestAttributes('order');
|
||||
|
||||
$transferOpenTrans = $this->getTransferObject();
|
||||
$order = $transferOpenTrans->getOrderArr($orderId);
|
||||
if(empty($order)) {
|
||||
throw new ResourceNotFoundException(sprintf('Auftrag mit ID \'%s\' nicht gefunden', $orderId));
|
||||
}
|
||||
$post = $this->request->getContent();
|
||||
$logId = $this->insertApiRequestLog(
|
||||
$this->accountId, $post, 'update_order',true,'auftrag','', $orderId
|
||||
);
|
||||
$arr = $this->converter->toArray($post);
|
||||
if(empty($arr)) {
|
||||
$this->setLogStatus($logId, 'error');
|
||||
throw new ResourceNotFoundException('XML konnte nicht geparsed werden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $contentType [xml|json]
|
||||
* @param int $statusCode HTTP-Statuscode
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function sendResponse($data, $contentType, $statusCode = Response::HTTP_OK)
|
||||
{
|
||||
return new Response(
|
||||
$data,
|
||||
$statusCode,
|
||||
['Content-Type' => 'application/xml; charset=UTF-8']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TransferOpentrans
|
||||
*/
|
||||
private function getTransferObject()
|
||||
{
|
||||
$id = (int)$this->app->DB->Select(
|
||||
"SELECT id FROM uebertragungen_account WHERE aktiv = 1 AND xml_pdf = 'TransferOpenTrans' AND id = %d LIMIT 1",
|
||||
$this->accountId
|
||||
);
|
||||
if($id < 0) {
|
||||
throw new ResourceNotFoundException('TransferOpenTrans Module not found');
|
||||
}
|
||||
|
||||
/** @var \Uebertragungen $transferObject */
|
||||
$transferObject = $this->app->loadModule('uebertragungen');
|
||||
if(empty($transferObject)) {
|
||||
throw new ResourceNotFoundException('TransferOpenTrans Module not found');
|
||||
}
|
||||
|
||||
return $transferObject->LoadTransferModul('TransferOpentrans', $id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Legacy;
|
||||
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
|
||||
class ShopimportController
|
||||
{
|
||||
/** @var Request $request */
|
||||
protected $request;
|
||||
|
||||
/** @var LegacyApplication $app */
|
||||
protected $app;
|
||||
|
||||
/** @var int $accountId */
|
||||
protected $accountId;
|
||||
|
||||
/**
|
||||
* @param LegacyApplication $app
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(LegacyApplication $app, Request $request, $accountId)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->app = $app;
|
||||
$this->accountId = $accountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $onlyActive
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getShopFromApi($onlyActive = true)
|
||||
{
|
||||
$shop = $this->app->DB->SelectRow(
|
||||
sprintf(
|
||||
'SELECT * FROM `shopexport` WHERE `api_account_id` = %d LIMIT 1',
|
||||
$this->accountId
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($shop)) {
|
||||
throw new ResourceNotFoundException('Shop not found');
|
||||
}
|
||||
|
||||
if($onlyActive && empty($shop['aktiv'])) {
|
||||
throw new ResourceNotFoundException('Shop not connected');
|
||||
}
|
||||
|
||||
return $shop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function auth()
|
||||
{
|
||||
$shop = $this->getShopFromApi();
|
||||
$pageContents = $this->app->remote->RemoteConnection($shop['id'], true);
|
||||
if (strpos($pageContents, 'success') !== 0) {
|
||||
throw new ResourceNotFoundException('Auth Error ' . $pageContents);
|
||||
}
|
||||
|
||||
/*$this->app->DB->Update(
|
||||
sprintf(
|
||||
"UPDATE `shopexport` SET `api_account_token` = '' WHERE `id` = %d",
|
||||
$shop['id']
|
||||
)
|
||||
);*/
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getOrderByRequest()
|
||||
{
|
||||
$orderNumber = $this->request->attributes->get('ordernumber');
|
||||
$orderNumber = base64_decode($orderNumber);
|
||||
if (empty($orderNumber)) {
|
||||
throw new ResourceNotFoundException(
|
||||
'Ordernumber is empty'
|
||||
);
|
||||
}
|
||||
|
||||
return $orderNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $shopId
|
||||
* @param bool $withDbCheck
|
||||
*/
|
||||
public function getArticleByRequest($shopId, $withDbCheck = true)
|
||||
{
|
||||
$articlenumber = $this->request->attributes->get('articlenumber');
|
||||
$articlenumber = base64_decode($articlenumber);
|
||||
if (empty($articlenumber)) {
|
||||
throw new ResourceNotFoundException(
|
||||
'Articlenumber is empty'
|
||||
);
|
||||
}
|
||||
|
||||
$article = $this->app->DB->SelectRow(
|
||||
sprintf(
|
||||
"SELECT art.id, art.projekt FROM `artikel` AS art
|
||||
LEFT JOIN `artikelnummer_fremdnummern` AS af on art.id = af.artikel AND af.aktiv = 1 AND af.shopid = %d
|
||||
WHERE (art.nummer = '%s' OR af.nummer = '%s') AND (art.geloescht = 0 OR art.geloescht IS NULL)
|
||||
ORDER BY af.id DESC
|
||||
LIMIT 1",
|
||||
$shopId,
|
||||
$this->app->DB->real_escape_string($articlenumber),
|
||||
$this->app->DB->real_escape_string($articlenumber)
|
||||
)
|
||||
);
|
||||
if (empty($article)) {
|
||||
if($withDbCheck) {
|
||||
throw new ResourceNotFoundException(
|
||||
sprintf('Articlenumber %s not found', $articlenumber)
|
||||
);
|
||||
}
|
||||
$article = [];
|
||||
}
|
||||
|
||||
$article['number'] = $articlenumber;
|
||||
|
||||
return $article;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function putArticleToShop()
|
||||
{
|
||||
$this->auth();
|
||||
$shop = $this->getShopFromApi();
|
||||
$article = $this->getArticleByRequest($shop['id']);
|
||||
|
||||
$ret = $this->app->remote->RemoteSendArticleList($shop['id'],[$article['id']], $article['number'], false);
|
||||
if (empty($ret) || !is_array($ret) || isset($ret['error'])) {
|
||||
return $this->sendResponse(
|
||||
json_encode(['success' => false]),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function getStatus()
|
||||
{
|
||||
$shop = $this->getShopFromApi(false);
|
||||
$status = !empty($shop['aktiv']);
|
||||
if($status) {
|
||||
$this->auth();
|
||||
}
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true, 'connected' => $status]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function postDisconnect()
|
||||
{
|
||||
$shop = $this->getShopFromApi(false);
|
||||
$status = !empty($shop['aktiv']);
|
||||
if(!$status) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => false,'error'=>'shop allready disconnected']
|
||||
),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
$this->app->DB->Update(sprintf("UPDATE `shopexport` SET `aktiv` = 0 WHERE `id` = %d", $shop['id']));
|
||||
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => true,'message'=>'shop disconnected']
|
||||
),
|
||||
Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function postReconnect()
|
||||
{
|
||||
$shop = $this->getShopFromApi(false);
|
||||
$status = !empty($shop['aktiv']);
|
||||
if($status) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => false,'error'=>'shop allready connected']
|
||||
),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
$this->app->DB->Update(sprintf("UPDATE `shopexport` SET `aktiv` = 1 WHERE `id` = %d", $shop['id']));
|
||||
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => true,'message'=>'shop reconnected']
|
||||
),
|
||||
Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function putOrderToXentral()
|
||||
{
|
||||
$this->auth();
|
||||
$shop = $this->getShopFromApi();
|
||||
$orderNumber = $this->getOrderByRequest();
|
||||
/** @var \Shopimport $shopimport */
|
||||
$shopimport = $this->app->loadModule('shopimport');
|
||||
$res = $shopimport->importSingleOrder(
|
||||
$shop['id'], $orderNumber, empty($shop['demomodus']), $shop['projekt'], true
|
||||
);
|
||||
if(empty($res['status'])) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => false,'error'=>$res['error']]
|
||||
),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
if($shop['auftraegeaufspaeter']) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
[
|
||||
'success' => true,
|
||||
'message'=>$res['info'],
|
||||
]
|
||||
),
|
||||
Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
$cart = $this->app->DB->SelectRow(
|
||||
sprintf('SELECT * FROM `shopimport_auftraege` WHERE `id` = %d', $res['id'])
|
||||
);
|
||||
[$customerNumber, $customerNumberImported] = $shopimport->getCustomerNumberFromShopCart($cart);
|
||||
$res = $shopimport->importShopOrder(
|
||||
$res['id'], $shop['utf8codierung'],
|
||||
$customerNumber, $customerNumberImported,
|
||||
$unknownPaymentTypes
|
||||
);
|
||||
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
[
|
||||
'success' => true,
|
||||
'message'=>$res['info'],
|
||||
]
|
||||
),
|
||||
Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function putArticleToXentral()
|
||||
{
|
||||
$this->auth();
|
||||
$shop = $this->getShopFromApi();
|
||||
$article = $this->getArticleByRequest($shop['id'], false);
|
||||
$ret = $this->app->remote->RemoteGetArticle($shop['id'], $article['number'], true);
|
||||
if (empty($ret) || !is_array($ret) || isset($ret['error'])) {
|
||||
return $this->sendResponse(
|
||||
json_encode(['success' => false]),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
if(empty($article['id'])) {
|
||||
$article = $this->getArticleByRequest($shop['id'], false);
|
||||
}
|
||||
if(!empty($article['id'])) {
|
||||
/** @var \Artikel $articleObj */
|
||||
$articleObj = $this->app->loadModule('artikel');
|
||||
$articleObj->updateShopArticle($article['id'], $ret);
|
||||
}
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function syncStorage()
|
||||
{
|
||||
//$this->auth();
|
||||
$shop = $this->getShopFromApi();
|
||||
$article = $this->getArticleByRequest($shop['id']);
|
||||
$ret = $this->app->remote->RemoteSendArticleList($shop['id'], [$article['id']],$article['number'], true);
|
||||
if (empty($ret) || (!is_array($ret) && $ret !== 1) || isset($ret['error'])) {
|
||||
return $this->sendResponse(
|
||||
json_encode(['success' => false]),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function getArticleSyncState()
|
||||
{
|
||||
$shop = $this->getShopFromApi();
|
||||
$count = $this->app->DB->Select(
|
||||
sprintf(
|
||||
'SELECT COUNT(`ao`.`id`)
|
||||
FROM `artikel_onlineshops` AS `ao`
|
||||
INNER JOIN `artikel` AS `art` ON `ao`.artikel = `art`.`id` AND `art`.geloescht = 0
|
||||
WHERE `ao`.shop = %d AND `ao`.`aktiv` = 1',
|
||||
$shop['id']
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true, 'count' => $count]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function postDistconnect()
|
||||
{
|
||||
//postReconnect
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function getModulelinks()
|
||||
{
|
||||
$shop = $this->getShopFromApi();
|
||||
$shopId = $shop['id'];
|
||||
/** @var \Onlineshops $onlineShop */
|
||||
$onlineShop = $this->app->loadModule('onlineshops');
|
||||
$moduleList = $onlineShop->getModulelinks($shopId);
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
['success' => true, 'modulelist' => $moduleList]
|
||||
),
|
||||
Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
$shop = $this->getShopFromApi();
|
||||
$shopId = $shop['id'];
|
||||
$stats = [];
|
||||
/** @var \Verkaufszahlen $verkaufszahlen */
|
||||
$verkaufszahlen = $this->app->loadModule('verkaufszahlen');
|
||||
|
||||
[$stats['orders_in_shipment'], $stats['orders_open']] = $verkaufszahlen->getVersandStats(
|
||||
sprintf(' AND a.shop = %d ', $shopId)
|
||||
);
|
||||
|
||||
$stats['packages_yesterday'] = $verkaufszahlen->getPackages(
|
||||
" v.versendet_am=DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 1 day),'%Y-%m-%d') '",
|
||||
sprintf('INNER JOIN `auftrag` AS `a` ON l.auftragid = a.id AND a.shop = %d', $shopId)
|
||||
);
|
||||
$stats['packages_today'] = $verkaufszahlen->getPackages(
|
||||
" v.versendet_am=DATE_FORMAT(NOW(),'%Y-%m-%d') '",
|
||||
sprintf('INNER JOIN `auftrag` AS `a` ON l.auftragid = a.id AND a.shop = %d', $shopId)
|
||||
);
|
||||
|
||||
[
|
||||
$stats['order_income_yesterday'],
|
||||
$stats['contribution_margin_yesterday'],
|
||||
$stats['contribution_margin_perc_yesterday']
|
||||
] =
|
||||
$verkaufszahlen->getOrderStats(
|
||||
sprintf(
|
||||
" AND `datum` = DATE_FORMAT(DATE_SUB(NOW(),INTERVAL 1 day),'%%Y-%%m-%%d') AND `shop` = %d ",
|
||||
$shopId
|
||||
)
|
||||
);
|
||||
[
|
||||
$stats['order_income_today'],
|
||||
$stats['contribution_margin_today'],
|
||||
$stats['contribution_margin_perc_today']
|
||||
] =
|
||||
$verkaufszahlen->getOrderStats(
|
||||
sprintf(
|
||||
" AND `datum` = DATE_FORMAT(NOW(),'%%Y-%%m-%%d') AND `shop` = %d ",
|
||||
$shopId
|
||||
)
|
||||
);
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true, 'stats' => $stats]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function postRefund()
|
||||
{
|
||||
$shop = $this->getShopFromApi();
|
||||
$shopId = $shop['id'];
|
||||
$post = $this->request->getContent();
|
||||
if(empty($post)) {
|
||||
throw new ResourceNotFoundException('Data is empty');
|
||||
}
|
||||
$contentType = $this->request->getContentType();
|
||||
$data = null;
|
||||
if ($contentType === 'json' || $contentType === null) {
|
||||
$data = json_decode($post);
|
||||
}
|
||||
if ($data === null && ($contentType === 'xml' || $contentType === null)) {
|
||||
$data = simplexml_load_string($post);
|
||||
}
|
||||
if(empty($post)) {
|
||||
throw new ResourceNotFoundException('could not parse Data');
|
||||
}
|
||||
|
||||
/** @var \Shopimport $shopimport */
|
||||
$shopimport = $this->app->loadModule('shopimport');
|
||||
if($shopimport === null || !method_exists($shopimport, 'Refund')) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
[
|
||||
'success' => false,
|
||||
'error'=>'not implemented'
|
||||
]
|
||||
),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$ret = $shopimport->Refund($shopId, $data);
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
return $this->sendResponse(
|
||||
json_encode(
|
||||
[
|
||||
'success' => false,
|
||||
'error' => $e->getMessage(),
|
||||
]
|
||||
),
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
return $this->sendResponse(json_encode(['success' => true,'creditnote_id' => $ret]), Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param string $contentType [xml|json]
|
||||
* @param int $statusCode HTTP-Statuscode
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function sendResponse($data, $contentType, $statusCode = Response::HTTP_OK)
|
||||
{
|
||||
return new Response(
|
||||
$data,
|
||||
$statusCode,
|
||||
['Content-Type' => 'application/json; charset=UTF-8']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Converter\Converter;
|
||||
use Xentral\Modules\Api\Converter\Exception\ConvertionException;
|
||||
use Xentral\Modules\Api\Error\ApiError;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Api\Resource\AbstractResource;
|
||||
use Xentral\Modules\Api\Resource\ResourceManager;
|
||||
use Xentral\Modules\Api\Resource\Result\AbstractResult;
|
||||
|
||||
abstract class AbstractController
|
||||
{
|
||||
/** @var Database $db */
|
||||
protected $db;
|
||||
|
||||
/** @var Request $request */
|
||||
protected $request;
|
||||
|
||||
/** @var Response $response */
|
||||
protected $response;
|
||||
|
||||
/** @var ResourceManager $resourceManager */
|
||||
protected $resourceManager;
|
||||
|
||||
/** @var string $resourceClass */
|
||||
protected $resourceClass;
|
||||
|
||||
/** @var \Api $db */
|
||||
protected $legacyApi;
|
||||
|
||||
/**
|
||||
* @param \Api $legacyApi
|
||||
* @param Database $database
|
||||
* @param Converter $converter
|
||||
* @param Request $request
|
||||
* @param ResourceManager $resource
|
||||
*/
|
||||
public function __construct($legacyApi, $database, $converter, $request, $resource)
|
||||
{
|
||||
$this->resourceManager = $resource;
|
||||
$this->legacyApi = $legacyApi;
|
||||
$this->converter = $converter;
|
||||
$this->request = $request;
|
||||
$this->db = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action Controller-Action
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function dispatch($action)
|
||||
{
|
||||
if (substr($action, -6) !== 'Action') {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'API controller action "%s" is not dispatchable.', $action
|
||||
));
|
||||
}
|
||||
if (!method_exists($this, $action)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'API controller method "%s" not found', $action
|
||||
));
|
||||
}
|
||||
|
||||
$this->response = $this->$action();
|
||||
if ($this->response === null) {
|
||||
throw new \RuntimeException('Controller must return a Response object. Null given.');
|
||||
}
|
||||
if (!$this->response instanceof Response) {
|
||||
throw new \RuntimeException('Controller must return a Response object.');
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
*/
|
||||
public function setResourceClass($className)
|
||||
{
|
||||
$this->resourceClass = $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID aus der URL (Route) bekommen
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getResourceId()
|
||||
{
|
||||
return (int)$this->request->attributes->getDigits('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $className
|
||||
*
|
||||
* @return AbstractResource
|
||||
*/
|
||||
protected function getResource($className = null)
|
||||
{
|
||||
return $this->resourceManager->get($className !== null ? $className : $this->resourceClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request-Body in Array wandeln
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestData()
|
||||
{
|
||||
try {
|
||||
return $this->converter->toArray($this->getContentType(), $this->request->getContent());
|
||||
} catch (ConvertionException $e) {
|
||||
throw new BadRequestException(
|
||||
sprintf('%s could not be decoded.', strtoupper($this->getContentType())),
|
||||
ApiError::CODE_MALFORMED_REQUEST_BODY
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string [json|xml]
|
||||
*/
|
||||
protected function getContentType()
|
||||
{
|
||||
return $this->request->getContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AbstractResult $result
|
||||
* @param int $statusCode
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function sendResult(AbstractResult $result, $statusCode = Response::HTTP_OK)
|
||||
{
|
||||
$contentType = $this->determineResponseContentType();
|
||||
$data = [];
|
||||
|
||||
if ($contentType === 'xml') {
|
||||
if ($result->isCollection()) {
|
||||
$data['items'] = $result->getData();
|
||||
$data['pagination'] = $result->getPagination();
|
||||
} else {
|
||||
$data['item'] = $result->getData();
|
||||
}
|
||||
}
|
||||
if ($contentType === 'json') {
|
||||
$data = $result->getResult();
|
||||
}
|
||||
|
||||
return $this->sendResponse($data, $contentType, $statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Content-Type für die Ausgabe bestimmen
|
||||
*
|
||||
* @return string [xml|json]
|
||||
*/
|
||||
protected function determineResponseContentType()
|
||||
{
|
||||
// Accept-Header auslesen
|
||||
$acceptable = $this->request->getAcceptableContentTypes();
|
||||
|
||||
switch ($acceptable[0]) {
|
||||
// Client ist vermutlich ein Browser > JSON ausliefern
|
||||
case 'text/html':
|
||||
$contentType = 'json';
|
||||
break;
|
||||
|
||||
// Client hat JSON angefragt
|
||||
case 'application/json':
|
||||
$contentType = 'json';
|
||||
break;
|
||||
|
||||
// Client hat XML angefragt
|
||||
case 'application/xml':
|
||||
$contentType = 'xml';
|
||||
break;
|
||||
|
||||
// Nicht eindeutig > JSON bevorzugen
|
||||
default:
|
||||
if (in_array('application/xml', $acceptable)) {
|
||||
$contentType = 'xml';
|
||||
break;
|
||||
}
|
||||
$contentType = 'json';
|
||||
break;
|
||||
}
|
||||
|
||||
return $contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param string $contentType [xml|json]
|
||||
* @param int $statusCode HTTP-Statuscode
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
protected function sendResponse($data, $contentType, $statusCode = Response::HTTP_OK)
|
||||
{
|
||||
if ($contentType === 'xml') {
|
||||
return new Response(
|
||||
$this->converter->arrayToXml($data, 'result'),
|
||||
$statusCode,
|
||||
['Content-Type' => 'application/xml; charset=UTF-8']
|
||||
);
|
||||
}
|
||||
|
||||
return new Response(
|
||||
$this->converter->arrayToJson($data),
|
||||
$statusCode,
|
||||
['Content-Type' => 'application/json; charset=UTF-8']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filterparameter aufbereiten
|
||||
*
|
||||
* @example /resource?title=123&project=1
|
||||
* @example /resource?title_starts_with=123&project=1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareFilterParams()
|
||||
{
|
||||
$queryParams = $this->request->get->all();
|
||||
|
||||
// Reservierte Parameter ignorieren
|
||||
unset(
|
||||
$queryParams['sort'],
|
||||
$queryParams['page'],
|
||||
$queryParams['items'],
|
||||
$queryParams['filter'],
|
||||
$queryParams['include']
|
||||
);
|
||||
|
||||
$filter = [];
|
||||
foreach ($queryParams as $filterKey => $filterValue) {
|
||||
$filter[$filterKey] = filter_var($filterValue, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW);
|
||||
}
|
||||
|
||||
// Komplexe Suchfilter enthalten Array
|
||||
$filter['filter'] = $this->prepareComplexFilterParams();
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filterparameter für komplexe Suche aufbereiten
|
||||
*
|
||||
* @example /resource?filter[0][property]=satz&filter[0][expression]=gte&filter[0][value]=10
|
||||
* &filter[1][property]=bezeichnung&filter[1][value]=%Irland%
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareComplexFilterParams()
|
||||
{
|
||||
$filter = [];
|
||||
|
||||
$params = $this->request->get->get('filter');
|
||||
if (!is_array($params)) {
|
||||
return $filter;
|
||||
}
|
||||
|
||||
ksort($params);
|
||||
$params = array_values($params);
|
||||
|
||||
return $params;
|
||||
|
||||
foreach ($params as $param) {
|
||||
|
||||
echo "<pre>";
|
||||
var_dump($params);
|
||||
echo "</pre>";
|
||||
exit;
|
||||
// @todo Sanitize
|
||||
|
||||
echo "<pre>";
|
||||
var_dump($param);
|
||||
echo "</pre>";
|
||||
exit;
|
||||
}
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sortierungsparameter aufbereiten
|
||||
*
|
||||
* @example /resource?sort=name,project
|
||||
* @example /resource?sort=-name,project
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareSortingParams()
|
||||
{
|
||||
$sorting = [];
|
||||
$sortQuery = filter_var($this->request->get->get('sort'), FILTER_SANITIZE_URL);
|
||||
if (empty($sortQuery)) {
|
||||
return $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alte Syntax
|
||||
*
|
||||
* @example /resource?sort=title:desc|projekt:asc
|
||||
*/
|
||||
if (strpos($sortQuery, '|')) {
|
||||
$sortParams = explode('|', $sortQuery);
|
||||
foreach ($sortParams as $sortParam) {
|
||||
if (strpos($sortParam, ':')) {
|
||||
list($sortField, $sortOrder) = explode(':', $sortParam, 2);
|
||||
} else {
|
||||
$sortField = $sortParam;
|
||||
$sortOrder = 'asc';
|
||||
}
|
||||
|
||||
if (empty($sortField) || $sortField === ':') {
|
||||
throw new InvalidArgumentException('Sorting parameter can not be empty');
|
||||
}
|
||||
if (!in_array(strtolower($sortOrder), ['asc', 'desc'], true)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Sorting order "%s" is not valid. Use "asc" or "desc".', $sortOrder
|
||||
));
|
||||
}
|
||||
|
||||
$sortOrder = strtolower($sortOrder) === 'desc' ? 'DESC' : 'ASC';
|
||||
$sorting[$sortField] = $sortOrder;
|
||||
}
|
||||
|
||||
return $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Neue Syntax: Minuszeichen vor dem Feld kehrt die Sortierung um
|
||||
*
|
||||
* @example /resource?sort=-title,projekt
|
||||
*/
|
||||
$sortParams = explode(',', $sortQuery);
|
||||
foreach ($sortParams as $sortParam) {
|
||||
if (strpos($sortParam, '-') === 0) {
|
||||
$sortField = substr_replace($sortParam, '', 0, 1);
|
||||
$sortOrder = 'DESC';
|
||||
} else {
|
||||
$sortField = $sortParam;
|
||||
$sortOrder = 'ASC';
|
||||
}
|
||||
|
||||
if (empty($sortField) || $sortField === '-') {
|
||||
throw new InvalidArgumentException('Sorting parameter can not be empty');
|
||||
}
|
||||
|
||||
$sorting[$sortField] = $sortOrder;
|
||||
}
|
||||
|
||||
return $sorting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareIncludeParams()
|
||||
{
|
||||
$includesQuery = $this->request->get->get('include');
|
||||
if (empty($includesQuery)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$includes = explode(',', $includesQuery);
|
||||
$includes = array_map('trim', $includes);
|
||||
$includes = array_map('htmlspecialchars', $includes);
|
||||
|
||||
return $includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function getPaginationPage()
|
||||
{
|
||||
$page = $this->request->get->getInt('page');
|
||||
|
||||
return $page > 0 && $page <= 1000 ? $page : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
protected function getPaginationCount()
|
||||
{
|
||||
$items = $this->request->get->getInt('items');
|
||||
|
||||
return $items > 0 && $items <= 1000 ? $items : 20;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use SimpleXMLElement;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\InvalidArgumentException;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\Resource\Result\CollectionResult;
|
||||
use Xentral\Modules\Api\Resource\Result\ItemResult;
|
||||
|
||||
class AddressController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Adressliste abrufen
|
||||
*
|
||||
* @example GET /v1/adressen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
// Kundennummer ist optional; dann nur eine Adresse zurückliefern
|
||||
$kundennummer = filter_var($this->request->get->get('kundennummer'), FILTER_SANITIZE_STRING);
|
||||
if (!empty($kundennummer)) {
|
||||
return $this->findByCustomerNumberAction($kundennummer);
|
||||
}
|
||||
|
||||
// Optionale GET-Parameter
|
||||
$page = $this->getPaginationPage();
|
||||
$itemsPerPage = $this->getPaginationCount();
|
||||
|
||||
// Limit und Offset aus Parameter berechnen
|
||||
$limit = $itemsPerPage;
|
||||
$offset = ($page - 1) * $itemsPerPage;
|
||||
|
||||
$this->legacyApi->app->Secure->GET['action'] = 'AdresseListeGet';
|
||||
$this->legacyApi->app->Secure->GET['json'] = true;
|
||||
$this->legacyApi->app->Secure->POST['xml'] =
|
||||
'<xml>'.
|
||||
'<limit>'.$limit.'</limit>'.
|
||||
'<offset>'.$offset.'</offset>'.
|
||||
'<gruppen><kennziffer></kennziffer></gruppen>'. // @todo kennziffer
|
||||
'</xml>';
|
||||
|
||||
/** @var SimpleXMLElement $xml */
|
||||
$xml = $this->legacyApi->ApiAdresseListeGet(true);
|
||||
$data = $this->converter->xmlToArray($xml);
|
||||
|
||||
// Paginierung aus den Ergebnissen basteln
|
||||
$pagination = array();
|
||||
$pagination['items_per_page'] = $limit;
|
||||
$pagination['items_current'] = (int)$data['anz_result'];
|
||||
$pagination['items_total'] = (int)$data['anz_gesamt'];
|
||||
$pagination['page_current'] = (int)floor($offset / $limit) + 1;
|
||||
$pagination['page_last'] = (int)ceil($pagination['items_total'] / $limit);
|
||||
|
||||
// Ergebnis aus alter API umstrukturieren
|
||||
$result = new CollectionResult($data['adresse'], $pagination);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelne Adresse per ID abrufen
|
||||
*
|
||||
* @example GET /v1/adressen/999
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function readAction()
|
||||
{
|
||||
$id = $this->request->attributes->getInt('id');
|
||||
$data = $this->getAddressById($id);
|
||||
$result = new ItemResult($data);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $number Kundennummer
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function findByCustomerNumberAction($number)
|
||||
{
|
||||
$data = $this->getAddressByCustomerNumber($number);
|
||||
$result = new ItemResult($data);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adresse anlegen
|
||||
*
|
||||
* @example POST /v1/adressen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
// Request-Body in $_POST['json'] schreiben
|
||||
$requestBody = file_get_contents('php://input');
|
||||
$this->legacyApi->app->Secure->POST['json'] = $requestBody;
|
||||
$this->legacyApi->app->Secure->GET['action'] = 'AdresseCreate';
|
||||
|
||||
// Adresse anlegen
|
||||
$customerNumber = $this->legacyApi->ApiAdresseCreate(true);
|
||||
|
||||
if (intval($customerNumber) <= 0) {
|
||||
// @todo Nicht sehr hilfreiche Meldung
|
||||
// @todo Refaktorieren und besser Exception werfen
|
||||
throw new BadRequestException('Adresse konnte nicht angelegt werden.');
|
||||
}
|
||||
|
||||
// Anlage war erfolgreich > Erzeugte Resource zurückliefern
|
||||
$data = $this->getAddressByCustomerNumber($customerNumber);
|
||||
$result = new ItemResult($data);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adresse aktualisieren
|
||||
*
|
||||
* @example PUT /v1/adressen/999
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
$id = $this->request->attributes->getInt('id');
|
||||
|
||||
// Request-Body zu XML konvertieren
|
||||
$requestBody = file_get_contents('php://input');
|
||||
$requestData = json_decode($requestBody, true);
|
||||
$requestData = array('adresse' => $requestData);
|
||||
$requestData['adresse']['id'] = (int)$id; // ID hinzufügen
|
||||
unset($requestData['adresse']['kundennummer']); // Kundennummer löschen, sonst wird evtl. die falsche Adresse aktualisiert // @todo Kundennummer änderbar machen
|
||||
$requestXml = $this->converter->arrayToXml($requestData);
|
||||
|
||||
// Adresse ändern über alte API
|
||||
$this->legacyApi->app->Secure->GET['action'] = 'AdresseEdit';
|
||||
$this->legacyApi->app->Secure->GET['json'] = true;
|
||||
$this->legacyApi->app->Secure->POST['xml'] = $requestXml;
|
||||
$customerId = (int)$this->legacyApi->ApiAdresseEdit(true);
|
||||
|
||||
if ($customerId <= 0) {
|
||||
// @todo Nicht sehr hilfreiche Meldung
|
||||
// @todo Refaktorieren und besser Exception werfen
|
||||
throw new BadRequestException('Adresse konnte nicht bearbeitet werden.');
|
||||
}
|
||||
|
||||
// Bearbeiten war erfolgreich > Bearbeitete Resource zurückliefern
|
||||
$data = $this->getAddressById($customerId);
|
||||
$result = new ItemResult($data);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelne Adresse per ID abrufen
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @throws ResourceNotFoundException
|
||||
*/
|
||||
protected function getAddressById($id)
|
||||
{
|
||||
if (intval($id) <= 0) {
|
||||
throw new InvalidArgumentException('Benötigter Parameter \'id\' ungültig.');
|
||||
}
|
||||
|
||||
/** @var SimpleXMLElement $xml */
|
||||
$xml = $this->legacyApi->ApiAdresseGet(true, $id);
|
||||
if (empty($xml)) {
|
||||
throw new ResourceNotFoundException(sprintf('Adresse mit ID \'%s\' nicht gefunden', $id));
|
||||
}
|
||||
$data = $this->converter->xmlToArray($xml, true);
|
||||
|
||||
// Ergebnis aus alter API umstrukturieren
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzene Adresse per Kundennummer abrufen
|
||||
*
|
||||
* @param string $kundennummer
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @throws ResourceNotFoundException
|
||||
*/
|
||||
protected function getAddressByCustomerNumber($kundennummer)
|
||||
{
|
||||
if (empty($kundennummer)) {
|
||||
throw new InvalidArgumentException('Benötigter Parameter \'kundennummer\' ist leer.');
|
||||
}
|
||||
|
||||
/** @var SimpleXMLElement $xml */
|
||||
$this->legacyApi->app->Secure->GET['kundennummer'] = $kundennummer;
|
||||
$xml = $this->legacyApi->ApiAdresseGet(true, '');
|
||||
if (empty($xml)) {
|
||||
throw new ResourceNotFoundException(sprintf('Adresse mit Kundennummer \'%s\' nicht gefunden', $kundennummer));
|
||||
}
|
||||
$data = $this->converter->xmlToArray($xml, true);
|
||||
|
||||
// Ergebnis aus alter API umstrukturieren
|
||||
return ['data' => $data];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\ValidationErrorException;
|
||||
|
||||
/**
|
||||
* Controller zum Anlegen und Bearbeiten von Abo-Artikeln
|
||||
*
|
||||
* Die Auflistung der Aboartikel-Ressource wird über den GenericController behandelt.
|
||||
*/
|
||||
class ArticleSubscriptionController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Abo-Artikel anlegen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$input = $this->getRequestData();
|
||||
$errors = [];
|
||||
|
||||
// Pflichtparameter prüfen
|
||||
if (empty($input['bezeichnung'])) {
|
||||
$errors[] = 'Required field "bezeichnung" is empty.';
|
||||
}
|
||||
if (empty($input['artikelnummer']) && empty($input['artikel'])) {
|
||||
$errors[] = 'Required fields "artikelnummer" and "artikel" are empty. One of them must be filled.';
|
||||
}
|
||||
// Artikelnummer in ID wandeln
|
||||
if (!empty($input['artikelnummer'])) {
|
||||
$input['artikel'] = (int)$this->db->fetchValue(
|
||||
'SELECT a.id FROM artikel AS a WHERE a.nummer = :artikelnummer',
|
||||
['artikelnummer' => $input['artikelnummer']]
|
||||
);
|
||||
// Artikelnummer existiert nicht
|
||||
if ($input['artikel'] === 0) {
|
||||
$errors[] = 'Artikel not found with article number: ' . $input['artikelnummer'];
|
||||
}
|
||||
unset($input['artikelnummer']);
|
||||
}
|
||||
// Kundennummer in Adressen-ID wandeln
|
||||
if (!empty($input['kundennummer'])) {
|
||||
$input['adresse'] = (int)$this->db->fetchValue(
|
||||
'SELECT a.id FROM adresse AS a WHERE a.kundennummer = :kundennummer',
|
||||
['kundennummer' => $input['kundennummer']]
|
||||
);
|
||||
// Kundennummer existiert nicht
|
||||
if ($input['adresse'] === 0) {
|
||||
$errors[] = 'Address not found with customer number: ' . $input['kundennummer'];
|
||||
}
|
||||
unset($input['kundennummer']);
|
||||
}
|
||||
|
||||
// Nach Pflichtfeld-Prüfung vorab Fehler anzeigen
|
||||
if (count($errors) > 0) {
|
||||
throw new ValidationErrorException($errors);
|
||||
}
|
||||
|
||||
// Default-Werte hinterlegen
|
||||
if (!array_key_exists('startdatum', $input)) {
|
||||
$input['startdatum'] = date('Y-m-d');
|
||||
}
|
||||
if (!array_key_exists('zahlzyklus', $input)) {
|
||||
$input['zahlzyklus'] = 1;
|
||||
}
|
||||
if (!array_key_exists('dokumenttyp', $input)) {
|
||||
$input['dokumenttyp'] = 'rechnung';
|
||||
}
|
||||
if (!array_key_exists('preisart', $input)) {
|
||||
$input['preisart'] = 'monat';
|
||||
}
|
||||
if (!array_key_exists('menge', $input)) {
|
||||
$input['menge'] = '0.00';
|
||||
}
|
||||
if (!array_key_exists('preis', $input)) {
|
||||
$input['preis'] = '0.00';
|
||||
}
|
||||
if (!array_key_exists('rabatt', $input)) {
|
||||
$input['rabatt'] = '0.00';
|
||||
}
|
||||
if (!array_key_exists('waehrung', $input)) {
|
||||
$input['waehrung'] = 'EUR';
|
||||
}
|
||||
if (!array_key_exists('reihenfolge', $input)) {
|
||||
$input['reihenfolge'] = 1;
|
||||
}
|
||||
|
||||
// Aboartikel-Eintrag anlegen
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$result = $resource->insert($input);
|
||||
|
||||
return $this->sendResult($result, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abo-Artikel bearbeiten
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
|
||||
$id = $this->getResourceId();
|
||||
$resource->checkOrFail($id);
|
||||
|
||||
$errors = [];
|
||||
$input = $this->getRequestData();
|
||||
|
||||
// Artikelnummer in ID wandeln
|
||||
if (!empty($input['artikelnummer'])) {
|
||||
$input['artikel'] = (int)$this->db->fetchValue(
|
||||
'SELECT a.id FROM artikel AS a WHERE a.nummer = :artikelnummer',
|
||||
['artikelnummer' => $input['artikelnummer']]
|
||||
);
|
||||
// Artikelnummer existiert nicht
|
||||
if ($input['artikel'] === 0) {
|
||||
$errors[] = 'Artikel not found with article number: ' . $input['artikelnummer'];
|
||||
}
|
||||
unset($input['artikelnummer']);
|
||||
}
|
||||
// Kundennummer in Adressen-ID wandeln
|
||||
if (!empty($input['kundennummer'])) {
|
||||
$input['adresse'] = (int)$this->db->fetchValue(
|
||||
'SELECT a.id FROM adresse AS a WHERE a.kundennummer = :kundennummer',
|
||||
['kundennummer' => $input['kundennummer']]
|
||||
);
|
||||
// Kundennummer existiert nicht
|
||||
if ($input['adresse'] === 0) {
|
||||
$errors[] = 'Address not found with customer number: ' . $input['kundennummer'];
|
||||
}
|
||||
unset($input['kundennummer']);
|
||||
}
|
||||
|
||||
// Nach Pflichtfeld-Prüfung vorab Fehler anzeigen
|
||||
if (count($errors) > 0) {
|
||||
throw new ValidationErrorException($errors);
|
||||
}
|
||||
if (empty($input)) {
|
||||
throw new BadRequestException('Payload is empty.');
|
||||
}
|
||||
|
||||
$result = $resource->edit($id, $input);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Components\Util\StringUtil;
|
||||
use Xentral\Modules\Api\Engine\ApiUrlGenerator;
|
||||
use Xentral\Modules\Api\Error\ApiError;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\Exception\ServerErrorException;
|
||||
use Xentral\Modules\Api\Resource\FileResource;
|
||||
use Xentral\Modules\Api\Resource\Result\ItemResult;
|
||||
|
||||
class DocumentScannerController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Resourcen-Liste abrufen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
// Filter, Sortierung und Paginierung
|
||||
$filter = $this->prepareFilterParams();
|
||||
$sorting = $this->prepareSortingParams();
|
||||
$includes = $this->prepareIncludeParams();
|
||||
$currentPage = $this->getPaginationPage();
|
||||
$itemsPerPage = $this->getPaginationCount();
|
||||
|
||||
// Liste laden
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$result = $resource->getList($filter, $sorting, [], $includes, $currentPage, $itemsPerPage);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelne Resource anhand ID laden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function readAction()
|
||||
{
|
||||
return $this->sendResult($this->readResult());
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei anlegen/hochladen
|
||||
*
|
||||
* @throws BadRequestException Wenn Pflichtfelder leer, oder Content-Type falsch
|
||||
* @throws ServerErrorException Wenn Datei aus unbekannten Gründen nicht angelegt werden konnte (sollte nicht auftreten)
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$input = null;
|
||||
$contentTypeRaw = $this->request->getHeader('Content-Type');
|
||||
if (empty($contentTypeRaw)) {
|
||||
$errorMsg = 'Content-Type header is empty. ';
|
||||
$errorMsg .= 'Only "application/x-www-form-urlencoded" or "multipart/form-data" is supported.';
|
||||
throw new BadRequestException(
|
||||
'Unsupported Content-Type', ApiError::CODE_CONTENT_TYPE_NOT_SUPPORTED, null, [$errorMsg]
|
||||
);
|
||||
}
|
||||
if (StringUtil::startsWith($contentTypeRaw, 'multipart/form-data')) {
|
||||
$input = $this->getRequestDataFromMultipartForm();
|
||||
}
|
||||
if (StringUtil::startsWith($contentTypeRaw, 'application/x-www-form-urlencoded')) {
|
||||
$input = $this->getRequestDataFromUrlEncodedForm();
|
||||
}
|
||||
if ($input === null) {
|
||||
$errorMsg = sprintf('Content-Type "%s" is not supported. ', $contentTypeRaw);
|
||||
$errorMsg .= 'Only "application/x-www-form-urlencoded" or "multipart/form-data" is supported.';
|
||||
throw new BadRequestException(
|
||||
'Unsupported Content-Type', ApiError::CODE_CONTENT_TYPE_NOT_SUPPORTED, null, [$errorMsg]
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($input['dateiname'])) {
|
||||
throw new BadRequestException('Required property "dateiname" is missing.');
|
||||
}
|
||||
if (empty($input['titel'])) {
|
||||
throw new BadRequestException('Required property "titel" is missing.');
|
||||
}
|
||||
if (empty($input['file_content'])) {
|
||||
throw new BadRequestException('Required property "file_content" is missing or file is empty.');
|
||||
}
|
||||
|
||||
// Meta-Daten prüfen
|
||||
if (!empty($input['meta'])) {
|
||||
$this->checkMetaData($input['meta']);
|
||||
$metaData = $input['meta'];
|
||||
}
|
||||
|
||||
$fileName = $input['dateiname']; // Pflichtfeld
|
||||
$fileTitle = $input['titel']; // Pflichtfeld
|
||||
$fileDescription = $input['beschreibung'] ?? '';
|
||||
$fileNumber = null;
|
||||
$fileCreatorUserId = null;
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$fileId = (int)$erp->CreateDatei(
|
||||
$fileName,
|
||||
$fileTitle,
|
||||
$fileDescription,
|
||||
$fileNumber,
|
||||
$input['file_content'],
|
||||
$fileCreatorUserId
|
||||
);
|
||||
if ($fileId <= 0) {
|
||||
throw new ServerErrorException('Failed to create file.');
|
||||
}
|
||||
|
||||
// Datei in docscan-Tabelle verknüpfen und Datei-Stichwort hinzufügen
|
||||
$this->db->perform(
|
||||
'INSERT INTO `docscan` (`id`, `datei`, `kategorie`) VALUES (NULL, :file_id, NULL)',
|
||||
['file_id' => $fileId]
|
||||
);
|
||||
$docscanId = $this->db->lastInsertId();
|
||||
$erp->AddDateiStichwort($fileId, 'Sonstige', 'DocScan', $docscanId);
|
||||
|
||||
// Meta-Daten speichern
|
||||
if (isset($metaData) && !empty($metaData)) {
|
||||
$this->saveMetaData($docscanId, $metaData);
|
||||
}
|
||||
|
||||
// Bei Erfolg die angelegte Resource zurückliefern; mit Success-Flag
|
||||
/** @var FileResource $resource */
|
||||
$result = $this->readResult($fileId);
|
||||
$result->setSuccess(true);
|
||||
|
||||
return $this->sendResult($result, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ResourceNotFoundException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequestException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestDataFromMultipartForm()
|
||||
{
|
||||
if ($this->request->getContentType() !== 'form-data') {
|
||||
throw new BadRequestException(
|
||||
'Unsupported Content-Type',
|
||||
ApiError::CODE_CONTENT_TYPE_NOT_SUPPORTED,
|
||||
null,
|
||||
['Content-Type must be "multipart/form-data"']
|
||||
);
|
||||
}
|
||||
|
||||
$input = $this->request->post->all();
|
||||
if (!isset($input['file_content']) && $this->request->files->has('file_content')) {
|
||||
$upload = $this->request->files->get('file_content');
|
||||
$input['file_content'] = $upload->getContent();
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequestException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestDataFromUrlEncodedForm()
|
||||
{
|
||||
if ($this->request->getContentType() !== 'x-www-form-urlencoded') {
|
||||
throw new BadRequestException(
|
||||
'Unsupported Content-Type',
|
||||
ApiError::CODE_CONTENT_TYPE_NOT_SUPPORTED,
|
||||
null,
|
||||
['Content-Type must be "application/x-www-form-urlencoded"']
|
||||
);
|
||||
}
|
||||
|
||||
return $this->request->post->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws BadRequestException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkMetaData($data)
|
||||
{
|
||||
if (!is_array($data)) {
|
||||
throw new BadRequestException('Wrong value type in property "meta". Only type array is allowed.');
|
||||
}
|
||||
|
||||
$allowedKeys = ['invoice_number', 'invoice_date', 'invoice_amount', 'invoice_tax', 'invoice_currency'];
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_int($key)) {
|
||||
throw new BadRequestException('Wrong format in property "meta". Numeric keys are not allowed.');
|
||||
}
|
||||
$cleanedKey = (string)preg_replace('#[^a-z0-9_]#', '', trim($key));
|
||||
if ($key !== $cleanedKey) {
|
||||
throw new BadRequestException(sprintf(
|
||||
'Meta key "%s" contains an illegal character. Allowed characters: a-z, 0-9 and underscore.', $key
|
||||
));
|
||||
}
|
||||
if (!in_array($key, $allowedKeys, true)) {
|
||||
throw new BadRequestException(sprintf(
|
||||
'Meta key "%s" is not allowed. Allowed keys: %s', $key, implode(', ', $allowedKeys)
|
||||
));
|
||||
}
|
||||
if (mb_strlen($value) > 32) {
|
||||
throw new BadRequestException(sprintf(
|
||||
'Wrong value format in property "meta.%s". Max value length is 32 characters.',
|
||||
$key
|
||||
));
|
||||
}
|
||||
|
||||
if ($key === 'invoice_number') {
|
||||
if (!is_string($value)) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value type in property "meta.invoice_number". Only type string is allowed.'
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($key === 'invoice_date') {
|
||||
$invoiceDate = DateTimeImmutable::createFromFormat('Y-m-d', $value);
|
||||
if ($invoiceDate === false || array_sum($invoiceDate::getLastErrors()) > 0) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value format or invalid date in property "meta.invoice_date". Allowed format: "YYYY-MM-DD"'
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($key === 'invoice_amount') {
|
||||
$cleanedInvoiceAmount = (string)preg_replace('#[^0-9.]#', '', $value);
|
||||
if ($value !== $cleanedInvoiceAmount) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value format in property "meta.invoice_amount". Value can only contain numbers and a period character.'
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($key === 'invoice_tax') {
|
||||
$cleanedInvoiceTax = (string)preg_replace('#[^0-9.]#', '', $value);
|
||||
if ($value !== $cleanedInvoiceTax) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value format in property "meta.invoice_tax". Value can only contain numbers and a period character.'
|
||||
);
|
||||
}
|
||||
}
|
||||
if ($key === 'invoice_currency') {
|
||||
if (!is_string($value)) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value type in property "meta.invoice_currency". Only type string is allowed.'
|
||||
);
|
||||
}
|
||||
if (mb_strlen($value) !== 3) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value format in property "meta.invoice_currency". Value must be three characters long.'
|
||||
);
|
||||
}
|
||||
$cleanedCurrencyCode = (string)preg_replace('#[^A-Z]#', '', $value);
|
||||
if ($value !== $cleanedCurrencyCode) {
|
||||
throw new BadRequestException(
|
||||
'Wrong value format in property "meta.invoice_currency". Value must contain three uppercase characters.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $docscanId
|
||||
* @param array $metaData
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function saveMetaData(int $docscanId, array $metaData)
|
||||
{
|
||||
if (empty($metaData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->beginTransaction();
|
||||
foreach ($metaData as $metaKey => $metaValue) {
|
||||
$this->db->perform(
|
||||
'INSERT INTO `docscan_metadata` (`id`, `docscan_id`, `meta_key`, `meta_value`)
|
||||
VALUES (NULL, :docscan_id, :meta_key, :meta_value)',
|
||||
[
|
||||
'docscan_id' => $docscanId,
|
||||
'meta_key' => (string)$metaKey,
|
||||
'meta_value' => (string)$metaValue,
|
||||
]
|
||||
);
|
||||
}
|
||||
$this->db->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $useFileId
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
*
|
||||
* @return ItemResult
|
||||
*/
|
||||
protected function readResult($useFileId = null)
|
||||
{
|
||||
$fileId = (int)$useFileId > 0 ? (int)$useFileId : $this->getResourceId();
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$filePath = $erp->GetDateiPfad($fileId);
|
||||
if (!is_file($filePath)) {
|
||||
throw new ResourceNotFoundException('File not found in filesystem.');
|
||||
}
|
||||
|
||||
$fileMime = mime_content_type($filePath);
|
||||
if ($fileMime === 'directory') {
|
||||
throw new ResourceNotFoundException('File not found. File is a directory.');
|
||||
}
|
||||
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$includes = ['metadata'];//$this->prepareIncludeParams();
|
||||
$result = $resource->getOne($fileId, $includes);
|
||||
$downloadBaseUrl = $this->buildDownloadBaseUrl($fileId);
|
||||
|
||||
// Daten anreichern um Download-Links
|
||||
$data = $result->getData();
|
||||
$data['mimetype'] = $fileMime;
|
||||
$data['links'] = [
|
||||
'download' => $downloadBaseUrl . '/download',
|
||||
'base64' => $downloadBaseUrl . '/base64',
|
||||
];
|
||||
|
||||
return new ItemResult($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $fileId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildDownloadBaseUrl($fileId)
|
||||
{
|
||||
$urlGenerator = new ApiUrlGenerator($this->request);
|
||||
|
||||
return $urlGenerator->generate('/v1/dateien/' . (int)$fileId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Error\ApiError;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\Exception\ServerErrorException;
|
||||
use Xentral\Modules\Api\Resource\FileResource;
|
||||
use Xentral\Modules\Api\Resource\Result\ItemResult;
|
||||
|
||||
class FileController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Resourcen-Liste abrufen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
// Filter, Sortierung und Paginierung
|
||||
$filter = $this->prepareFilterParams();
|
||||
$sorting = $this->prepareSortingParams();
|
||||
$includes = $this->prepareIncludeParams();
|
||||
$currentPage = $this->getPaginationPage();
|
||||
$itemsPerPage = $this->getPaginationCount();
|
||||
|
||||
// Liste laden
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$result = $resource->getList($filter, $sorting, [], $includes, $currentPage, $itemsPerPage);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelne Resource anhand ID laden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function readAction()
|
||||
{
|
||||
return $this->sendResult($this->readResult());
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei als Download senden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function downloadAction()
|
||||
{
|
||||
$fileId = $this->getResourceId();
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$filePath = $erp->GetDateiPfad($fileId);
|
||||
$fileName = $erp->GetDateiName($fileId);
|
||||
if (!is_file($filePath)) {
|
||||
throw new ResourceNotFoundException('File not found in filesystem.');
|
||||
}
|
||||
|
||||
$fileMime = mime_content_type($filePath);
|
||||
if ($fileMime === 'directory') {
|
||||
throw new ResourceNotFoundException('File not found. File is a directory.');
|
||||
}
|
||||
|
||||
$header = [
|
||||
'Content-Type' => $fileMime,
|
||||
'Content-Disposition' => sprintf('attachment; filename="%s"', $fileName),
|
||||
'Content-Length' => (string)filesize($filePath),
|
||||
];
|
||||
|
||||
return new Response(file_get_contents($filePath), 200, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei base64-kodiert senden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function base64Action()
|
||||
{
|
||||
$fileId = $this->getResourceId();
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$filePath = $erp->GetDateiPfad($fileId);
|
||||
if (!is_file($filePath)) {
|
||||
throw new ResourceNotFoundException('File not found in filesystem.');
|
||||
}
|
||||
|
||||
$fileMime = mime_content_type($filePath);
|
||||
if ($fileMime === 'directory') {
|
||||
throw new ResourceNotFoundException('File not found. File is a directory.');
|
||||
}
|
||||
|
||||
$prefix = 'data:' . $fileMime . ';base64,';
|
||||
$header = [
|
||||
'Content-Type' => 'text/plain',
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
|
||||
return new Response($prefix . base64_encode(file_get_contents($filePath)), 200, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei anlegen/hochladen
|
||||
*
|
||||
* @throws BadRequestException Wenn Pflichtfelder leer, oder Content-Type falsch
|
||||
* @throws ServerErrorException Wenn Datei aus unbekannten Gründen nicht angelegt werden konnte (sollte nicht auftreten)
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$input = $this->getRequestDataFromUrlEncodedForm();
|
||||
|
||||
if (empty($input['dateiname'])) {
|
||||
throw new BadRequestException('Required property "dateiname" is missing.');
|
||||
}
|
||||
if (empty($input['titel'])) {
|
||||
throw new BadRequestException('Required property "titel" is missing.');
|
||||
}
|
||||
if (empty($input['file_content'])) {
|
||||
throw new BadRequestException('Required property "file_content" is missing.');
|
||||
}
|
||||
|
||||
$fileName = $input['dateiname']; // Pflichtfeld
|
||||
$fileTitle = $input['titel']; // Pflichtfeld
|
||||
$fileDescription = $input['beschreibung'] ?? '';
|
||||
$fileNumber = null;
|
||||
$fileCreatorUserId = null;
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$fileId = (int)$erp->CreateDatei(
|
||||
$fileName,
|
||||
$fileTitle,
|
||||
$fileDescription,
|
||||
$fileNumber,
|
||||
$input['file_content'],
|
||||
$fileCreatorUserId
|
||||
);
|
||||
|
||||
if ($fileId <= 0) {
|
||||
throw new ServerErrorException('Failed to create file.');
|
||||
}
|
||||
|
||||
// if (!empty($input['belegtyp'])) {
|
||||
// $erp->AddDateiStichwort($fileId, 'Belege', $input['belegtyp'], $belegId); // @todo $belegId
|
||||
// }
|
||||
|
||||
// Bei Erfolg die angelegte Resource zurückliefern; mit Success-Flag
|
||||
/** @var FileResource $resource */
|
||||
$result = $this->readResult($fileId);
|
||||
$result->setSuccess(true);
|
||||
|
||||
return $this->sendResult($result, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ResourceNotFoundException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
throw new ResourceNotFoundException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BadRequestException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestDataFromUrlEncodedForm()
|
||||
{
|
||||
$request = $this->request;
|
||||
if ($request->getContentType() !== 'x-www-form-urlencoded') {
|
||||
throw new BadRequestException(
|
||||
'Unsupported Content-Type',
|
||||
ApiError::CODE_CONTENT_TYPE_NOT_SUPPORTED,
|
||||
null,
|
||||
['Content-Type must be "application/x-www-form-urlencoded"']
|
||||
);
|
||||
}
|
||||
|
||||
return $request->post->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $useFileId
|
||||
*
|
||||
* @throws ResourceNotFoundException
|
||||
*
|
||||
* @return ItemResult
|
||||
*/
|
||||
protected function readResult($useFileId = null)
|
||||
{
|
||||
$fileId = (int)$useFileId > 0 ? (int)$useFileId : $this->getResourceId();
|
||||
|
||||
$erp = $this->legacyApi->app->erp;
|
||||
$filePath = $erp->GetDateiPfad($fileId);
|
||||
if (!is_file($filePath)) {
|
||||
throw new ResourceNotFoundException('File not found in filesystem.');
|
||||
}
|
||||
|
||||
$fileMime = mime_content_type($filePath);
|
||||
if ($fileMime === 'directory') {
|
||||
throw new ResourceNotFoundException('File not found. File is a directory.');
|
||||
}
|
||||
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$includes = $this->prepareIncludeParams();
|
||||
$result = $resource->getOne($fileId, $includes);
|
||||
$fullUri = $this->request->getFullUrl();
|
||||
|
||||
// URI um File-ID erweitern, wenn der Request ohne ID war (beim Anlegen)
|
||||
if ((int)$useFileId > 0) {
|
||||
$fullUri .= '/' . $useFileId;
|
||||
}
|
||||
|
||||
// Daten anreichern um Download-Links
|
||||
$data = $result->getData();
|
||||
$data['mimetype'] = $fileMime;
|
||||
$data['links'] = [
|
||||
'download' => $fullUri . '/download',
|
||||
'base64' => $fullUri . '/base64',
|
||||
];
|
||||
|
||||
return new ItemResult($data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Http\Response;
|
||||
|
||||
class GenericController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Resourcen-Liste abrufen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function listAction()
|
||||
{
|
||||
// Filter, Sortierung und Paginierung
|
||||
$filter = $this->prepareFilterParams();
|
||||
$sorting = $this->prepareSortingParams();
|
||||
$includes = $this->prepareIncludeParams();
|
||||
$currentPage = $this->getPaginationPage();
|
||||
$itemsPerPage = $this->getPaginationCount();
|
||||
|
||||
// Liste laden
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$result = $resource->getList($filter, $sorting, [], $includes, $currentPage, $itemsPerPage);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Einzelne Resource anhand ID laden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function readAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$includes = $this->prepareIncludeParams();
|
||||
|
||||
$id = $this->getResourceId();
|
||||
$result = $resource->getOne($id, $includes);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource anlegen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
|
||||
$input = $this->getRequestData();
|
||||
$result = $resource->insert($input);
|
||||
|
||||
return $this->sendResult($result, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource ändern
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
|
||||
$id = $this->getResourceId();
|
||||
$resource->checkOrFail($id);
|
||||
|
||||
$input = $this->getRequestData();
|
||||
$result = $resource->edit($id, $input);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource löschen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
|
||||
$id = $this->getResourceId();
|
||||
$resource->checkOrFail($id);
|
||||
|
||||
$result = $resource->delete($id);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Exception;
|
||||
use Xentral\Components\Http\Request;
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\Exception\ServerErrorException;
|
||||
use Xentral\Modules\Api\LegacyBridge\LegacyApplication;
|
||||
use Xentral\Modules\Report\ReportCsvExportService;
|
||||
use Xentral\Modules\Report\ReportGateway;
|
||||
use Xentral\Modules\Report\ReportPdfExportService;
|
||||
|
||||
class ReportsController
|
||||
{
|
||||
/** @var LegacyApplication $api*/
|
||||
private $app;
|
||||
|
||||
/** @var Request $request */
|
||||
private $request;
|
||||
|
||||
/** @var int $apiAccountId */
|
||||
private $apiAccountId;
|
||||
|
||||
/**
|
||||
* @param LegacyApplication $app
|
||||
* @param Request $request
|
||||
* @param int $apiAccountId
|
||||
*/
|
||||
public function __construct(LegacyApplication $app, Request $request, $apiAccountId)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $request;
|
||||
$this->apiAccountId = $apiAccountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Datei als Download senden
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function downloadAction()
|
||||
{
|
||||
$reportId = $this->request->attributes->getInt('id');
|
||||
$parameters = $this->request->get->all();
|
||||
|
||||
/** @var ReportGateway $gateway */
|
||||
$gateway = $this->app->Container->get('ReportGateway');
|
||||
$reportObject = $gateway->getReportById($reportId);
|
||||
if ($reportObject === null) {
|
||||
throw new ResourceNotFoundException('Resource not found');
|
||||
}
|
||||
|
||||
/** @var ReportGateway $gateway */
|
||||
$gateway = $this->app->Container->get('ReportGateway');
|
||||
$transferOptions = $gateway->findTransferArrayByReportId($reportId);
|
||||
if (
|
||||
empty($transferOptions)
|
||||
|| !isset(
|
||||
$transferOptions['api_active'],
|
||||
$transferOptions['api_account_id'],
|
||||
$transferOptions['api_format']
|
||||
)
|
||||
|| $transferOptions['api_active'] === 0
|
||||
|| $transferOptions['api_account_id'] !== $this->apiAccountId
|
||||
) {
|
||||
return new Response(
|
||||
json_encode(
|
||||
['error' => ['http_code' => 403, 'message' => 'Access denied']]
|
||||
, JSON_PRETTY_PRINT
|
||||
),
|
||||
Response::HTTP_FORBIDDEN
|
||||
);
|
||||
}
|
||||
|
||||
$clientFileName = '';
|
||||
$filePath = '';
|
||||
try {
|
||||
switch ($transferOptions['api_format']) {
|
||||
case 'csv':
|
||||
/** @var ReportCsvExportService $csvExporter */
|
||||
$csvExporter = $this->app->Container->get('ReportCsvExportService');
|
||||
$clientFileName = $csvExporter->generateFileName($reportObject);
|
||||
$filePath = $csvExporter->createCsvFileFromReport($reportObject, $parameters);
|
||||
|
||||
break;
|
||||
|
||||
case 'pdf':
|
||||
/** @var ReportPdfExportService $pdfExporter */
|
||||
$pdfExporter = $this->app->Container->get('ReportPdfExportService');
|
||||
$clientFileName = $pdfExporter->generateFileName($reportObject);
|
||||
$filePath = $pdfExporter->createPdfFileFromReport($reportObject, $parameters);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
|
||||
if (!is_file($filePath)) {
|
||||
throw new ServerErrorException();
|
||||
}
|
||||
|
||||
$fileMime = mime_content_type($filePath);
|
||||
$header = [
|
||||
'Content-Type' => $fileMime,
|
||||
'Content-Disposition' => sprintf('attachment; filename="%s"', $clientFileName),
|
||||
'Content-Length' => (string)filesize($filePath),
|
||||
];
|
||||
$response = new Response(file_get_contents($filePath), 200, $header);
|
||||
unlink($filePath);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Error\ApiError;
|
||||
use Xentral\Modules\Api\Exception\ResourceNotFoundException;
|
||||
use Xentral\Modules\Api\Exception\RouteNotFoundException;
|
||||
use Xentral\Modules\Api\Exception\ServerErrorException;
|
||||
use Xentral\Modules\Api\Exception\WebserverMisconfigurationException;
|
||||
use Xentral\Modules\Api\Http\Exception\HttpException;
|
||||
use Xentral\Modules\Api\Http\PathInfoDetector;
|
||||
use Xentral\Modules\Api\Resource\Result\ItemResult;
|
||||
|
||||
class StartController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @throws HttpException
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
if (!$this->request->isFailsafeUri()) {
|
||||
|
||||
/*
|
||||
* Erkennung von fehlerhafter Server-Konfiguration
|
||||
*
|
||||
* Problem:
|
||||
* Nginx übermittelt in der Standard-Konfiguration nicht den PathInfo an PHP.
|
||||
* Wenn PathInfo nicht gesetzt ist, landet man immer in diesem Controller und es sieht so aus
|
||||
* als würde die API grundsätzlich funktionieren, obwohl man im falschen Endpunkt rauskommt.
|
||||
*
|
||||
* Lösung:
|
||||
* Nachfolgend wird versucht den PathInfo-Teil aus anderen Server-Variablen zu ermitteln.
|
||||
* Bei Unterschieden zwischen dem ermittelten und dem gesetzten PathInfo wird eine Exception geworfen.
|
||||
*/
|
||||
|
||||
$pathInfoDetector = new PathInfoDetector($this->request);
|
||||
$pathInfoExpected = $pathInfoDetector->detect();
|
||||
$pathInfoActual = (string)$this->request->server->get('PATH_INFO');
|
||||
|
||||
if ($pathInfoActual !== $pathInfoExpected) {
|
||||
throw new WebserverMisconfigurationException(
|
||||
'Webserver configuration incorrect. Pathinfo is invalid.',
|
||||
ApiError::CODE_WEBSERVER_PATHINFO_INVALID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->sendResult(new ItemResult(['info' => 'Nothing here']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action zum Ausliefern der /api/docs.html
|
||||
*
|
||||
* Action greift nur wenn der Webserver falsch konfiguriert ist. Der Webserver müsste existierende
|
||||
* Dateien direkt ausliefern ohne Umweg über den API-Frontcontroller.
|
||||
*
|
||||
* @throws ServerErrorException
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function docsAction()
|
||||
{
|
||||
$docsHtmlFilePath = $this->getApiRootPath() . DIRECTORY_SEPARATOR . 'docs.html';
|
||||
if (!is_file($docsHtmlFilePath)) {
|
||||
throw new ServerErrorException(sprintf('File not found: %s', $docsHtmlFilePath));
|
||||
}
|
||||
|
||||
return new Response(file_get_contents($docsHtmlFilePath), Response::HTTP_OK, ['Content-Type' => 'text/html']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action zum Ausliefern von Assets (CSS und JS) der /api/docs.html
|
||||
*
|
||||
* @throws RouteNotFoundException
|
||||
* @throws ResourceNotFoundException
|
||||
* @throws ServerErrorException
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function docsAssetsAction()
|
||||
{
|
||||
$assetFileName = $this->request->attributes->get('assetfile');
|
||||
if (empty($assetFileName)) {
|
||||
throw new RouteNotFoundException('Empty asset file name');
|
||||
}
|
||||
|
||||
$mapping = [
|
||||
'docs.css' => 'text/css',
|
||||
'docs_custom.css' => 'text/css',
|
||||
'docs.js' => 'application/json',
|
||||
'0.docs.js' => 'application/json',
|
||||
];
|
||||
|
||||
if (!array_key_exists($assetFileName, $mapping)) {
|
||||
throw new ResourceNotFoundException(sprintf('Asset file "%s" not found.', $assetFileName));
|
||||
}
|
||||
|
||||
$apiRootDir = $this->getApiRootPath() . DIRECTORY_SEPARATOR;
|
||||
$assetFilePath = $apiRootDir . 'assets' . DIRECTORY_SEPARATOR . $assetFileName;
|
||||
$contentType = $mapping[$assetFileName];
|
||||
|
||||
if (!is_file($assetFilePath)) {
|
||||
throw new ServerErrorException(sprintf('File not found: %s', $assetFilePath));
|
||||
}
|
||||
|
||||
return new Response(file_get_contents($assetFilePath), Response::HTTP_OK, ['Content-Type' => $contentType]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absoute Path without trailing slash
|
||||
*/
|
||||
private function getApiRootPath()
|
||||
{
|
||||
return dirname(__DIR__, 5) . DIRECTORY_SEPARATOR . 'www' . DIRECTORY_SEPARATOR . 'api';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Api\Controller\Version1;
|
||||
|
||||
use Xentral\Components\Http\Response;
|
||||
use Xentral\Modules\Api\Exception\BadRequestException;
|
||||
use Xentral\Modules\Api\Exception\ValidationErrorException;
|
||||
|
||||
/**
|
||||
* Controller zum Anlegen und Bearbeiten von Trackingnummern
|
||||
*
|
||||
* Die Auflistung der Trackingnummer-Ressource wird über den GenericController behandelt.
|
||||
*/
|
||||
class TrackingNumberController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* Trackingsnummer anlegen
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function createAction()
|
||||
{
|
||||
$input = $this->getRequestData();
|
||||
$errors = [];
|
||||
|
||||
// Pflichtfelder prüfen
|
||||
if (empty($input['tracking'])) {
|
||||
$errors[] = 'Required field "tracking" is empty.';
|
||||
}
|
||||
if (empty($input['internet']) && empty($input['auftrag']) && empty($input['lieferschein'])) {
|
||||
$errors[] =
|
||||
'Required fields "internet", "auftrag" and "lieferschein" are empty. ' .
|
||||
'One of them has to be filled.';
|
||||
}
|
||||
if (empty($input['gewicht'])) {
|
||||
$errors[] = 'Required field "gewicht" is empty.';
|
||||
}
|
||||
if (empty($input['anzahlpakete'])) {
|
||||
$errors[] = 'Required field "anzahlpakete" is empty.';
|
||||
}
|
||||
if (empty($input['versendet_am'])) {
|
||||
$errors[] = 'Required field "versendet_am" is empty.';
|
||||
}
|
||||
|
||||
// Nach Pflichtfeld-Prüfung vorab Fehler anzeigen
|
||||
if (count($errors) > 0) {
|
||||
throw new ValidationErrorException($errors);
|
||||
}
|
||||
|
||||
// Format der Pflichtfelder prüfen
|
||||
$input['versendet_am'] = $this->ensureShippingDateFormat($input['versendet_am']);
|
||||
$input['anzahlpakete'] = $this->ensureParcelCountFormat($input['anzahlpakete']);
|
||||
|
||||
// Prüfen ob Auftragsdaten gültig
|
||||
$orderData = $this->ensureOrderData($input['lieferschein'], $input['auftrag'], $input['internet']);
|
||||
|
||||
// Trackingnummer-Eintrag anlegen
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
$bindValues = [
|
||||
'adresse' => $orderData['adresseid'],
|
||||
'lieferschein' => $orderData['lieferscheinid'],
|
||||
'projekt' => $orderData['projektid'],
|
||||
'firma' => $orderData['firmenid'],
|
||||
'gewicht' => $input['gewicht'],
|
||||
'anzahlpakete' => $input['anzahlpakete'],
|
||||
'versendet_am' => $input['versendet_am'],
|
||||
'tracking' => $input['tracking'],
|
||||
'abgeschlossen' => 1,
|
||||
];
|
||||
$result = $resource->insert($bindValues);
|
||||
|
||||
return $this->sendResult($result, Response::HTTP_CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trackingnummer bearbeiten
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function updateAction()
|
||||
{
|
||||
$resource = $this->getResource($this->resourceClass);
|
||||
|
||||
$id = $this->getResourceId();
|
||||
$resource->checkOrFail($id);
|
||||
|
||||
$input = $this->getRequestData();
|
||||
$updateData = [];
|
||||
|
||||
// Format prüfen
|
||||
if (isset($input['versendet_am'])) {
|
||||
$updateData['versendet_am'] = $this->ensureShippingDateFormat($input['versendet_am']);
|
||||
}
|
||||
if (isset($input['anzahlpakete'])) {
|
||||
$updateData['anzahlpakete'] = $this->ensureParcelCountFormat($input['anzahlpakete']);
|
||||
}
|
||||
|
||||
if (isset($input['gewicht'])) {
|
||||
$updateData['gewicht'] = (string)$input['gewicht'];
|
||||
}
|
||||
if (isset($input['tracking'])) {
|
||||
$updateData['tracking'] = (string)$input['tracking'];
|
||||
}
|
||||
|
||||
// Prüfen ob Auftragsdaten gültig
|
||||
if (isset($input['lieferschein']) || isset($input['auftrag']) || isset($input['internet'])) {
|
||||
$orderData = $this->ensureOrderData($input['lieferschein'], $input['auftrag'], $input['internet']);
|
||||
|
||||
$updateData['adresse'] = $orderData['adresseid'];
|
||||
$updateData['lieferschein'] = $orderData['lieferscheinid'];
|
||||
$updateData['projekt'] = $orderData['projektid'];
|
||||
$updateData['firma'] = $orderData['firmenid'];
|
||||
}
|
||||
|
||||
if (empty($updateData)) {
|
||||
throw new BadRequestException('Payload is empty.');
|
||||
}
|
||||
$result = $resource->edit($id, $updateData);
|
||||
|
||||
return $this->sendResult($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob Auftragsdaten gültig und gibt diese zurück
|
||||
*
|
||||
* @param string|null $deliveryNoteNumber Lieferscheinnummer
|
||||
* @param string|null $orderNumber Auftragsnummer
|
||||
* @param string|null $internetNumber Internetnummer aus Auftrag
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function ensureOrderData($deliveryNoteNumber = null, $orderNumber = null, $internetNumber = null)
|
||||
{
|
||||
$orderData = [];
|
||||
|
||||
if (!empty($deliveryNoteNumber)) {
|
||||
$orderData = $this->ensureOrderDataByDeliveryNoteNumber($deliveryNoteNumber);
|
||||
}
|
||||
if (!empty($orderNumber)) {
|
||||
$orderData = $this->ensureOrderDataByOrderNumber($orderNumber);
|
||||
}
|
||||
if (!empty($internetNumber)) {
|
||||
$orderData = $this->ensureOrderDataByInternetNumber($internetNumber);
|
||||
}
|
||||
if (count($orderData) === 0) {
|
||||
throw new ValidationErrorException(['Could not find order data.']);
|
||||
}
|
||||
|
||||
return $orderData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auftrag anhand der Internetnummer (im Auftrag) finden
|
||||
*
|
||||
* @param string $internetNumber
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function ensureOrderDataByInternetNumber($internetNumber)
|
||||
{
|
||||
$order = $this->db->fetchAll(
|
||||
'SELECT
|
||||
au.id AS auftragsid,
|
||||
au.projekt AS projektid,
|
||||
au.adresse AS adresseid,
|
||||
au.belegnr AS auftragsnummer,
|
||||
au.internet AS internetnummer,
|
||||
au.firma AS firmenid
|
||||
FROM auftrag AS au
|
||||
WHERE au.internet = :internetnummer',
|
||||
['internetnummer' => $internetNumber]
|
||||
);
|
||||
if (count($order) === 0) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Order not found with internet number "%s".', $internetNumber),
|
||||
]);
|
||||
}
|
||||
if (count($order) > 1) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Logic error: Found more than one order with internet number "%s".', $internetNumber),
|
||||
]);
|
||||
}
|
||||
|
||||
$orderData = $order[0];
|
||||
|
||||
$deliveryNotes = $this->db->fetchAll(
|
||||
'SELECT l.id AS lieferscheinid , l.belegnr AS lieferscheinnummer
|
||||
FROM lieferschein AS l
|
||||
WHERE l.auftragid = :order_id',
|
||||
['order_id' => $orderData['auftragsid']]
|
||||
);
|
||||
if (count($deliveryNotes) === 0) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Delivery note not found for internet number "%s".', $internetNumber),
|
||||
]);
|
||||
}
|
||||
if (count($deliveryNotes) > 1) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Logic error: Found more than one delivery note for internet number "%s".', $internetNumber),
|
||||
]);
|
||||
}
|
||||
|
||||
$orderData['lieferscheinid'] = $deliveryNotes[0]['lieferscheinid'];
|
||||
$orderData['lieferscheinnummer'] = $deliveryNotes[0]['lieferscheinnummer'];
|
||||
|
||||
return $orderData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auftrag anhand der Auftragsnummer finden
|
||||
*
|
||||
* @param string $orderNumber
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function ensureOrderDataByOrderNumber($orderNumber)
|
||||
{
|
||||
$order = $this->db->fetchAll(
|
||||
'SELECT
|
||||
au.id AS auftragsid,
|
||||
au.projekt AS projektid,
|
||||
au.adresse AS adresseid,
|
||||
au.belegnr AS auftragsnummer,
|
||||
au.internet AS internetnummer,
|
||||
au.firma AS firmenid
|
||||
FROM auftrag AS au
|
||||
WHERE au.belegnr = :auftragsnummer',
|
||||
['auftragsnummer' => $orderNumber]
|
||||
);
|
||||
if (count($order) === 0) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Order not found with order number "%s".', $orderNumber),
|
||||
]);
|
||||
}
|
||||
if (count($order) > 1) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Logic error: Found more than one order with order number "%s".', $orderNumber),
|
||||
]);
|
||||
}
|
||||
|
||||
$orderData = $order[0];
|
||||
|
||||
$deliveryNotes = $this->db->fetchAll(
|
||||
'SELECT l.id AS lieferscheinid , l.belegnr AS lieferscheinnummer
|
||||
FROM lieferschein AS l
|
||||
WHERE l.auftragid = :order_id',
|
||||
['order_id' => $orderData['auftragsid']]
|
||||
);
|
||||
if (count($deliveryNotes) === 0) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Delivery note not found for order number "%s".', $orderNumber),
|
||||
]);
|
||||
}
|
||||
if (count($deliveryNotes) > 1) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Logic error: Found more than one delivery note for order number "%s".', $orderNumber),
|
||||
]);
|
||||
}
|
||||
|
||||
$orderData['lieferscheinid'] = $deliveryNotes[0]['lieferscheinid'];
|
||||
$orderData['lieferscheinnummer'] = $deliveryNotes[0]['lieferscheinnummer'];
|
||||
|
||||
return $orderData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auftrag anhand der Lieferscheinnummer finden
|
||||
*
|
||||
* @param string $deliveryNoteNumber
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function ensureOrderDataByDeliveryNoteNumber($deliveryNoteNumber)
|
||||
{
|
||||
$order = $this->db->fetchAll(
|
||||
'SELECT
|
||||
au.id AS auftragsid,
|
||||
au.projekt AS projektid,
|
||||
au.adresse AS adresseid,
|
||||
au.belegnr AS auftragsnummer,
|
||||
au.internet AS internetnummer,
|
||||
l.belegnr AS lieferscheinnummer,
|
||||
l.id AS lieferscheinid,
|
||||
au.firma AS firmenid
|
||||
FROM lieferschein AS l
|
||||
INNER JOIN auftrag AS au ON l.auftragid = au.id
|
||||
WHERE l.belegnr = :lieferschein',
|
||||
['lieferschein' => $deliveryNoteNumber]
|
||||
);
|
||||
if (count($order) === 0) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Order not found with delivery note number "%s".', $deliveryNoteNumber),
|
||||
]);
|
||||
}
|
||||
if (count($order) > 1) {
|
||||
throw new ValidationErrorException([
|
||||
sprintf('Logic error: Found more than one order with delivery note number "%s".', $deliveryNoteNumber),
|
||||
]);
|
||||
}
|
||||
|
||||
return $order[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $shippingDate
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function ensureShippingDateFormat($shippingDate)
|
||||
{
|
||||
if (!preg_match('#^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$#', $shippingDate)) {
|
||||
throw new ValidationErrorException(['Field "versendet_am" does not match required format: YYYY-MM-DD']);
|
||||
}
|
||||
|
||||
return $shippingDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $parcelCount
|
||||
*
|
||||
* @throws ValidationErrorException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function ensureParcelCountFormat($parcelCount)
|
||||
{
|
||||
if (!preg_match('#^[0-9]+$#', $parcelCount)) {
|
||||
throw new ValidationErrorException(['Field "anzahlpakete" does not match required format: [0-9]']);
|
||||
}
|
||||
|
||||
return (int)$parcelCount;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user