Skip to content

Commit

Permalink
[CreditMemo] Add tax items to credit memo
Browse files Browse the repository at this point in the history
  • Loading branch information
GSadee committed Jan 14, 2020
1 parent dc9eabb commit f93fc37
Show file tree
Hide file tree
Showing 20 changed files with 447 additions and 8 deletions.
25 changes: 25 additions & 0 deletions migrations/Version20200113091731.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20200113091731 extends AbstractMigration
{
public function up(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');

$this->addSql('ALTER TABLE sylius_refund_credit_memo ADD tax_items LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:json)\'');
}

public function down(Schema $schema): void
{
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');

$this->addSql('ALTER TABLE sylius_refund_credit_memo DROP tax_items');
}
}
13 changes: 13 additions & 0 deletions spec/Entity/CreditMemoSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
use Sylius\RefundPlugin\Entity\CreditMemoUnit;
use Sylius\RefundPlugin\Entity\CustomerBillingData;
use Sylius\RefundPlugin\Entity\ShopBillingData;
use Sylius\RefundPlugin\Entity\TaxItem;

final class CreditMemoSpec extends ObjectBehavior
{
function let(ChannelInterface $channel): void
{
$creditMemoUnit = new CreditMemoUnit('Portal gun', 1000, 50);
$taxItem = new TaxItem('VAT', 50);

$this->beConstructedWith(
'7903c83a-4c5e-4bcf-81d8-9dc304c6a353',
Expand All @@ -26,6 +28,7 @@ function let(ChannelInterface $channel): void
'en_US',
$channel,
[$creditMemoUnit->serialize()],
[$taxItem->serialize()],
'Comment',
new \DateTime('01-01-2020 10:10:10'),
new CustomerBillingData('Rick Sanchez', 'Main St. 3322', '90802', 'US', 'Curse Purge Plus!', 'Los Angeles', 'Baldwin Hills', '323'),
Expand Down Expand Up @@ -58,6 +61,11 @@ function it_has_total(): void
$this->getTotal()->shouldReturn(1000);
}

function it_has_a_subtotal(): void
{
$this->getSubtotal()->shouldReturn(950);
}

function it_has_currency_code(): void
{
$this->getCurrencyCode()->shouldReturn('USD');
Expand All @@ -78,6 +86,11 @@ function it_has_units(): void
$this->getUnits()->shouldBeLike([new CreditMemoUnit('Portal gun', 1000, 50)]);
}

function it_has_tax_items(): void
{
$this->getTaxItems()->shouldBeLike([new TaxItem('VAT', 50)]);
}

function it_has_date_of_creation(): void
{
$this->getIssuedAt()->shouldBeLike(new \DateTime('01-01-2020 10:10:10'));
Expand Down
31 changes: 31 additions & 0 deletions spec/Entity/TaxItemSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace spec\Sylius\RefundPlugin\Entity;

use PhpSpec\ObjectBehavior;
use Sylius\RefundPlugin\Entity\TaxItemInterface;

final class TaxItemSpec extends ObjectBehavior
{
function let(): void
{
$this->beConstructedWith('VAT', 100);
}

function it_implements_tax_item_interface(): void
{
$this->shouldImplement(TaxItemInterface::class);
}

function it_has_a_label(): void
{
$this->getLabel()->shouldReturn('VAT');
}

function it_has_an_amount(): void
{
$this->getAmount()->shouldReturn(100);
}
}
17 changes: 13 additions & 4 deletions spec/Generator/CreditMemoGeneratorSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
use Sylius\RefundPlugin\Entity\CreditMemoUnit;
use Sylius\RefundPlugin\Entity\CustomerBillingData;
use Sylius\RefundPlugin\Entity\ShopBillingData;
use Sylius\RefundPlugin\Entity\TaxItem;
use Sylius\RefundPlugin\Exception\OrderNotFound;
use Sylius\RefundPlugin\Generator\CreditMemoGeneratorInterface;
use Sylius\RefundPlugin\Generator\CreditMemoIdentifierGeneratorInterface;
use Sylius\RefundPlugin\Generator\CreditMemoUnitGeneratorInterface;
use Sylius\RefundPlugin\Generator\NumberGenerator;
use Sylius\RefundPlugin\Generator\TaxItemsGeneratorInterface;
use Sylius\RefundPlugin\Model\OrderItemUnitRefund;
use Sylius\RefundPlugin\Model\ShipmentRefund;
use Sylius\RefundPlugin\Provider\CurrentDateTimeProviderInterface;
Expand All @@ -29,6 +31,7 @@ function let(
OrderRepositoryInterface $orderRepository,
CreditMemoUnitGeneratorInterface $orderItemUnitCreditMemoUnitGenerator,
CreditMemoUnitGeneratorInterface $shipmentCreditMemoUnitGenerator,
TaxItemsGeneratorInterface $taxItemsGenerator,
NumberGenerator $creditMemoNumberGenerator,
CurrentDateTimeProviderInterface $currentDateTimeProvider,
CreditMemoIdentifierGeneratorInterface $creditMemoIdentifierGenerator
Expand All @@ -37,6 +40,7 @@ function let(
$orderRepository,
$orderItemUnitCreditMemoUnitGenerator,
$shipmentCreditMemoUnitGenerator,
$taxItemsGenerator,
$creditMemoNumberGenerator,
$currentDateTimeProvider,
$creditMemoIdentifierGenerator
Expand All @@ -50,15 +54,16 @@ function it_implements_credit_memo_generator_interface(): void

function it_generates_credit_memo_basing_on_event_data(
OrderRepositoryInterface $orderRepository,
CreditMemoUnitGeneratorInterface $orderItemUnitCreditMemoUnitGenerator,
CreditMemoUnitGeneratorInterface $shipmentCreditMemoUnitGenerator,
TaxItemsGeneratorInterface $taxItemsGenerator,
NumberGenerator $creditMemoNumberGenerator,
CurrentDateTimeProviderInterface $currentDateTimeProvider,
CreditMemoIdentifierGeneratorInterface $creditMemoIdentifierGenerator,
OrderInterface $order,
ChannelInterface $channel,
ShopBillingDataInterface $shopBillingData,
AddressInterface $customerBillingAddress,
CreditMemoUnitGeneratorInterface $orderItemUnitCreditMemoUnitGenerator,
CreditMemoUnitGeneratorInterface $shipmentCreditMemoUnitGenerator,
CurrentDateTimeProviderInterface $currentDateTimeProvider,
CreditMemoIdentifierGeneratorInterface $creditMemoIdentifierGenerator,
\DateTime $dateTime
): void {
$firstUnitRefund = new OrderItemUnitRefund(1, 500);
Expand Down Expand Up @@ -102,6 +107,9 @@ function it_generates_credit_memo_basing_on_event_data(
$shipmentCreditMemoUnit = new CreditMemoUnit('Galaxy post', 400, 0);
$shipmentCreditMemoUnitGenerator->generate(3, 400)->willReturn($shipmentCreditMemoUnit);

$taxItem = new TaxItem('VAT', 100);
$taxItemsGenerator->generate([$firstUnitRefund, $secondUnitRefund])->willReturn([$taxItem]);

$creditMemoNumberGenerator->generate()->willReturn('2018/07/00001111');

$currentDateTimeProvider->now()->willReturn($dateTime);
Expand All @@ -121,6 +129,7 @@ function it_generates_credit_memo_basing_on_event_data(
$secondCreditMemoUnit->serialize(),
$shipmentCreditMemoUnit->serialize(),
],
[$taxItem->serialize()],
'Comment',
$dateTime->getWrappedObject(),
new CustomerBillingData('Rick Sanchez', 'Universe St. 444', '000333', 'US', 'Los Angeles', 'Curse Purge Plus!'),
Expand Down
77 changes: 77 additions & 0 deletions spec/Generator/TaxItemsGeneratorSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace spec\Sylius\RefundPlugin\Generator;

use Doctrine\Common\Collections\ArrayCollection;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Model\AdjustmentInterface;
use Sylius\Component\Core\Model\OrderItemUnitInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\RefundPlugin\Entity\TaxItem;
use Sylius\RefundPlugin\Generator\TaxItemsGeneratorInterface;
use Sylius\RefundPlugin\Model\OrderItemUnitRefund;

final class TaxItemsGeneratorSpec extends ObjectBehavior
{
function let(RepositoryInterface $orderItemUnitRepository): void
{
$this->beConstructedWith($orderItemUnitRepository);
}

function it_implements_tax_items_generator_interface(): void
{
$this->shouldImplement(TaxItemsGeneratorInterface::class);
}

function it_generates_tax_items(
RepositoryInterface $orderItemUnitRepository,
OrderItemUnitInterface $firstOrderItemUnit,
OrderItemUnitInterface $secondOrderItemUnit,
AdjustmentInterface $firstAdjustment,
AdjustmentInterface $secondAdjustment
): void {
$firstUnitRefund = new OrderItemUnitRefund(1, 500);
$secondUnitRefund = new OrderItemUnitRefund(3, 200);

$orderItemUnitRepository->find(1)->willReturn($firstOrderItemUnit);
$firstOrderItemUnit->getTotal()->willReturn(500);
$firstOrderItemUnit->getTaxTotal()->willReturn(50);
$firstOrderItemUnit
->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT)
->willReturn(new ArrayCollection([$firstAdjustment->getWrappedObject()]))
;
$firstAdjustment->getLabel()->willReturn('VAT');

$orderItemUnitRepository->find(3)->willReturn($secondOrderItemUnit);
$secondOrderItemUnit->getTotal()->willReturn(200);
$secondOrderItemUnit->getTaxTotal()->willReturn(20);
$secondOrderItemUnit
->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT)
->willReturn(new ArrayCollection([$secondAdjustment->getWrappedObject()]))
;
$secondAdjustment->getLabel()->willReturn('VAT');

$this->generate([$firstUnitRefund, $secondUnitRefund])->shouldBeLike([new TaxItem('VAT', 70)]);
}

function it_generates_tax_items_with_partial_amount(
RepositoryInterface $orderItemUnitRepository,
OrderItemUnitInterface $orderItemUnit,
AdjustmentInterface $adjustment
): void {
$unitRefund = new OrderItemUnitRefund(1, 250);

$orderItemUnitRepository->find(1)->willReturn($orderItemUnit);
$orderItemUnit->getTotal()->willReturn(500);
$orderItemUnit->getTaxTotal()->willReturn(50);
$orderItemUnit
->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT)
->willReturn(new ArrayCollection([$adjustment->getWrappedObject()]))
;
$adjustment->getLabel()->willReturn('VAT');

$this->generate([$unitRefund])->shouldBeLike([new TaxItem('VAT', 25)]);
}
}
27 changes: 27 additions & 0 deletions src/Entity/CreditMemo.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class CreditMemo implements CreditMemoInterface
/** @var array */
protected $units;

/** @var array */
protected $taxItems;

/** @var string */
protected $comment;

Expand All @@ -54,6 +57,7 @@ public function __construct(
string $localeCode,
ChannelInterface $channel,
array $units,
array $taxItems,
string $comment,
\DateTimeInterface $issuedAt,
CustomerBillingDataInterface $from,
Expand All @@ -67,6 +71,7 @@ public function __construct(
$this->localeCode = $localeCode;
$this->channel = $channel;
$this->units = $units;
$this->taxItems = $taxItems;
$this->comment = $comment;
$this->issuedAt = $issuedAt;
$this->from = $from;
Expand Down Expand Up @@ -118,6 +123,16 @@ public function getUnits(): array
return $units;
}

public function getTaxItems(): array
{
$taxItems = [];
foreach ($this->taxItems as $taxItem) {
$taxItems[] = TaxItem::unserialize($taxItem);
}

return $taxItems;
}

public function getComment(): string
{
return $this->comment;
Expand All @@ -137,4 +152,16 @@ public function getTo(): ?ShopBillingDataInterface
{
return $this->to;
}

public function getSubtotal(): int
{
$subtotal = 0;

/** @var CreditMemoUnit $unit */
foreach ($this->getUnits() as $unit) {
$subtotal += $unit->getTotal() - $unit->getTaxesTotal();
}

return $subtotal;
}
}
7 changes: 7 additions & 0 deletions src/Entity/CreditMemoInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ public function getChannel(): ChannelInterface;

public function getUnits(): array;

/**
* @return array<TaxItemInterface>
*/
public function getTaxItems(): array;

public function getComment(): string;

public function getIssuedAt(): \DateTimeInterface;

public function getFrom(): CustomerBillingDataInterface;

public function getTo(): ?ShopBillingDataInterface;

public function getSubtotal(): int;
}
49 changes: 49 additions & 0 deletions src/Entity/TaxItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Sylius\RefundPlugin\Entity;

/** @final */
class TaxItem implements TaxItemInterface
{
/** @var string */
protected $label;

/** @var int */
protected $amount;

public function __construct(string $label, int $amount)
{
$this->label = $label;
$this->amount = $amount;
}

public function getLabel(): string
{
return $this->label;
}

public function getAmount(): int
{
return $this->amount;
}

public function serialize(): string
{
$serialized = json_encode(['label' => $this->label, 'amount' => $this->amount]);

if ($serialized === false) {
throw new \Exception('Tax item cannot be serialized.');
}

return $serialized;
}

public static function unserialize(string $serialized): self
{
$data = json_decode($serialized, true);

return new self($data['label'], $data['amount']);
}
}
14 changes: 14 additions & 0 deletions src/Entity/TaxItemInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Sylius\RefundPlugin\Entity;

interface TaxItemInterface
{
public function getLabel(): string;

public function getAmount(): int;

public function serialize(): string;
}
Loading

0 comments on commit f93fc37

Please sign in to comment.