diff --git a/src/Entities/Receipt.php b/src/Entities/Receipt.php index dd9694f..db18db9 100644 --- a/src/Entities/Receipt.php +++ b/src/Entities/Receipt.php @@ -196,7 +196,7 @@ class Receipt extends Entity */ public function getItems(): Items { - return $this->items; + return $this->items ?? new Items(); } /** @@ -207,6 +207,7 @@ class Receipt extends Entity * @return Receipt * @throws EmptyItemsException * @throws InvalidEntityInCollectionException + * @throws Exception */ public function setItems(Items $items): self { @@ -215,6 +216,8 @@ class Receipt extends Entity } $items->checkItemsClasses(); $this->items = $items; + $this->getItems()->each(fn ($item) => $this->total += $item->getSum()); + $this->total = round($this->total, 2); return $this; } @@ -251,7 +254,7 @@ class Receipt extends Entity */ public function getVats(): ?Vats { - return $this->vats; + return $this->vats ?? new Vats(); } /** @@ -260,6 +263,7 @@ class Receipt extends Entity * @param Vats|null $vats * @return Receipt * @throws EmptyVatsException + * @throws Exception */ public function setVats(?Vats $vats): self { @@ -267,6 +271,8 @@ class Receipt extends Entity throw new EmptyVatsException(); } $this->vats = $vats; + /** @var Vat $vat */ + $this->getVats()->each(fn ($vat) => $vat->setSum($this->getTotal())); return $this; } @@ -280,18 +286,6 @@ class Receipt extends Entity return $this->total; } - /** - * Устанавливает полную сумму чека - * - * @param float $total - * @return Receipt - */ - public function setTotal(float $total): self - { - $this->total = $total; - return $this; - } - /** * Возвращает установленного кассира * @@ -387,28 +381,11 @@ class Receipt extends Entity 'payments' => $this->getPayments(), ]; $this->getAgentInfo()?->jsonSerialize() && $json['agent_info'] = $this->getAgentInfo(); - $this->getSupplier()?->jsonSerialize() && $json['vats'] = $this->getVats(); + $this->getSupplier()?->jsonSerialize() && $json['supplier_info'] = $this->getSupplier(); $this->getVats()?->jsonSerialize() && $json['vats'] = $this->getVats(); !is_null($this->getAddCheckProps()) && $json['additional_check_props'] = $this->getAddCheckProps(); !is_null($this->getCashier()) && $json['cashier'] = $this->getCashier(); $this->getAddUserProps()?->jsonSerialize() && $json['additional_user_props'] = $this->getAddUserProps(); return $json; } - - ///** - // * Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020. - // * - // * @return float - // * @throws Exception - // */ - //public function calcTotal(): float - //{ - // $sum = 0; - // $this->clearVats(); - // foreach ($this->items->get() as $item) { - // $sum += $item->calcSum(); - // $this->addVat(new Vat($item->getVat()->getType(), $item->getSum())); - // } - // return $this->total = round($sum, 2); - //} } diff --git a/tests/AtolOnline/Tests/Entities/ReceiptTest.php b/tests/AtolOnline/Tests/Entities/ReceiptTest.php index 57628b6..3075b3d 100644 --- a/tests/AtolOnline/Tests/Entities/ReceiptTest.php +++ b/tests/AtolOnline/Tests/Entities/ReceiptTest.php @@ -12,6 +12,7 @@ namespace AtolOnline\Tests\Entities; use AtolOnline\{ Collections\Items, Collections\Payments, + Collections\Vats, Entities\AgentInfo, Entities\Client, Entities\Company, @@ -20,6 +21,8 @@ use AtolOnline\{ Entities\PayingAgent, Entities\Receipt, Entities\ReceivePaymentsOperator, + Entities\Supplier, + Entities\Vat, Enums\AgentTypes, Enums\SnoTypes, Tests\BasicTestCase}; @@ -27,6 +30,7 @@ use AtolOnline\Exceptions\{ EmptyItemNameException, EmptyItemsException, EmptyPaymentsException, + EmptyVatsException, InvalidEntityInCollectionException, InvalidEnumValueException, InvalidInnLengthException, @@ -35,6 +39,7 @@ use AtolOnline\Exceptions\{ NegativeItemQuantityException, NegativePaymentSumException, TooHighItemPriceException, + TooHighItemSumException, TooHighPaymentSumException, TooLongItemNameException, TooLongPayingAgentOperationException, @@ -76,8 +81,9 @@ class ReceiptTest extends BasicTestCase */ public function testConstructor(): void { - $receipt = $this->validReceipt(); + $receipt = $this->newReceipt(); $this->assertIsAtolable($receipt); + $receipt->getItems(); } /** @@ -104,7 +110,7 @@ class ReceiptTest extends BasicTestCase * @throws TooLongPayingAgentOperationException * @throws Exception */ - public function testSetAgentInfo(): void + public function testAgentInfo(): void { $agent_info = new AgentInfo( AgentTypes::ANOTHER, @@ -112,9 +118,42 @@ class ReceiptTest extends BasicTestCase new ReceivePaymentsOperator(['+79519999999']), new MoneyTransferOperator('MTO Name', '9876543210', 'London', ['+79517777777']), ); - $receipt = $this->validReceipt()->setAgentInfo($agent_info); + $receipt = $this->newReceipt()->setAgentInfo($agent_info); $this->assertArrayHasKey('agent_info', $receipt->jsonSerialize()); $this->assertEquals($receipt->getAgentInfo(), $receipt->jsonSerialize()['agent_info']); + $this->assertArrayNotHasKey('agent_info', $receipt->setAgentInfo(null)->jsonSerialize()); + } + + /** + * Тестирует установку данных поставщика + * + * @return void + * @covers \AtolOnline\Entities\Receipt::setSupplier + * @covers \AtolOnline\Entities\Receipt::getSupplier + * @covers \AtolOnline\Entities\Receipt::jsonSerialize + * @throws EmptyItemNameException + * @throws EmptyItemsException + * @throws EmptyPaymentsException + * @throws InvalidEntityInCollectionException + * @throws InvalidEnumValueException + * @throws InvalidInnLengthException + * @throws InvalidPhoneException + * @throws NegativeItemPriceException + * @throws NegativeItemQuantityException + * @throws NegativePaymentSumException + * @throws TooHighItemPriceException + * @throws TooHighPaymentSumException + * @throws TooLongItemNameException + * @throws TooManyException + * @throws Exception + */ + public function testSupplier(): void + { + $supplier = new Supplier('some name', '+fasd3\qe3fs_=nac99013928czc', ['+122997365456']); + $receipt = $this->newReceipt()->setSupplier($supplier); + $this->assertArrayHasKey('supplier_info', $receipt->jsonSerialize()); + $this->assertEquals($receipt->getSupplier(), $receipt->jsonSerialize()['supplier_info']); + $this->assertArrayNotHasKey('supplier_info', $receipt->setSupplier(null)->jsonSerialize()); } /** @@ -122,7 +161,7 @@ class ReceiptTest extends BasicTestCase * * @return void * @covers \AtolOnline\Entities\Receipt - * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Entities\Receipt::setItems * @covers \AtolOnline\Collections\Items::checkCount * @covers \AtolOnline\Exceptions\EmptyItemsException * @throws InvalidEnumValueException @@ -147,7 +186,7 @@ class ReceiptTest extends BasicTestCase * * @return void * @covers \AtolOnline\Entities\Receipt - * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Entities\Receipt::setItems * @covers \AtolOnline\Collections\Items::checkItemsClasses * @covers \AtolOnline\Collections\Items::checkItemClass * @covers \AtolOnline\Exceptions\InvalidEntityInCollectionException @@ -204,7 +243,7 @@ class ReceiptTest extends BasicTestCase * * @return void * @covers \AtolOnline\Entities\Receipt - * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Entities\Receipt::setPayments * @covers \AtolOnline\Collections\Items::checkItemsClasses * @covers \AtolOnline\Collections\Items::checkItemClass * @covers \AtolOnline\Exceptions\InvalidEntityInCollectionException @@ -230,6 +269,103 @@ class ReceiptTest extends BasicTestCase ); } + /** + * Тестирует выброс исключения при передаче пустой коллекции ставок НДС + * + * @return void + * @covers \AtolOnline\Entities\Receipt + * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Collections\Vats::checkCount + * @covers \AtolOnline\Exceptions\EmptyVatsException + * @throws EmptyItemNameException + * @throws EmptyItemsException + * @throws EmptyPaymentsException + * @throws EmptyVatsException + * @throws InvalidEntityInCollectionException + * @throws InvalidEnumValueException + * @throws NegativeItemPriceException + * @throws NegativeItemQuantityException + * @throws NegativePaymentSumException + * @throws TooHighItemPriceException + * @throws TooHighPaymentSumException + * @throws TooLongItemNameException + * @throws TooManyException + */ + public function testEmptyVatsException(): void + { + $this->expectException(EmptyVatsException::class); + $this->newReceipt()->setVats(new Vats([])); + } + + /** + * Тестирует выброс исключения при передаче коллекции ставок НДС с некорректным содержимым + * + * @return void + * @covers \AtolOnline\Entities\Receipt + * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Collections\Vats::checkItemsClasses + * @covers \AtolOnline\Collections\Vats::checkItemClass + * @covers \AtolOnline\Exceptions\InvalidEntityInCollectionException + * @throws EmptyItemNameException + * @throws EmptyItemsException + * @throws EmptyPaymentsException + * @throws EmptyVatsException + * @throws InvalidEntityInCollectionException + * @throws InvalidEnumValueException + * @throws NegativeItemPriceException + * @throws NegativeItemQuantityException + * @throws NegativePaymentSumException + * @throws TooHighItemPriceException + * @throws TooHighPaymentSumException + * @throws TooLongItemNameException + * @throws TooManyException + */ + public function testInvalidVatInCollectionException(): void + { + $this->expectException(InvalidEntityInCollectionException::class); + $this->expectErrorMessage('Коллекция AtolOnline\Collections\Vats должна содержать объекты AtolOnline\Entities\Vat'); + $this->newReceipt()->setVats(new Vats(['qwerty'])); + } + + /** + * Тестирует просчёт общей суммы чека и ставок НДС + * + * @covers \AtolOnline\Entities\Receipt::setVats + * @covers \AtolOnline\Entities\Receipt::getVats + * @covers \AtolOnline\Entities\Receipt::getTotal + * @throws TooHighItemPriceException + * @throws NegativeItemPriceException + * @throws EmptyPaymentsException + * @throws InvalidEntityInCollectionException + * @throws InvalidEnumValueException + * @throws TooHighItemSumException + * @throws NegativePaymentSumException + * @throws TooHighPaymentSumException + * @throws EmptyItemsException + * @throws EmptyItemNameException + * @throws TooManyException + * @throws NegativeItemQuantityException + * @throws TooLongItemNameException + * @throws Exception + */ + public function testCalculations(): void + { + $items_total = 0; + $receipt = $this->newReceipt(); + + //TODO при $receipt->getItems()->pluck('sum') стреляет InvalidEntityInCollectionException + // см. примечания в конструкторе EntityCollection + $receipt->getItems()->each(function ($item) use (&$items_total) { + /** @var Item $item */ + return $items_total += $item->getSum(); + }); + $this->assertEquals($items_total, $receipt->getTotal()); + + /** @var Vat $vat */ + $receipt->setVats(new Vats($this->generateVatObjects(2)))->getVats() + ->each(fn ($vat) => $this->assertEquals($items_total, $vat->getSum())); + } + /** * Возвращает валидный тестовый объект чека * @@ -247,12 +383,12 @@ class ReceiptTest extends BasicTestCase * @throws TooLongItemNameException * @throws TooManyException */ - protected function validReceipt(): Receipt + protected function newReceipt(): Receipt { return new Receipt( new Client('John Doe', 'john@example.com', '+1/22/99*73s dsdas654 5s6', '+fasd3\qe3fs_=nac99013928czc'), new Company('company@example.com', SnoTypes::OSN, '1234567890', 'https://example.com'), - new Items($this->generateItemObjects()), + new Items($this->generateItemObjects(2)), new Payments($this->generatePaymentObjects()) ); }