kna/accounting-bundle

This Bundle provides event-driven accounting implementation

dev-master 2019-09-17 11:48 UTC

This package is auto-updated.

Last update: 2024-04-17 21:45:55 UTC


README

This Bundle provides event-driven accounting implementation.

Installation

composer require kna/accounting-bundle

Configuring

Add config

// config/packages/kna_accounting.yaml

kna_accounting:
  account:
    class: App\Entity\Account # default
  entry:
    class: App\Entity\Entry # default
  event:
    class: App\Entity\Event # default
    discriminator_type: string #default
    discriminator_name: type #default
    discriminator_length: 255 #default
    discriminator_map:
      payment: App\Entity\PaymentEvent
      sale: App\Entity\SaleEvent

Create base entities

Account:

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Kna\AccountingBundle\Entity\BaseAccount;

class Account extends BaseAccount
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
}

Entry:

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Kna\AccountingBundle\Entity\BaseEntry;

class Base extends BaseEntry
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
}

Event:

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Kna\AccountingBundle\Entity\BaseEvent;

abstract class Event extends BaseEvent
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
}

Create events

For example:

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

class PaymentEvent extends Event
{
    /**
     * @ORM\ManyToOne(targetEntity="Account")
     */
    protected $account;
}

and

<?php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

class SaleEvent extends Event
{
    /**
     * @ORM\ManyToOne(targetEntity="Order")
     */
    protected $order;
}

Create event provider

<?php
namespace App\Accounting;

use App\Entity\Payment;
use App\Entity\Order;
use App\Entity\PaymentEvent;
use App\Entity\SaleEvent;
use Money\Currency;
use Money\Money;
use Kna\AccountingBundle\Accounting\BaseEventProvider;

class DefaultEventProvider extends BaseEventProvider
{
    /**
     * {@inheritDoc}
     */
    public function supports($source): bool
    {
        return 
            $source instanceof Payment ||
            $source instanceof Order
        ;
    }

    /**
     * {@inheritDoc}
     */
    public function createEvents($source): \Generator
    {
        if ($source instanceof Payment) {
            $event = new PaymentEvent();
            $event->setAmount(new Money($source->getAmount(), new Currency($source->getCurrency())));
            $event->setAccount($source->getAccount());
            $event->setOccurredAt(new \DateTime());
            $event->setNoticedAt(new \DateTime());
            yield $event;
        } elseif ($source instanceof Order) {
            $event = new SaleEvent();
            $event->setAmount(new Money($source->getAmount(), new Currency($source->getCurrency())));
            $event->setOrder($source);
            $event->setOccurredAt(new \DateTime());
            $event->setNoticedAt(new \DateTime());
            yield $event;
        }
    }
}

Create entry provider

<?php
namespace App\Accounting;

use App\Entity\PaymentEvent;
use App\Entity\SaleEvent;
use Kna\AccountingBundle\Model\EventInterface;
use Kna\AccountingBundle\Accounting\BaseEventProvider;

class DefaultEntryProvider extends BaseEntryProvider
{
    /**
     * {@inheritDoc}
     */
    public function supports($source): bool
    {
        return 
            $source instanceof PaymentEvent ||
            $source instanceof SaleEvent
        ;
    }

    /**
     * {@inheritDoc}
     */
    public function createEntries(EventInterface $event): \Generator
    {
        if ($event instanceof PaymentEvent) {
            $entry = $this->createEntry();
            $entry->setAccount($event->getAccount());
            $entry->setAmount($event->getAmount());
            $entry->setDescription($this->translator->trans('event.payment.description', ['%event%' => (string) $event]));

            yield $entry;
        } elseif ($event instanceof SaleEvent) {
            $entry = $this->createEntry();
            $entry->setAccount($event->getOrder()->getAccount());
            $entry->setAmount($event->getAmount()->negative());
            $entry->setDescription($this->translator->trans('event.sale.description', ['%event%' => (string) $event, '%order%' => $event->getOrder()->getId()]));

            yield $entry;
        }
    }
}

Usage

Use event manager

<?php
namespace App\Controller;

use App\Entity\Order;
use Kna\AccountingBundle\Accounting\EventManager;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class DefaultController extends AbstractController
{
    /**
    * @var EventManager
    */
    protected $eventManager;
    
    public function __construct(EventManager $eventManager) {
        $this->eventManager = $eventManager;
    }
    
    public function index(): Response
    {
        $order = new Order();
        $this->eventManager->processSource($order);
    }

}

Use event processing command

php bin/console kna_accounting:process-events --loop