OpenXE/classes/Modules/FiskalyApi/Service/FiskalyTransactionPosSessionService.php
2021-05-21 08:49:41 +02:00

384 lines
13 KiB
PHP

<?php
declare(strict_types=1);
namespace Xentral\Modules\FiskalyApi\Service;
use Datetime;
use DateTimeZone;
use Exception;
use Xentral\Components\Database\Database;
use Xentral\Modules\FiskalyApi\Data\Export;
use Xentral\Modules\FiskalyApi\Data\Transaction\TransactionReponse;
use Xentral\Modules\FiskalyApi\Data\Transaction\TransactionReponseCollection;
use Xentral\Modules\FiskalyApi\Data\Transaction\TransactionRequest;
use Xentral\Modules\FiskalyApi\Exception\InvalidArgumentException;
use Xentral\Modules\FiskalyApi\Exception\InvalidTransactionException;
final class FiskalyTransactionPosSessionService implements FiskalyTransactionPosSessionInterface
{
/** @var Database $db */
private $db;
/**
* FiskalyTransactionPosSessionService constructor.
*
* @param Database $db
*/
public function __construct(Database $db)
{
$this->db = $db;
}
/**
* @param string $trxId
*
* @return array|null
*/
public function get(string $trxId): ?array
{
return $this->db->fetchRow(
'SELECT * FROM `fiskaly_transaction` WHERE `trx_id` = :trx_id',
['trx_id' => $trxId]
);
}
/**
* @param TransactionReponseCollection $transactionResponseCollection
*/
public function insertTransactions(TransactionReponseCollection $transactionResponseCollection): void
{
foreach ($transactionResponseCollection as $transactionResponse) {
$trxId = $transactionResponse->getId();
if (!empty($this->get($trxId))) {
continue;
}
$this->create(null, $transactionResponse);
}
}
/**
* @param string $trxId
*
* @return int|null
*/
public function getTransactionIdFromTrxId(string $trxId): ?int
{
$fiskalyTransactionId = $this->db->fetchValue(
'SELECT `id` FROM `fiskaly_transaction` WHERE `trx_id` = :trx_id',
[
'trx_id' => $trxId,
]
);
return $fiskalyTransactionId === false ? null : (int)$fiskalyTransactionId;
}
/**
* @param string $document
* @param int $documentId
*
* @return array
*/
public function getTransactionFromDocument(string $document, int $documentId): array
{
return $this->db->fetchRow(
'SELECT ft.*
FROM `fiskaly_transaction` AS `ft`
INNER JOIN `fiskaly_tranaction_mapping` AS `ftm` ON ft.id = ftm.fiskaly_transaction_id
WHERE ftm.document = :document AND ftm.document_id = :document_id',
[
'document' => $document,
'document_id' => $documentId,
]
);
}
/**
* @param string $trxId
* @param string $document
* @param int $documentId
*
* @return int
*/
public function tryMapDocument(string $trxId, string $document, int $documentId): int
{
$fiskalyTransactionId = $this->getTransactionIdFromTrxId($trxId);
$mappingId = $fiskalyTransactionId === null ? false : $this->db->fetchValue(
'SELECT ftm.id
FROM `fiskaly_tranaction_mapping` AS `ftm`
WHERE ftm.fiskaly_transaction_id = :fiskaly_transaction_id
AND ftm.document = :document
AND ftm.document_id = :document_id',
[
'fiskaly_transaction_id' => $fiskalyTransactionId,
'document' => $document,
'document_id' => $documentId,
]
);
if ($mappingId !== false) {
return (int)$mappingId;
}
$this->db->perform(
'INSERT INTO `fiskaly_tranaction_mapping` (`fiskaly_transaction_id`, `document`, `document_id`)
VALUES (:fiskaly_transaction_id, :document, :document_id)',
[
'fiskaly_transaction_id' => $fiskalyTransactionId,
'document' => $document,
'document_id' => $documentId,
]
);
return $this->db->lastInsertId();
}
/**
* @param TransactionRequest|null $request
* @param TransactionReponse|null $response
*
* @return int
*/
public function create(
?TransactionRequest $request,
?TransactionReponse $response
): int {
if ($request === null && $response === null) {
throw new InvalidArgumentException('response or request required');
}
$trxId = $request === null ? $response->getId() : $request->getId();
if (!empty($this->get($trxId))) {
throw new InvalidTransactionException('Transaction already exists');
}
$this->db->perform(
'INSERT INTO `fiskaly_transaction`
(`tss_id`, `client_id`, `trx_id`, `state`,
`time_start`, `time_end`, `json_request`, `json_response`)
VALUES (:tss_id, :client_id, :trx_id, :state,
NULL, NULL, :json_request, :json_response)',
[
'tss_id' => $request === null ? $response->getTssId() : $request->getTssId(),
'client_id' => $request === null ? $response->getClientId() : $request->getClientId(),
'trx_id' => $trxId,
'state' => $response === null ? null : $response->getState(),
'json_request' => $request === null ? null : json_encode($request->toArray()),
'json_response' => $response === null ? null : json_encode($response->toArray()),
]
);
$fiskalyTransactionId = $this->db->lastInsertId();
if ($response === null) {
return $fiskalyTransactionId;
}
if ($response->getTimeStart() !== null) {
$this->db->perform(
'UPDATE `fiskaly_transaction`
SET `time_start` = FROM_UNIXTIME(:time_start)
WHERE `id` = :id',
[
'time_start' => $response->getTimeStart()->getTimestamp(),
'id' => $fiskalyTransactionId,
]
);
}
if ($response->getTimeEnd() !== null) {
$this->db->perform(
'UPDATE `fiskaly_transaction`
SET `time_end` = FROM_UNIXTIME(:time_end)
WHERE `id` = :id',
[
'time_end' => $response->getTimeEnd()->getTimestamp(),
'id' => $fiskalyTransactionId,
]
);
}
return $fiskalyTransactionId;
}
/**
* @param int $fiskalyTransactionPosSessionId
* @param TransactionRequest $request
* @param TransactionReponse $response
*/
public function update(
int $fiskalyTransactionPosSessionId,
TransactionRequest $request,
TransactionReponse $response
): void {
if ($response->getTimeEnd() === null) {
$this->db->perform(
'UPDATE `fiskaly_transaction`
SET `state` = :state,
`time_end` = NULL,
`json_request` = :json_request,
`json_response` = :json_response
WHERE `id` = :id',
[
'state' => $response->getState(),
'json_request' => json_encode($request->toApiResult()),
'json_response' => json_encode($response->toApiResult()),
'id' => $fiskalyTransactionPosSessionId,
]
);
return;
}
$this->db->perform(
'UPDATE `fiskaly_transaction`
SET `state` = :state,
`time_end` = FROM_UNIXTIME(:time_end),
`json_request` = :json_request,
`json_response` = :json_response
WHERE `id` = :id',
[
'state' => $response->getState(),
'time_end' => $response->getTimeEnd()->getTimestamp(),
'json_request' => json_encode($request->toApiResult()),
'json_response' => json_encode($response->toApiResult()),
'id' => $fiskalyTransactionPosSessionId,
]
);
}
/**
* @param Export $export
*
* @throws Exception
*/
public function createOrUpdateExport(Export $export): void
{
if ($this->getExportIdFromUuid($export->getUuId()) === null) {
$this->createExport($export);
return;
}
$this->updateExport($export);
}
/**
* @param Export $export
*
* @throws Exception
* @return int
*/
public function createExport(Export $export): int
{
$this->db->perform(
'INSERT INTO `fiskaly_kassensichv_export`
(`uuid`, `type`, `env`, `tssid`, `state`, `href`, `time_request`, `time_start`, `time_end`)
VALUES (:uuid, :type, :env, :tssid, :state, :href, :time_request, :time_start, :time_end)',
[
'uuid' => $export->getUuId(),
'type' => $export->getType(),
'env' => $export->getEnv(),
'tssid' => $export->getTssId(),
'state' => $export->getState(),
'href' => $export->getHref(),
'time_request' => $export->getTimeRequest() === null ? null : (new Datetime(
'now',
new DateTimeZone('UTC')
))->setTimeStamp(
$export->getTimeRequest()
)->format('Y-m-d H:i:s'),
'time_start' => $export->getTimeStart() === null ? null : (new Datetime(
'now', new DateTimeZone('UTC')
))->setTimeStamp($export->getTimeStart())
->format('Y-m-d H:i:s'),
'time_end' => $export->getTimeEnd() === null ? null : (new Datetime(
'now', new DateTimeZone('UTC')
))->setTimeStamp($export->getTimeEnd())
->format('Y-m-d H:i:s'),
]
);
return $this->db->lastInsertId();
}
/**
* @param Export $export
*
* @throws Exception
*/
public function updateExport(Export $export): void
{
$this->db->perform(
'UPDATE `fiskaly_kassensichv_export`
SET `state` = :state,
`href` = :href,
`time_request` = :time_request,
`time_start` = :time_start,
`time_end` = :time_end
WHERE `uuid` = :uuid',
[
'uuid' => $export->getUuId(),
'state' => $export->getState(),
'href' => $export->getHref(),
'time_request' => (new Datetime('now', new DateTimeZone('UTC')))->setTimeStamp(
$export->getTimeRequest()
)->format('Y-m-d H:i:s'),
'time_start' => (new Datetime('now', new DateTimeZone('UTC')))->setTimeStamp($export->getTimeStart())
->format('Y-m-d H:i:s'),
'time_end' => (new Datetime('now', new DateTimeZone('UTC')))->setTimeStamp($export->getTimeEnd())
->format('Y-m-d H:i:s'),
]
);
}
/**
* @param string $tssId
*
* @return array
*/
public function getExportUrlsNotInDms(string $tssId): array
{
return $this->db->fetchAll(
"SELECT fke.id, fke.href, fke.uuid
FROM `fiskaly_kassensichv_export` AS `fke`
LEFT JOIN `datei_stichwoerter` AS `ds` ON fke.id = ds.parameter AND ds.objekt = 'fiskaly_kassensichv_export'
WHERE `fke`.state = 'COMPLETED' AND fke.tssid = :tssid AND ds.id IS NULL",
['tssid' => $tssId]
);
}
/**
* @param string $state
* @param string|null $tssId
*
* @return array
*/
public function getUuIdsByState(string $state, ?string $tssId = null): array
{
if ($tssId === null) {
return $this->db->fetchCol(
'SELECT `uuid` FROM `fiskaly_kassensichv_export` WHERE `state` = :state',
[
'state' => $state,
]
);
}
return $this->db->fetchCol(
'SELECT `uuid` FROM `fiskaly_kassensichv_export` WHERE `tssid` = :tssid AND `state` = :state',
[
'tssid' => $tssId,
'state' => $state,
]
);
}
/**
* @param string $uuid
*
* @return int|null
*/
private function getExportIdFromUuid(string $uuid): ?int
{
$id = $this->db->fetchValue(
'SELECT `id` FROM `fiskaly_kassensichv_export` WHERE `uuid` = :uuid',
['uuid' => $uuid]
);
return $id === false ? null : (int)$id;
}
}