Skip to content

Commit

Permalink
Code refactor and add tests
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Poyigi <6567634+sampoyigi@users.noreply.github.com>
  • Loading branch information
sampoyigi committed Jun 3, 2024
1 parent 63b024e commit f138702
Show file tree
Hide file tree
Showing 16 changed files with 734 additions and 78 deletions.
1 change: 1 addition & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_KEY" value="base64:YzE5YjR2b3hrem1ucmdmc2Fkbm92NW1veHBkMWdpa3k="/>
<env name="DB_DATABASE" value="testbench"/>
</php>
<source>
<include>
Expand Down
20 changes: 6 additions & 14 deletions src/Actions/RedeemsCoupon.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

namespace Igniter\Coupons\Actions;

use Igniter\Cart\CartCondition;
use Igniter\Cart\Models\Order;
use Igniter\Coupons\Models\Coupon;
use Igniter\Coupons\Models\CouponHistory;
use Igniter\Flame\Traits\ExtensionTrait;
use Igniter\System\Actions\ModelAction;
Expand All @@ -27,27 +27,19 @@ public function redeemCoupon()
/**
* Add cart coupon to order by order_id
*
* @param \Igniter\Cart\Models\Order $order
* @param \Igniter\Cart\CartCondition $couponCondition
* @param \Igniter\User\Models\Customer $customer
* @param float $couponValue
* @param \Igniter\Coupons\Models\Coupon $coupon
*
* @return int|bool
* @return bool
*/
public function logCouponHistory($couponCondition)
public function logCouponHistory($couponValue, Coupon $coupon)
{
if (!$couponCondition instanceof CartCondition) {
throw new \InvalidArgumentException(sprintf(
'Invalid argument, expected %s, got %s',
CartCondition::class, get_class($couponCondition)
));
}

// Make sure order model exists
if (!$this->model->exists) {
return false;
}

/** @var Order $this */
return CouponHistory::createHistory($couponCondition, $this->model);
return CouponHistory::createHistory($coupon, $couponValue, $this->model);
}
}
7 changes: 7 additions & 0 deletions src/CartConditions/Coupon.php
Original file line number Diff line number Diff line change
Expand Up @@ -233,4 +233,11 @@ public static function isApplicableTo($cartItem)

return $applicableItems->contains($cartItem->id);
}

public function __destruct()
{
self::$couponModel = null;
self::$applicableItems = null;
self::$hasErrors = false;
}
}
8 changes: 5 additions & 3 deletions src/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Igniter\Cart\Classes\CartManager;
use Igniter\Cart\Facades\Cart;
use Igniter\Cart\Models\Order;
use Igniter\Coupons\Actions\RedeemsCoupon;
use Igniter\Coupons\Models\Coupon;
use Igniter\Coupons\Models\CouponHistory;
use Igniter\Coupons\Models\Scopes\CouponScope;
Expand All @@ -24,7 +25,7 @@ public function boot()
{
Order::extend(function($model) {
$model->relation['hasMany']['coupon_history'] = [\Igniter\Coupons\Models\CouponHistory::class, 'delete' => true];
$model->implement[] = 'Igniter.Coupons.Actions.RedeemsCoupon';
$model->implement[] = RedeemsCoupon::class;
});

Event::listen('cart.added', function() {
Expand All @@ -51,8 +52,9 @@ public function boot()
});

Event::listen('igniter.checkout.afterSaveOrder', function($order) {
if ($couponCondition = Cart::conditions()->get('coupon')) {
$order->logCouponHistory($couponCondition);
$couponCondition = Cart::conditions()->get('coupon');
if ($couponCondition && $coupon = $couponCondition->getModel()) {
$order->logCouponHistory($couponCondition->getValue(), $coupon);
}
});

Expand Down
8 changes: 8 additions & 0 deletions src/Models/Coupon.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ public function isExpired($orderDateTime = null)
$start = $this->fixed_date->copy()->setTimeFromTimeString($this->fixed_from_time);
$end = $this->fixed_date->copy()->setTimeFromTimeString($this->fixed_to_time);

if ($start->gt($end)) {
$end->addDay();
}

return !$orderDateTime->between($start, $end);
case 'period':
return !$orderDateTime->between($this->period_start_date, $this->period_end_date);
Expand All @@ -204,6 +208,10 @@ public function isExpired($orderDateTime = null)
$start = $orderDateTime->copy()->setTimeFromTimeString($this->recurring_from_time);
$end = $orderDateTime->copy()->setTimeFromTimeString($this->recurring_to_time);

if ($start->gt($end)) {
$end->addDay();
}

return !$orderDateTime->between($start, $end);
}

Expand Down
17 changes: 8 additions & 9 deletions src/Models/CouponHistory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Igniter\Coupons\Models;

use Igniter\Flame\Database\Model;
use Igniter\System\Models\Concerns\Switchable;
use Igniter\User\Models\Concerns\HasCustomer;
use Illuminate\Support\Facades\Event;

Expand All @@ -12,6 +13,7 @@
class CouponHistory extends Model
{
use HasCustomer;
use Switchable;

/**
* @var string The database table name
Expand Down Expand Up @@ -68,7 +70,7 @@ public static function redeem($orderId)
'created_at' => now(),
]);

Event::fire('admin.order.couponRedeemed', [$couponHistory]);
Event::dispatch('admin.order.couponRedeemed', [$couponHistory]);
});
}

Expand All @@ -90,25 +92,22 @@ public function touchStatus()
}

/**
* @param \Igniter\Cart\CartCondition $couponCondition
* @param \Igniter\Coupons\Models\Coupon $coupon
* @param float $couponValue
* @param \Igniter\Cart\Models\Order $order
* @return \Igniter\Coupons\Models\CouponHistory|bool
*/
public static function createHistory($couponCondition, $order)
public static function createHistory($coupon, $couponValue, $order)
{
if (!$coupon = $couponCondition->getModel()) {
return false;
}

$model = new static;
$model->order_id = $order->getKey();
$model->customer_id = $order->customer ? $order->customer->getKey() : null;
$model->coupon_id = $coupon->coupon_id;

Check failure on line 105 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$coupon_id.

Check failure on line 105 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$coupon_id.
$model->code = $coupon->code;

Check failure on line 106 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$code.

Check failure on line 106 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$code.
$model->amount = $couponCondition->getValue();
$model->amount = $couponValue;
$model->min_total = $coupon->min_total;

Check failure on line 108 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$min_total.

Check failure on line 108 in src/Models/CouponHistory.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - Static Analysis

Access to an undefined property Igniter\Coupons\Models\Coupon::$min_total.

if ($model->fireSystemEvent('couponHistory.beforeAddHistory', [$couponCondition, $order->customer, $coupon], true) === false) {
if ($model->fireSystemEvent('couponHistory.beforeAddHistory', [$couponValue, $order->customer, $coupon]) === false) {
return false;
}

Expand Down
59 changes: 59 additions & 0 deletions tests/Actions/RedeemsCouponTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Igniter\Cart\Tests\Actions;

use Igniter\Cart\Models\Order;
use Igniter\Coupons\Actions\RedeemsCoupon;
use Igniter\Coupons\Models\Coupon as CouponModel;
use Igniter\Coupons\Models\CouponHistory;
use Illuminate\Support\Facades\Event;

it('redeems coupon correctly', function() {
Event::fake();

$order = Order::factory()->create();
$order->totals()->create([
'code' => 'coupon',
'title' => 'Coupon (test-coupon)',
'value' => 10,
'priority' => 1,
]);

$couponHistory = CouponHistory::create([
'order_id' => $order->order_id,
'coupon_id' => 1,
'code' => 'test-coupon',
'amount' => 10,
'min_total' => 0,
]);

(new RedeemsCoupon($order))->redeemCoupon();

expect($couponHistory->fresh()->status)->toBeTrue();

Event::assertDispatched('admin.order.couponRedeemed');
});

it('logs coupon history correctly', function() {
Event::fake();

$order = Order::factory()->create();
$coupon = CouponModel::factory()->create();
$redeemsCoupon = new RedeemsCoupon($order);

expect($redeemsCoupon->logCouponHistory(10, $coupon))->toBeInstanceOf(CouponHistory::class);

Event::assertDispatched('couponHistory.beforeAddHistory');
});

it('fails log coupon history when order does not exists', function() {
Event::fake();

$order = Order::factory()->make(['exists' => false]);
$coupon = CouponModel::factory()->create();
$redeemsCoupon = new RedeemsCoupon($order);

expect($redeemsCoupon->logCouponHistory(10, $coupon))->toBeFalse();

Event::assertNotDispatched('couponHistory.beforeAddHistory');
});
123 changes: 123 additions & 0 deletions tests/ApiResources/CouponsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php

namespace Igniter\Cart\Tests\ApiResources;

use Igniter\Cart\Models\Category;
use Igniter\Cart\Models\Menu;
use Igniter\Coupons\Models\Coupon;
use Igniter\Coupons\Models\CouponHistory;
use Igniter\User\Models\User;
use Illuminate\Testing\Fluent\AssertableJson;
use Laravel\Sanctum\Sanctum;

it('returns all coupons', function() {
Sanctum::actingAs(User::factory()->create(), ['coupons:*']);

$this
->get(route('igniter.api.coupons.index'))
->assertOk()
->assertJsonPath('data.0.attributes.name', Coupon::first()->name);
});

it('returns all coupons with menus, categories and history', function() {
$coupon = Coupon::first();
$coupon->menus()->save(Menu::factory()->create());
$coupon->categories()->save(Category::factory()->create());
$coupon->history()->save(CouponHistory::create([
'order_id' => 1,
'coupon_id' => 1,
'code' => 'test-coupon',
'amount' => 10,
'min_total' => 0,
]));

Sanctum::actingAs(User::factory()->create(), ['coupons:*']);

$this
->get(route('igniter.api.coupons.index', ['include' => [
'menus', 'categories', 'history'
]]))
->assertOk()
->assertJsonPath('data.0.attributes.name', $coupon->name)
->assertJsonPath('data.0.relationships.menus.data.0.id', (string)$coupon->menus->first()->getKey())
->assertJsonPath('data.0.relationships.categories.data.0.id', (string)$coupon->categories->first()->getKey())
->assertJsonPath('data.0.relationships.history.data.0.id', (string)$coupon->history->first()->getKey());
});

it('shows a coupon', function() {
Sanctum::actingAs(User::factory()->create(), ['coupons:*']);
$coupon = Coupon::first();

$this
->get(route('igniter.api.coupons.show', [$coupon->getKey()]))
->assertOk()
->assertJson(fn(AssertableJson $json) => $json
->has('data.attributes', fn(AssertableJson $json) => $json
->where('name', $coupon->name)
->where('code', $coupon->code)
->etc()
)->etc()
);
});

it('creates a coupon', function() {
Sanctum::actingAs(User::factory()->create(), ['coupons:*']);

$this
->post(route('igniter.api.coupons.store'), [
'name' => 'Test coupon',
'code' => 'TESTCOUPON',
'type' => 'P',
'discount' => 10,
'redemptions' => 10,
'customer_redemptions' => 1,
'validity' => 'forever',
])
->assertCreated()
->assertJson(fn(AssertableJson $json) => $json
->has('data.attributes', fn(AssertableJson $json) => $json
->where('name', 'Test coupon')
->where('code', 'TESTCOUPON')
->where('type', 'P')
->where('discount', 10)
->where('redemptions', 10)
->where('customer_redemptions', 1)
->etc()
));
});

it('updates a coupon', function() {
Sanctum::actingAs(User::factory()->create(), ['coupons:*']);
$coupon = Coupon::first();

$this
->put(route('igniter.api.coupons.update', [$coupon->getKey()]), [
'name' => 'Test coupon',
'code' => 'TESTCOUPON',
'type' => 'P',
'discount' => 10,
'redemptions' => 10,
'customer_redemptions' => 1,
'validity' => 'forever',
])
->assertOk();

expect($coupon->fresh())->name->toBe('Test coupon')
->code->toBe('TESTCOUPON')
->type->toBe('P')
->discount->toBe(10.0)
->redemptions->toBe(10)
->customer_redemptions->toBe(1)
->validity->toBe('forever');
});

it('deletes a coupon', function() {
Sanctum::actingAs(User::factory()->create(), ['coupons:*']);
$coupon = Coupon::first();

$this
->delete(route('igniter.api.coupons.destroy', [$coupon->getKey()]))
->assertStatus(204);

expect(Coupon::find($coupon->getKey()))->toBeNull();
});
Loading

0 comments on commit f138702

Please sign in to comment.