Commit a0f0f227 authored by Karamel's avatar Karamel
Browse files

Add UnicityException on TicketAPI with duplicated line number or tax lines.

parent 873aadff
......@@ -24,6 +24,7 @@ namespace Pasteque\Server\API;
use \Pasteque\Server\Exception\InvalidRecordException;
use \Pasteque\Server\Exception\InvalidFieldException;
use \Pasteque\Server\Exception\UnicityException;
use \Pasteque\Server\Model\CashRegister;
use \Pasteque\Server\Model\CashSession;
use \Pasteque\Server\Model\FiscalTicket;
......@@ -167,8 +168,36 @@ class TicketAPI extends APIHelper implements API
try {
$this->dao->commit();
} catch (\Exception $e) {
// Consider the write error as an input error, try to register
// a failure ticket.
// Maybe it is because of duplicated ticket lines
$lineDispOrders = [];
foreach ($ticket->getLines() as $line) {
$dispOrder = $line->getDispOrder();
if (array_key_exists($dispOrder, $lineDispOrders)) {
$rejectReason = sprintf('Error: duplicated line n°%d',
$dispOrder);
$this->registerFailure($ticket, $rejectReason);
throw new UnicityException(Ticket::class,
'lines.dispOrder', $dispOrder);
} else {
$lineDispOrders[$dispOrder] = true;
}
}
// Or duplicated tax lines
$taxes = [];
foreach ($ticket->getTaxes() as $tax) {
$taxId = $tax->getTax()->getId();
if (array_key_exists($taxId, $taxes)) {
$rejectReason = sprintf('Error: duplicated tax with id %d',
$taxId);
$this->registerFailure($ticket, $rejectReason);
throw new UnicityException(Ticket::class,
'taxes.tax', $taxId);
} else {
$taxes[$taxId] = true;
}
}
// Anyway, consider the write error as an input error,
// try to register a failure ticket.
$rejectReason = 'Error: ' . $e->getMessage();
$this->registerFailure($ticket, $rejectReason);
throw new \BadMethodCallException($rejectReason, 0, $e);
......
<?php
// Pastèque API
//
// Copyright (C) 2012-2015 Scil (http://scil.coop)
// Cédric Houbart, Philippe Pary
//
// This file is part of Pastèque.
//
// Pastèque is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pastèque is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pastèque. If not, see <http://www.gnu.org/licenses/>.
namespace Pasteque\Server\Exception;
/**
* The operation failed because the value of a field is required
* to be unique.
* Id fields are excluded, those are not business-related.
*/
class UnicityException extends \Exception implements PastequeException
{
private $class;
private $field;
private $value;
public function __construct($class, $field, $value) {
$this->class = $class;
$this->field = $field;
$this->value = $value;
$msg = sprintf('The value of %s for %s must be unique (faulty value is %s of type %s).',
$this->field, $this->class, $this->getJsonableValue(),
gettype($value));
parent::__construct($msg);
}
public function getClass() {
return $this->class;
}
public function getField() {
return $this->field;
}
public function getValue() {
return $this->value;
}
public function getJsonableValue() {
if (gettype($this->value) == 'resource') {
return '<resource>';
} else {
return $this->value;
}
}
public function toStruct() {
return [
'error' => 'UnicityException',
'class' => $this->class,
'field' => $this->field,
'value' => $this->getJsonableValue(),
'message' => $this->message,
];
}
}
......@@ -25,6 +25,7 @@ use \Pasteque\Server\API\CustomerAPI;
use \Pasteque\Server\API\TicketAPI;
use \Pasteque\Server\Exception\InvalidFieldException;
use \Pasteque\Server\Exception\InvalidRecordException;
use \Pasteque\Server\Exception\UnicityException;
use \Pasteque\Server\Model\Category;
use \Pasteque\Server\Model\CashRegister;
use \Pasteque\Server\Model\CashSession;
......@@ -568,7 +569,6 @@ class TicketAPITest extends TestCase
/** @depends testSaveTicket
* Test writing a ticket with invalid data (twice the same line number) */
public function testSaveScrewedTicket() {
$this->expectException(\BadMethodCallException::class);
$line1 = TicketLine::fromStruct(['dispOrder' => 1,
'taxedUnitPrice' => 11.0,
'quantity' => 1, 'tax' => $this->tax->getId(),
......@@ -604,7 +604,37 @@ class TicketAPITest extends TestCase
'amount' => 33.0,
'currencyAmount' => 33.0], $this->dao);
$tkt->addPayment($pm1);
$this->api->write($tkt);
$exceptionThrown = false;
try {
$this->api->write($tkt);
} catch (UnicityException $e) {
$exceptionThrown = true;
// Check the exception
$this->assertEquals(Ticket::class, $e->getClass());
$this->assertEquals('lines.dispOrder', $e->getField());
$this->assertEquals(2, $e->getValue());
// Check that the ticket was not registered.
$searchTkt = $this->dao->search(Ticket::class);
$this->assertEquals(0, count($searchTkt));
// Check that the failure fiscal ticket is there.
$readfTkt = $this->dao->read(FiscalTicket::class, [
'type' => FiscalTicket::TYPE_TICKET,
'sequence' => FiscalTicket::getFailureTicketSequence($tkt),
'number' => 1]);
$readEOSTkt = $this->dao->read(FiscalTicket::class, [
'type' => FiscalTicket::TYPE_TICKET,
'sequence' => FiscalTicket::getFailureTicketSequence($tkt),
'number' => 0]);
$this->assertNotNull($readfTkt);
$this->assertNotNull($readEOSTkt);
$fdata = json_decode($readfTkt->getContent(), true);
$this->assertNotNull($fdata);
$this->assertEquals('Error: duplicated line n°2',
$fdata['failure']);
$this->assertTrue($readfTkt->checkSignature(null));
$this->assertTrue($readEOSTkt->checkSignature($readfTkt));
}
$this->assertTrue($exceptionThrown, 'Expecting UnicityException.');
}
/** @depends testSaveTicket */
......
Markdown is supported
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