Skip to content

Commit

Permalink
Initialization of a billing agreement has been moved from the manager…
Browse files Browse the repository at this point in the history
… to a handler
  • Loading branch information
inspiran committed Mar 10, 2013
1 parent 74ff9d8 commit c66b8e0
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 323 deletions.
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -2,13 +2,13 @@
"name": "vespolina/billing",
"type": "library",
"description": "Vespolina Billing.",
"keywords": ["vespolina", "billing", "ecommerce"],
"keywords": ["vespolina", "billing", "ecommerce", "recurring", "plans"],
"homepage": "http://vespolina-project.org",
"license": "MIT",
"authors": [
{
"name": "Vespolina Team",
"homepage": "https://github.com/vespolina/VespolinaPartner/contributors"
"homepage": "https://github.com/vespolina/VespolinaBilling"
}
],
"require": {
Expand Down
11 changes: 11 additions & 0 deletions lib/Vespolina/Billing/Handler/EntityHandlerInterface.php
Expand Up @@ -27,6 +27,17 @@ interface EntityHandlerInterface
*/
function createBillingAgreements($entity);

/**
* Init is called after a billing agreement has been created
* It copies relevant fields from the entity to the billing agreement
*
* @param $billingAgreement The billing agreement to be initialized
* @param $entity The main entity (eg. Order)
* @param $entityItem The item of the entity (eg. OrderItem)
* @return mixed
*/
function initBillingAgreement(BillingAgreementInterface $billingAgreement, $entity, $entityItem = null);

/**
* Cancel the billing process for this entity
*
Expand Down
92 changes: 89 additions & 3 deletions lib/Vespolina/Billing/Handler/OrderHandler.php
Expand Up @@ -12,6 +12,7 @@
use Vespolina\Entity\Billing\BillingRequestInterface;
use Vespolina\Billing\Handler\EntityHandlerInterface;
use Vespolina\Entity\Order\OrderInterface;
use Vespolina\Entity\Order\ItemInterface;

class OrderHandler implements EntityHandlerInterface
{
Expand All @@ -25,24 +26,109 @@ public function __construct(BillingManagerInterface $billingManager)

public function createBillingAgreements($entity)
{
$billingAgreements = array();
$recurringItems = array(); //Initial set of detected recurring items
$recurringItemsMerged = array(); //Final set of recurring items after merge

if (!$this->isBillable($entity)) {
throw new \ErrorException('Entity is not billable');
}

//Collect items for which a recurring charge exists
/** @var Item $item **/
foreach ($entity->getItems() as $item) {
$pricingSet = $item->getPricing();
$pricingSet->getProcessed();

if ($pricingSet->get('recurringCharge')) {

$recurringItems = $item;
}
}

//Todo: merge items together
$recurringItems = $recurringItems;

foreach ($recurringItems as $recurringItem) {

// Check if we can attach this item to one of the existing billing agreements.
// If no suitable agreement can be found a new one is created
// If a suitable agreement is found the order item is attached to it
$this->createOrUpdateBusinessAgreements($billingAgreements, $recurringItem);
}
}

public function cancelBilling($entity)
{

}

public function initBillingAgreement(BillingAgreementInterface $billingAgreement, $entity, $entityItem = null)
{
/** @var PartnerInterface $owner **/
$owner = $entity->getOwner();

$paymentProfile = $owner->getPreferredPaymentProfile();

$billingAgreement
->setPartner($owner)
->setPaymentProfile($owner->getPaymentProfile())
;
}

public function isBillable($entity)
{
//Currenlty we only check if the entity is valid but we should additional business logic here
// (eg. if the order is cancelled it should not eligable for billing)
if (!$this->isBillableEntity($entity)) return false;

if (null == $entity->getOwner()) return false;

return true;
}

protected function createOrUpdateBusinessAgreements(array &$agreements, ItemInterface $item, $context = null)
{
$pricingSet = $item->getPricing();
$interval = $pricingSet->get('interval');
$cycles = $pricingSet->get('cycles');

if ($item->getAttribute('start_billing')) {
$startsOn = $item->getAttribute('start_billing');
} elseif ($context['dueDate']) {
$startsOn = $pricingSet->get('startsOn');
$date = explode(',', $startsOn->format('Y,m'));
$startsOn->setDate($date[0], $date[1], $context['dueDate']);
} else {
$startsOn = $pricingSet->get('startsOn');
}
$startTimestamp = $startsOn->getTimestamp();

//Find a suitable billing agreement
$activeAgreement = null;
foreach ($agreements as $agreement) {
if ($agreement->getBillingInterval() == $interval &&
$agreement->getBillingCycles() == $cycles &&
$agreement->getInitialBillingDate()->getTimestamp() == $startTimestamp) {
$activeAgreement = $agreement;
}
}

if (null == $activeAgreement) {
$activeAgreement = $this->billingManager->createBillingAgreement();
$this->initBillingAgreement($item->getParent(), $item);
$activeAgreement
->setInitialBillingDate($startsOn)
->setNextBillingDate($startsOn)
->setBillingCycles($pricingSet->get('cycles'))
->setBillingInterval($pricingSet->get('interval'));
;
$agreements[] = $activeAgreement;
}

$activeAgreement->addOrderItem($item);
$activePricingSet = $activeAgreement->getPricing();
$activeAgreement->setPricing($pricingSet->plus($activePricingSet));

return $this->isBillableEntity($entity);
return $activeAgreement;
}

protected function isBillableEntity($entity)
Expand Down
28 changes: 3 additions & 25 deletions lib/Vespolina/Billing/Manager/BillingManager.php
Expand Up @@ -91,6 +91,7 @@ public function findBillingAgreementById($id)
*/
public function billEntity($entity)
{
$billingAgreements = array();
$entityHandler = $this->getEntityHandler($entity);

if (null == $entityHandler)
Expand All @@ -111,8 +112,7 @@ public function billEntity($entity)
$this->gateway->updateBillingAgreement($billingAgreement);
}


return true;
return $billingAgreements;
}

/**
Expand All @@ -129,21 +129,6 @@ public function createBillingAgreement()

return new $this->billingAgreementClass();
}
/**
* @inheritdoc
*/
public function createBillingAgreements(OrderInterface $order)
{
$owner = $order->getOwner();
$paymentProfile = $owner->getPreferredPaymentProfile();

$paymentProfileType = $paymentProfile->getType();
$context = $this->context['billingAgreement'][$paymentProfileType];

$billingAgreements = $this->prepBillingAgreements($context, $owner, $paymentProfile, $order->getItems());

return $billingAgreements;
}

/**
* Rebuilds the billing agreement if there are any adjustments to the old agreement
Expand Down Expand Up @@ -178,17 +163,10 @@ public function recreateBillingAgreementByPartnerAndPaymentProfile(Partner $part
}

/**
* @param $context
* @param \Vespolina\Entity\Partner\Partner $partner
* @param \Vespolina\Entity\Partner\PaymentProfile $paymentProfile
* @param $orderItems
* @return array
*/
private function prepBillingAgreements($context, Partner $partner, PaymentProfile $paymentProfile, $orderItems)
{
$billingAgreements = array();
/** @var Item $item **/
foreach ($orderItems as $item) {
$pricingSet = $item->getPricing();
Expand Down Expand Up @@ -252,7 +230,7 @@ protected function addItemToAgreements(ItemInterface $item, array &$agreements,
$this->gateway->persistBillingAgreement($activeAgreement);
return $activeAgreement;
}
} */

public function processPendingBillingRequests()
{
Expand Down
6 changes: 0 additions & 6 deletions lib/Vespolina/Billing/Manager/BillingManagerInterface.php
Expand Up @@ -35,12 +35,6 @@ function billEntity($entity);
*/
function createBillingAgreement();

/**
* @param \Vespolina\Entity\Order\OrderInterface $order
* @return array
*/
function createBillingAgreements(OrderInterface $order);

/**
* Create a new billing request
*
Expand Down
14 changes: 14 additions & 0 deletions phpunit.xml
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="tests/bootstrap.php" color="true">
<testsuites>
<testsuite name="Vespolina Billing">
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">./lib</directory>
</whitelist>
</filter>
</phpunit>
13 changes: 0 additions & 13 deletions phpunit.xml.dist

This file was deleted.

51 changes: 23 additions & 28 deletions tests/Manager/BillingManagerTest.php
Expand Up @@ -7,21 +7,16 @@

use Vespolina\Billing\Manager\BillingManager;
use Vespolina\Billing\Gateway\BillingGateway;
use Vespolina\Entity\Order\OrderEvents;
use Vespolina\Entity\Order\Order;
use Vespolina\Entity\Partner\PaymentProfileType\Invoice;
use Vespolina\Entity\Billing\BillingAgreementInterface;
use Vespolina\EventDispatcher\EventDispatcherInterface;
use Vespolina\EventDispatcher\EventInterface;
use Vespolina\Pricing\Entity\Element\RecurringElement;
use Vespolina\Pricing\Entity\PricingSet;

use Vespolina\Billing\Tests\Manager\TestDispatcher;
use Vespolina\Billing\Tests\Manager\TestBaseManager;

/**
* @group ecommerce
*/
class BillingManagerTest extends TestBaseManager
class BillingManagerTest extends \PHPUnit_Framework_TestCase
{
protected $billingGateway;

Expand All @@ -30,18 +25,13 @@ public function testConstruct()
$this->markTestIncomplete('tests are need to make sure the contexts are set up correctly');
}

public function test()
public function testCreateBillingAgreement()
{
$this->markTestIncomplete('the various pieces need to be tested with the events tha are triggered');
// track states in processing

/** current needs */
// get order
// create current bill
// create recurring bill
// get CC
// submit current bill to CC
// create licenses when CC is approved
$billingManager = $this->createBillingManager();

$billingAgreement = $billingManager->createBillingAgreement();

$this->assertTrue($billingAgreement instanceof BillingAgreementInterface);
}

public function testCreateBillingAgreements()
Expand Down Expand Up @@ -131,12 +121,9 @@ public function testGenerateRequestFromAgreement()

protected function createTestOrder()
{
$licenses = $this->getTestObjectsProvider()->loadLicenseProductDataFixtures();
$upgrade = $this->getTestObjectsProvider()->loadUpgradeProductDataFixture();
$user = $this->getTestObjectsProvider()->createRandomUser();

$order = $this->getOrderManager()->createOrder();
$order->setPartner($user->getPartner());
//$order->setOwner($user->getPartner());

$this->getOrderManager()->addProductToOrder($order, $licenses[License::PRODUCT_LICENSE_NAME], array(), 1, false);
$this->getOrderManager()->addProductToOrder($order, $licenses[License::PRODUCT_LICENSE_NAME], array(), 1, false);
Expand All @@ -152,18 +139,26 @@ protected function createTestOrder()

protected function createBillingManager()
{
$this->billingGateway = new BillingGateway($this->getMolino(), 'Vespolina\Entity\Billing\BillingAgreement');
//$this->billingGateway = new BillingGateway($this->getMolino(), 'Vespolina\Entity\Billing\BillingAgreement');

$billingGateway = $this->getMockBuilder('Vespolina\Billing\Gateway\BillingGateway')
->disableOriginalConstructor()
->getMock()
;

$eventDispatcher = new TestDispatcher();
$classMapping = array(
'billingAgreementClass' => 'Vespolina\Entity\Billing\BillingAgreement',
'billingRequestClass' => 'Vespolina\Entity\Billing\BillingRequest',
);
$contexts = array(
'ImmersiveLabs\CaraCore\Context\InvoiceAgreementContext',
'ImmersiveLabs\CaraCore\Context\InvoiceRequestContext',
);
$manager = new BillingManager($this->billingGateway, $classMapping, $contexts, $eventDispatcher);
$contexts = array();
$manager = new BillingManager($billingGateway, $classMapping, $contexts, $eventDispatcher);

return $manager;
}

protected function getMolino()
{

}
}

0 comments on commit c66b8e0

Please sign in to comment.