Skip to content

Commit

Permalink
Added order Collector
Browse files Browse the repository at this point in the history
  • Loading branch information
hiqsol committed May 7, 2020
1 parent d75f5b2 commit e2e89fe
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 22 deletions.
23 changes: 18 additions & 5 deletions src/order/Billing.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,35 +42,48 @@ class Billing implements BillingInterface
* @var BillRepositoryInterface
*/
protected $repository;
/**
* @var CollectorInterface
*/
protected $collector;

public function __construct(
CalculatorInterface $calculator,
AggregatorInterface $aggregator,
MergerInterface $merger,
?BillRepositoryInterface $repository
?BillRepositoryInterface $repository,
?CollectorInterface $collector
) {
$this->calculator = $calculator;
$this->aggregator = $aggregator;
$this->merger = $merger;
$this->repository = $repository;
$this->collector = $collector ?? new Collector();
}

public function calculate(OrderInterface $order): array
public function calculate($source, DateTimeImmutable $time = null): array
{
$charges = $this->calculator->calculateOrder($order);
$charges = $this->calculateCharges($source, $time);
$bills = $this->aggregator->aggregateCharges($charges);

return $this->merger->mergeBills($bills);
}

public function perform(OrderInterface $order): array
public function perform($source, DateTimeImmutable $time = null): array
{
$charges = $this->calculator->calculateOrder($order);
$charges = $this->calculateCharges($source, $time);
$bills = $this->getRepoAggregator()->aggregateCharges($charges);

return $this->saveBills($bills);
}

public function calculateCharges($source, DateTimeImmutable $time = null): array
{
$order = $this->collector->collect($source, $time);

return $this->calculator->calculateOrder($order);
}

private function getRepoAggregator(): AggregatorInterface
{
if ($this->repoAggregator === null) {
Expand Down
14 changes: 10 additions & 4 deletions src/order/BillingInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

namespace hiqdev\php\billing\order;

use hiqdev\php\billing\bill\Bill;
use hiqdev\php\billing\bill\BillInterface;
use hiqdev\php\billing\charge\ChargeInterface;

/**
* Billing calculates and saves bills for given order.
Expand All @@ -20,12 +21,17 @@
interface BillingInterface
{
/**
* @return Bill[]
* @return BillInterface[]
*/
public function calculate(OrderInterface $order): array;
public function calculate($source, DateTimeImmutable $time = null): array;

/**
* @return BillInterface[] array of charges
*/
public function perform(OrderInterface $order): array;
public function perform($source, DateTimeImmutable $time = null): array;

/**
* @return ChargeInterface[]
*/
public function calculateCharges($source, DateTimeImmutable $time = null): array;
}
2 changes: 1 addition & 1 deletion src/order/Calculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public function calculateOrder(OrderInterface $order): array
continue;
}

$charges[$actionKey] = $this->calculatePlan($plans[$actionKey], $action);
$charges = array_merge($charges, $this->calculatePlan($plans[$actionKey], $action));
}

return $charges;
Expand Down
54 changes: 54 additions & 0 deletions src/order/Collector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* PHP Billing Library
*
* @link https://github.com/hiqdev/php-billing
* @package php-billing
* @license BSD-3-Clause
* @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
*/

namespace hiqdev\php\billing\order;

use DateTimeImmutable;
use hiqdev\php\billing\action\ActionInterface;

/**
* Creates order from given source:
* - Order: just passs by. Can be prepared more in other implementations.
* - Action or Action[]: create order from given action(s)
* @author Andrii Vasyliev <sol@hiqdev.com>
*/
class Collector implements CollectorInterface
{
public function collect($source, DateTimeImmutable $time = null): OrderInterface
{
if ($source instanceof OrderInterface) {
return $source;
}
if ($source instanceof ActionInterface) {
return Order::fromAction($source);
}
if (is_array($source)) {
$item = reset($source);
if ($item instanceof OrderInterface) {
return $this->mergeOrders($source);
}
if ($item instanceof ActionInterface) {
return Order::fromActions($source);
}
}

throw new \Exception('unknown order source');
}

protected function mergeOrders(array $orders): OrderInterface
{
$actions = [];
foreach ($orders as $order) {
$actions = array_merge($actions, $order->getActions());
}

return Order::fromActions($actions);
}
}
33 changes: 33 additions & 0 deletions src/order/CollectorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
/**
* PHP Billing Library
*
* @link https://github.com/hiqdev/php-billing
* @package php-billing
* @license BSD-3-Clause
* @copyright Copyright (c) 2017-2018, HiQDev (http://hiqdev.com/)
*/

namespace hiqdev\php\billing\order;

use DateTimeImmutable;

/**
* Order Collector collects order from given source.
* Actual source can be different, see Collector.
* Also, it can be user shopping for example.
*
* ```
* $cart = new Cart();
* /// fill cart
* $bills = $this->billing->calculate($cart)
* ```
* @author Andrii Vasyliev <sol@hiqdev.com>
*/
interface CollectorInterface
{
/**
* @return OrderInterface
*/
public function collect($source, DateTimeImmutable $time = null): OrderInterface;
}
6 changes: 6 additions & 0 deletions src/plan/PlanInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use hiqdev\php\billing\EntityInterface;
use hiqdev\php\billing\price\PriceInterface;
use hiqdev\php\billing\customer\CustomerInterface;

/**
* Plan Interface.
Expand All @@ -35,4 +36,9 @@ public function getUniqueId();
* @return PriceInterface[]
*/
public function getPrices(): ?array;

/**
* @return CustomerInterface
*/
public function getSeller(): ?CustomerInterface;
}
25 changes: 15 additions & 10 deletions tests/behat/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
use hiqdev\php\billing\action\Action;
use hiqdev\php\billing\charge\Charge;
use hiqdev\php\billing\charge\ChargeInterface;
use hiqdev\php\billing\charge\Generalizer;
use hiqdev\php\billing\customer\Customer;
use hiqdev\php\billing\formula\FormulaEngine;
use hiqdev\php\billing\order\Calculator;
use hiqdev\php\billing\plan\Plan;
use hiqdev\php\billing\price\SinglePrice;
use hiqdev\php\billing\target\Target;
use hiqdev\php\billing\tests\support\order\SimpleBilling;
use hiqdev\php\billing\type\Type;
use hiqdev\php\units\Quantity;
use Money\Currencies\ISOCurrencies;
Expand Down Expand Up @@ -63,10 +63,6 @@ class FeatureContext implements Context

/** @var string */
protected $expectedError;
/** @var Generalizer */
protected $generalizer;
/** @var Calculator */
protected $calculator;

/**
* Initializes context.
Expand All @@ -75,8 +71,8 @@ public function __construct()
{
$this->customer = new Customer(null, 'somebody');
$this->moneyParser = new DecimalMoneyParser(new ISOCurrencies());
$this->generalizer = new Generalizer();
$this->calculator = new Calculator($this->generalizer, null, null);
$this->plan = new Plan(null, 'plan', $this->customer);
$this->billing = SimpleBilling::fromPlan($this->plan);
}

/**
Expand All @@ -88,7 +84,16 @@ public function priceIs($target, $type, $sum, $currency, $unit, $quantity = 0)
$target = new Target(Target::ANY, $target);
$quantity = Quantity::create($unit, $quantity);
$sum = $this->moneyParser->parse($sum, $currency);
$this->price = new SinglePrice(null, $type, $target, null, $quantity, $sum);
$this->setPrice(new SinglePrice(null, $type, $target, null, $quantity, $sum));
}

private function setPrice($price)
{
$this->price = $price;
$ref = new \ReflectionClass($this->plan);
$prop = $ref->getProperty('prices');
$prop->setAccessible(true);
$prop->setValue($this->plan, [$price]);
}

/**
Expand Down Expand Up @@ -199,7 +204,7 @@ public function calculatePrice(): void
{
$this->expectError(function () {
$this->price->setModifier($this->getFormulaEngine()->build($this->formula));
$this->charges = $this->calculator->calculatePrice($this->price, $this->action);
$this->charges = $this->billing->calculateCharges($this->action);
});
}

Expand Down
19 changes: 18 additions & 1 deletion tests/support/order/SimpleBilling.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@
namespace hiqdev\php\billing\tests\support\order;

use hiqdev\php\billing\bill\BillRepositoryInterface;
use hiqdev\php\billing\customer\CustomerInterface;
use hiqdev\php\billing\order\Billing;
use hiqdev\php\billing\order\CalculatorInterface;
use hiqdev\php\billing\plan\PlanInterface;
use hiqdev\php\billing\sale\SaleInterface;
use hiqdev\php\billing\target\Target;
use hiqdev\php\billing\tests\support\bill\SimpleBillRepository;
use hiqdev\php\billing\tools\Aggregator;
use hiqdev\php\billing\tools\AggregatorInterface;
use hiqdev\php\billing\tools\Merger;
use hiqdev\php\billing\tools\MergerInterface;
use hiqdev\php\billing\sale\Sale;

class SimpleBilling extends Billing
{
Expand All @@ -32,11 +37,23 @@ public function __construct(
$merger = $merger ?: new Merger();
$repository = $repository ?: new SimpleBillRepository();

parent::__construct($calculator, $aggregator, $merger, $repository);
parent::__construct($calculator, $aggregator, $merger, $repository, null);
}

public function getBillRepository(): BillRepositoryInterface
{
return $this->repository;
}

public static function fromPlan(PlanInterface $plan, CustomerInterface $customer = null)
{
$customer ??= $plan->getSeller();
$sale = new Sale(null, Target::any(), $customer, $plan);
return self::fromSale($sale);
}

public static function fromSale(SaleInterface $sale)
{
return new self(new SimpleCalculator(null, $sale));
}
}
2 changes: 1 addition & 1 deletion tests/unit/order/CalculatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function testCalculateCharges()
{
$charges = $this->calculator->calculateOrder($this->order);
foreach ($this->order->getActions() as $actionKey => $action) {
$this->checkCharges($action, $charges[$actionKey]);
$this->checkCharges($action, [$charges[$actionKey]]);
}
}
}

0 comments on commit e2e89fe

Please sign in to comment.