Skip to content
This repository was archived by the owner on Feb 2, 2022. It is now read-only.

Respect custom morph types #190

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Coupon/RedeemedCoupon.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public static function record(Coupon $coupon, AcceptsCoupons $model)
return $model->redeemedCoupons()->create([
'name' => $coupon->name(),
'times_left' => $coupon->times(),
'owner_type' => $model->ownerType(),
'owner_id' => $model->ownerId(),
'owner_type' => $model->owner_type,
'owner_id' => $model->owner_id,
]);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Credit/Credit.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static function addAmountForOwner(Model $owner, Money $amount)
// if the owner has no credit yet
return static::create([
'owner_id' => $owner->id,
'owner_type' => get_class($owner),
'owner_type' => $owner->getMorphClass(),
'currency' => $amount->getCurrency()->getCode(),
'value' => (int) $amount->getAmount(),
]);
Expand Down
2 changes: 1 addition & 1 deletion src/FirstPayment/Actions/StartSubscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public function makeProcessedOrderItems()
protected function processedOrderItemData()
{
return [
'owner_type' => get_class($this->owner),
'owner_type' => $this->owner->getMorphClass(),
'owner_id' => $this->owner->id,
'process_at' => now(),
'description' => $this->getDescription(),
Expand Down
2 changes: 1 addition & 1 deletion src/FirstPayment/FirstPaymentBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public function getMolliePayload()
'redirectUrl' => $this->redirectUrl,
'metadata' => [
'owner' => [
'type' => get_class($this->owner),
'type' => $this->owner->getMorphClass(),
'id' => $this->owner->id,
],
'actions' => $this->actions->toMolliePayload(),
Expand Down
2 changes: 1 addition & 1 deletion src/Order/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static function createFromItems(OrderItemCollection $items, $overrides =

$order = static::create(array_merge([
'owner_id' => $owner->id,
'owner_type' => get_class($owner),
'owner_type' => $owner->getMorphClass(),
'number' => static::numberGenerator()->generate(),
'currency' => $currency,
'subtotal' => $items->sum('subtotal'),
Expand Down
6 changes: 3 additions & 3 deletions src/Order/OrderItemCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function whereOwner($owner)
{
return $this->filter(function ($item) use ($owner) {
return (string) $item->owner_id === (string) $owner->id
&& $item->owner_type === get_class($owner);
&& $item->owner_type === $owner->getMorphClass();
});
}

Expand All @@ -53,9 +53,9 @@ public function whereOwner($owner)
public function chunkByOwner()
{
return $this->owners()->sortBy(function ($owner) {
return get_class($owner) . '_' . $owner->id;
return $owner->getMorphClass() . '_' . $owner->id;
})->mapWithKeys(function ($owner) {
$key = get_class($owner) . '_' . $owner->id;
$key = $owner->getMorphClass() . '_' . $owner->id;
return [$key => $this->whereOwner($owner)];
});
}
Expand Down
6 changes: 4 additions & 2 deletions src/Traits/HasOwner.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Laravel\Cashier\Traits;

use Illuminate\Database\Eloquent\Model;

trait HasOwner
{
/**
Expand All @@ -18,14 +20,14 @@ public function owner()
* Scope a query to only records for a specific owner.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param mixed $owner
* @param Model $owner
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeWhereOwner($query, $owner)
{
return $query
->where('owner_id', $owner->id)
->where('owner_type', get_class($owner));
->where('owner_type', $owner->getMorphClass());
}
}
20 changes: 20 additions & 0 deletions tests/Credit/CreditTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Laravel\Cashier\Tests\Credit;

use Illuminate\Database\Eloquent\Relations\Relation;
use Laravel\Cashier\Credit\Credit;
use Laravel\Cashier\Tests\BaseTestCase;
use Laravel\Cashier\Tests\Fixtures\User;
Expand Down Expand Up @@ -48,4 +49,23 @@ public function testMaxOutForOwner()
$this->assertTrue(Money::EUR(510)->equals($usedEUR));
$this->assertEquals(11836, Credit::whereOwner($user)->whereCurrency('EUR')->first()->value);
}

public function testOwnerTypeIsSetOnCreditMorphColumn()
{
$this->withPackageMigrations();

$userMorphType = 'user';

Relation::morphMap([
$userMorphType => User::class,
]);

$user = factory(User::class)->create();

Credit::addAmountForOwner($user, Money::USD(12348));

$credit = Credit::first();

$this->assertEquals($userMorphType, $credit->owner_type);
}
}
2 changes: 1 addition & 1 deletion tests/FirstPayment/FirstPaymentBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function canBuildPayload()
'webhookUrl' => 'https://www.example.com/mandate-webhook',
'metadata' => [
'owner' => [
'type' => get_class($owner),
'type' => $owner->getMorphClass(),
'id' => $owner->id,
],
'actions' => [
Expand Down
4 changes: 2 additions & 2 deletions tests/ManageSubscriptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function canCreateDirectDebitSubscriptionForMandatedCustomer()
$this->assertTrue($scheduled_order_item->is($user->subscription('main')->orderItems()->first()));
$this->assertEquals('EUR', $scheduled_order_item->currency);
$this->assertEquals($user->id, $scheduled_order_item->owner_id);
$this->assertEquals(get_class($user), $scheduled_order_item->owner_type);
$this->assertEquals($user->getMorphClass(), $scheduled_order_item->owner_type);
$this->assertCarbon(now(), $scheduled_order_item->process_at, 5);
$this->assertEquals(1, $scheduled_order_item->quantity);
$this->assertEquals(1000, $scheduled_order_item->unit_price);
Expand Down Expand Up @@ -111,7 +111,7 @@ public function canCreateDirectDebitSubscriptionForMandatedCustomer()
$scheduled_order_item = $subscription->scheduled_order_item;
$this->assertEquals('EUR', $scheduled_order_item->currency);
$this->assertEquals($user->id, $scheduled_order_item->owner_id);
$this->assertEquals(get_class($user), $scheduled_order_item->owner_type);
$this->assertEquals($user->getMorphClass(), $scheduled_order_item->owner_type);
$this->assertCarbon(now()->addMonth(), $scheduled_order_item->process_at);
$this->assertEquals(1000, $scheduled_order_item->unit_price);
$this->assertEquals(10, $scheduled_order_item->tax_percentage);
Expand Down
23 changes: 23 additions & 0 deletions tests/Order/OrderItemTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

namespace Laravel\Cashier\Tests\Order;

use Illuminate\Database\Eloquent\Relations\Relation;
use Laravel\Cashier\Order\OrderItem;
use Laravel\Cashier\Order\OrderItemCollection;
use Laravel\Cashier\Subscription;
use Laravel\Cashier\Tests\BaseTestCase;
use Laravel\Cashier\Tests\Fixtures\User;

class OrderItemTest extends BaseTestCase
{
Expand Down Expand Up @@ -79,6 +82,26 @@ public function testScopeProcessed()
$this->assertEquals(3, OrderItem::processed(false)->count());
}

public function testOrderItemTableHasCorrectOrderableType()
{
$newUserMorphKey = 'user';
$newSubscriptionMorphKey = 'subscription';

Relation::morphMap([
$newUserMorphKey => User::class,
$newSubscriptionMorphKey => Subscription::class,
]);

$this->withPackageMigrations();

$orderItem = factory(OrderItem::class)->create();

$this->assertEquals($newUserMorphKey, (new User())->getMorphClass());
$this->assertEquals($newSubscriptionMorphKey, (new Subscription())->getMorphClass());
$this->assertEquals((new User())->getMorphClass(), $orderItem->owner_type);
$this->assertEquals((new Subscription())->getMorphClass(), $orderItem->orderable_type);
}

public function testScopeUnprocessed()
{
$this->withPackageMigrations();
Expand Down
38 changes: 34 additions & 4 deletions tests/Order/OrderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Laravel\Cashier\Tests\Order;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\Event;
use Laravel\Cashier\Order\Contracts\MinimumPayment;
use Laravel\Cashier\Events\BalanceTurnedStale;
Expand Down Expand Up @@ -39,7 +41,7 @@ public function canCreateFromOrderItems()
factory(OrderItem::class, 2)->make([
'process_at' => now()->subMinute(), // sub minute so we're sure it's ready to be processed
'owner_id' => $user->id,
'owner_type' => get_class($user),
'owner_type' => $user->getMorphClass(),
'currency' => 'EUR',
'quantity' => 1,
'unit_price' => 12345, // includes vat
Expand Down Expand Up @@ -75,13 +77,41 @@ public function canCreateFromOrderItems()
$this->assertEquals('open', $order->mollie_payment_status);
}

/** @test */
public function canCreateFromOrderItemsWithCustomPolymorphicRelation()
{
Relation::morphMap([
'user' => User::class, // Model with Billable trait
'order' => Order::class,
]);

$user = $this->getMandatedUser(true, ['id' => 2]);
$subscription = $this->createMonthlySubscription();

$subscription->orderItems()->saveMany(
factory(OrderItem::class, 2)->make([
'process_at' => now()->subMinute(), // sub minute so we're sure it's ready to be processed
'owner_id' => $user->id,
'owner_type' => $user->getMorphClass(),
'currency' => 'EUR',
'quantity' => 1,
'unit_price' => 12345, // includes vat
'tax_percentage' => 21.5,
])
);

$order = Order::createFromItems(OrderItem::all());

$this->assertEquals((new User())->getMorphClass(), $order->owner_type);
}

/** @test */
public function creatingANewOrderSchedulesNextOrderItems()
{
$user = factory(User::class)->create(['id' => 2]);
$subscription = factory(Subscription::class)->create([
'owner_id' => $user->id,
'owner_type' => get_class($user),
'owner_type' => $user->getMorphClass(),
'plan' => 'monthly-10-1',
'cycle_ends_at' => now(),
]);
Expand Down Expand Up @@ -133,7 +163,7 @@ public function handlesOwnerBalance()

$subscription = factory(Subscription::class)->create([
'owner_id' => $user->id,
'owner_type' => get_class($user),
'owner_type' => $user->getMorphClass(),
'plan' => 'monthly-10-1',
'cycle_ends_at' => now(),
]);
Expand Down Expand Up @@ -397,7 +427,7 @@ public function canCreateOrderFromOrderItemsWhenTotalValueIsNegativeAndOwnerHasN
'orderable_id' => null,
'process_at' => now()->subMinute(), // sub minute so we're sure it's ready to be processed
'owner_id' => $user->id,
'owner_type' => get_class($user),
'owner_type' => $user->getMorphClass(),
'currency' => 'EUR',
'quantity' => 1,
'unit_price' => -12345, // includes vat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function createsMandatePaymentForSubscription()
"locale" => "nl_NL",
"metadata" => [
"owner" => [
"type" => get_class($this->user),
"type" => $this->user->getMorphClass(),
"id" => 1,
],
"actions" => [
Expand Down
2 changes: 1 addition & 1 deletion tests/database/factories/OrderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
$factory->define(Order::class, function (Faker $faker) {
return [
'owner_id' => 1,
'owner_type' => User::class,
'owner_type' => (new User())->getMorphClass(),
'currency' => 'EUR',
'subtotal' => 123,
'tax' => 0,
Expand Down
4 changes: 2 additions & 2 deletions tests/database/factories/OrderItemFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

$factory->define(OrderItem::class, function (Faker $faker) {
return [
'owner_type' => User::class,
'owner_type' => (new User())->getMorphClass(),
'owner_id' => 1,
'orderable_type' => Subscription::class,
'orderable_type' => (new Subscription())->getMorphClass(),
'orderable_id' => 1,
'description' => 'Some dummy description',
'unit_price' => 12150,
Expand Down
5 changes: 3 additions & 2 deletions tests/database/factories/RedeemedCouponFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
use Laravel\Cashier\Tests\Fixtures\User;

$factory->define(RedeemedCoupon::class, function (Faker $faker) {
$user = new User();
return [
'name' => 'Test redemeed coupon',
'model_type' => Subscription::class,
'model_type' => (new Subscription())->getMorphClass(),
'model_id' => 1,
'owner_type' => User::class,
'owner_type' => (new User())->getMorphClass(),
'owner_id' => 1,
'times_left' => 1,
];
Expand Down
2 changes: 1 addition & 1 deletion tests/database/factories/SubscriptionFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
'name' => 'dummy name',
'plan' => 'monthly-10-1',
'owner_id' => 1,
'owner_type' => User::class,
'owner_type' => (new User())->getMorphClass(),
'cycle_started_at' => now(),
'cycle_ends_at' => function (array $subscription) {
return Carbon::parse($subscription['cycle_started_at'])->addMonth();
Expand Down