Commit 80dabfc6 authored by Karamel's avatar Karamel
Browse files

Rewrite CashsessionAPI->write like tickets. Fiscal number disociated from session number.

parent 5f0b0cc4
......@@ -22,6 +22,7 @@
namespace Pasteque\Server\API;
use \Pasteque\Server\API\FiscalAPI;
use \Pasteque\Server\Model\CashRegister;
use \Pasteque\Server\Model\CashSession;
use \Pasteque\Server\Model\FiscalTicket;
......@@ -80,27 +81,17 @@ class CashsessionAPI extends APIHelper implements API
* @param $reason The technical fault, added in the FiscalTicket. */
private function registerFailure($session, $reason) {
$sequence = FiscalTicket::getFailureZTicketSequence($session);
$number = 1; /* Number is dissociated from session number, because the
* same number can be rejected multiple times. */
// Look for the last failure in sequence to get the number.
$previousFTicket = null;
$prevSearch = $this->dao->search(FiscalTicket::class,
[new DAOCondition('type', '=', FiscalTicket::TYPE_ZTICKET),
new DAOCondition('sequence', '=', $sequence)],
1, null, '-number');
if (count($prevSearch) > 0) {
$previousFTicket = $prevSearch[0];
if ($previousFTicket->getNumber() === 0) {
$previousFTicket = null; // Ignore EOS
} else {
$number = $previousFTicket->getNumber() + 1;
}
}
// Create the failure fiscal ticket.
$fiscalAPI = new FiscalAPI($this->dao);
$previousFTicket = $fiscalAPI->getLastFiscalTicket(FiscalTicket::TYPE_ZTICKET, $sequence);
// Create the failure ticket
$fiscalTicket = new FiscalTicket();
$fiscalTicket->setType(FiscalTicket::TYPE_ZTICKET);
$fiscalTicket->setSequence($sequence);
$fiscalTicket->setNumber($number);
if ($previousFTicket !== null) {
$fiscalTicket->setNumber($previousFTicket->getNumber() + 1);
} else {
$fiscalTicket->setNumber(1);
}
$fiscalTicket->setDate(new \DateTime());
$stone = $session->toStone();
$stone['failure'] = $reason;
......@@ -113,91 +104,85 @@ class CashsessionAPI extends APIHelper implements API
$this->dao->commit();
}
/** Write session data. Can be called only once all the tickets are stored.
* To write all data at once (open, tickets and close), a call to write must
* be done first with the opened session. Then register all the tickets and
* finally call write with the full cash session data.
/** Write a cash session. At least two calls must be performed during the lifespan.
* One to open, one to close. Tickets are stored between these calls.
* When closing a session, the next one is automatically created.
* @return The entry or the array of entries.
* @throw \BadMethodCallException When trying to close a session without
* @param $session The session to register (cannot be an array of sessions).
* @return The session after registration.
* @throws \BadMethodCallException When trying to close a session without
* writing it as opened before, or when trying to update an already closed
* session. */
public function write($data) {
$this->supportOrDie($data);
$arrayArgs = is_array($data);
$data = ($arrayArgs) ? $data : array($data);
$previousFTicket = null;
foreach ($data as $d) {
// Defensive checks
// Reserved number 0
if ($d->getSequence() === 0) {
$rejectReason = 'Session number 0 is reserved.';
$this->registerFailure($d, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
$currentData = $this->dao->readSnapshot(static::MODEL_NAME, $d->getId());
// Overwriting a closed session
if ($currentData !== null && $currentData->isClosed()) {
$rejectReason = 'Closed sessions are read-only.';
$this->registerFailure($d, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
if ($currentData === null && $d->isClosed()) {
// Trying to register everything at once, this will prevent
// registering the tickets. Throw an error.
$rejectReason = 'Trying to close a session that was not registered as open.';
$this->registerFailure($d, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
if ($d->isClosed()) {
// Create associated fiscal ticket
$fiscalTicket = new FiscalTicket();
$fiscalTicket->setType(FiscalTicket::TYPE_ZTICKET);
$fiscalTicket->setSequence(FiscalTicket::getZTicketSequence($d));
$fiscalTicket->setNumber($d->getSequence());
$fiscalTicket->setDate($d->getCloseDate());
$fiscalTicket->setContent(json_encode($d->toStone()));
// Check continuity and integrity
if ($d->getSequence() == 1 && $previousFTicket !== null) {
// No.1 with a previous ticket
// TODO: warn messing up things
$previousFTicket = null;
} elseif ($previousFTicket !== null) {
// Check number continuity from previous to this one
if ($previousFTicket->getNumber() != $d->getSequence() - 1) {
// TODO: warn ticket discontinuity
}
} else { // $previousTicket is null and it's not No.1
// First registered ticket, get the previous one
$previousFTicket = $this->dao->read(FiscalTicket::class,
['type' => FiscalTicket::TYPE_ZTICKET,
'sequence' => $fiscalTicket->getSequence(),
'number' => $fiscalTicket->getNumber() - 1]);
if ($previousFTicket === null) {
// TODO: warn discontinuity
}
}
// Sign
$fiscalTicket->sign($previousFTicket);
$this->dao->write($fiscalTicket);
$previousFTicket = $fiscalTicket;
// Create next empty session
$next = new CashSession();
$next->setCashRegister($d->getCashRegister());
$next->setSequence($d->getSequence() + 1);
$next->setContinuous(true); // until proven different by clients
$next->initSums($d);
$this->dao->write($next);
}
$this->dao->write($d);
* session.
* @throws \Exception When an unknown error occurs.
* Nothing is registered in that case (at least it shouldn't). */
public function write($session) {
if (get_class($session) !== static::MODEL_NAME) {
throw new \InvalidArgumentException(sprintf('Incompatible class %s expecting %s', get_class($session), static::MODEL_NAME));
}
$this->updateEOSTicket($previousFTicket);
$this->dao->commit();
if ($arrayArgs) {
return $data;
// Defensive checks
// Reserved number 0
if ($session->getSequence() === 0) {
$rejectReason = 'Session number 0 is reserved.';
$this->registerFailure($session, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
$currentData = $this->dao->readSnapshot(static::MODEL_NAME, $session->getId());
// Overwriting a closed session
if ($currentData !== null && $currentData->isClosed()) {
$rejectReason = 'Closed sessions are read-only.';
$this->registerFailure($session, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
if ($currentData === null && $session->isClosed()) {
// Trying to register everything at once, this will prevent
// registering the tickets. Throw an error.
$rejectReason = 'Trying to close a session that was not registered as open.';
$this->registerFailure($session, $rejectReason);
throw new \BadMethodCallException($rejectReason);
}
if ($session->isClosed()) {
$fiscalAPI = new FiscalAPI($this->dao);
$sequence = FiscalTicket::getZTicketSequence($session);
$previousFTicket = $fiscalAPI->getLastFiscalTicket(FiscalTicket::TYPE_ZTICKET, $sequence);
// Create associated fiscal ticket
$fiscalTicket = new FiscalTicket();
$fiscalTicket->setType(FiscalTicket::TYPE_ZTICKET);
$fiscalTicket->setSequence($sequence);
if ($previousFTicket !== null) {
$fiscalTicket->setNumber($previousFTicket->getNumber() + 1);
} else {
$fiscalTicket->setNumber(1);
}
$fiscalTicket->setDate($session->getCloseDate());
$fiscalTicket->setContent(json_encode($session->toStone()));
// Sign
$fiscalTicket->sign($previousFTicket);
// Write
$this->dao->write($session);
$this->dao->write($fiscalTicket);
$this->updateEOSTicket($fiscalTicket);
// Create next empty session
$next = new CashSession();
$next->setCashRegister($session->getCashRegister());
$next->setSequence($session->getSequence() + 1);
$next->setContinuous(true); // until proven different by clients
$next->initSums($session);
$this->dao->write($next);
} else {
return $data[0];
$this->dao->write($session);
}
// Commit
try {
$this->dao->commit();
} catch (\Exception $e) {
// Consider the write error as an input error, try to register
// a failure ticket
$rejectReason = 'Error: ' . $e->getMessage();
$this->registerFailure($session, $rejectReason);
throw new \BadMethodCallException($rejectReason);
// If an error occurs while registering the failure, the exception
// will be propagated.
}
return $session;
}
/** Update the signature of the end-of-sequence FiscalTicket with
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment