Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge in 0.5.5 updates #1262

Merged
merged 4 commits into from
Sep 21, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,16 @@ public function create()
$handle = Str::handle("{$this->typeHandle}_{$this->attributeGroup->translate('name')}");
$this->attributeGroup->handle = $handle;

$uniquenessConstraint = 'unique:' . get_class($this->attributeGroup) . ',handle';
if ($this->attributeGroup->id) {
$uniquenessConstraint .= ',' . $this->attributeGroup->id;
}

$this->validate([
'attributeGroup.handle' => 'unique:'.get_class($this->attributeGroup).',handle,'.$this->attributeGroup->id,
'attributeGroup.handle' => $uniquenessConstraint,
]);


if ($this->attributeGroup->id) {
$this->attributeGroup->save();
$this->emit('attribute-group-edit.updated', $this->attributeGroup->id);
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/Actions/Taxes/GetTaxZone.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ public function execute(Addressable $address = null)
}
}

if ($address && $address->country_id) {
$countryZone = app(GetTaxZoneCountry::class)->execute($address->country_id);
if ($countryZone) {
return $countryZone->taxZone;
}
}

return TaxZone::getDefault();
}
}
32 changes: 32 additions & 0 deletions packages/core/src/Actions/Taxes/GetTaxZoneCountry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Lunar\Actions\Taxes;

use Lunar\Models\TaxZoneCountry;

class GetTaxZoneCountry
{
public function execute($countryId)
{
$taxZone = $this->getZone($countryId);

if ($taxZone instanceof TaxZoneCountry) {
return $taxZone;
}

if (!$taxZone) {
return null;
}
}

/**
* Return the zone or zones which match this country.
*
* @param int $countryId
* @return TaxZoneCountry|null
*/
protected function getZone(int $countryId)
{
return TaxZoneCountry::whereCountryId($countryId)->first();
}
}
2 changes: 1 addition & 1 deletion packages/core/src/Managers/DiscountManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public function getApplied(): Collection

public function apply(Cart $cart): Cart
{
if (! $this->discounts) {
if (! $this->discounts || $this->discounts?->isEmpty()) {
$this->discounts = $this->getDiscounts($cart);
}

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/Pipelines/Cart/ApplyDiscounts.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ final class ApplyDiscounts
*/
public function handle(Cart $cart, Closure $next)
{
$cart->discounts = collect([]);
$cart->discountBreakdown = collect([]);

Discounts::apply($cart);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/**
* @group lunar.actions
*/
class SortProductsByPriceTest extends TestCase
class GenerateOrderReferenceTest extends TestCase
{
use RefreshDatabase;

Expand Down
61 changes: 61 additions & 0 deletions packages/core/tests/Unit/Actions/Taxes/GetTaxZoneCountryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Lunar\Tests\Unit\Actions\Taxes;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Lunar\Actions\Taxes\GetTaxZoneCountry;
use Lunar\Models\Country;
use Lunar\Models\TaxZoneCountry;
use Lunar\Tests\TestCase;

/**
* @group lunar.actions
*/
class GetTaxZoneCountryTest extends TestCase
{
use RefreshDatabase;

/** @test */
public function can_match_country_id()
{
$belgium = Country::factory()->create([
'name' => 'Belgium',
]);

$uk = Country::factory()->create([
'name' => 'United Kingdom',
]);

$taxZoneBelgium = TaxZoneCountry::factory()->create([
'country_id' => $belgium->id,
]);

$taxZoneUk = TaxZoneCountry::factory()->create([
'country_id' => $uk->id,
]);

$zone = app(GetTaxZoneCountry::class)->execute($uk->id);

$this->assertEquals($taxZoneUk->id, $zone->id);
}

/** @test */
public function can_mismatch_country_id()
{
$belgium = Country::factory()->create([
'name' => 'Belgium',
]);

$uk = Country::factory()->create([
'name' => 'United Kingdom',
]);

$taxZoneBelgium = TaxZoneCountry::factory()->create([
'country_id' => $belgium->id,
]);

$zone = app(GetTaxZoneCountry::class)->execute($uk->id);

$this->assertNull($zone);
}
}
99 changes: 99 additions & 0 deletions packages/core/tests/Unit/Actions/Taxes/GetTaxZoneTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace Lunar\Tests\Unit\Actions\Taxes;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Lunar\Actions\Taxes\GetTaxZone;
use Lunar\Actions\Taxes\GetTaxZoneCountry;
use Lunar\Models\Address;
use Lunar\Models\Country;
use Lunar\Models\State;
use Lunar\Models\TaxZone;
use Lunar\Models\TaxZoneCountry;
use Lunar\Models\TaxZonePostcode;
use Lunar\Models\TaxZoneState;
use Lunar\Tests\TestCase;

/**
* @group lunar.actions
*/
class GetTaxZoneTest extends TestCase
{
use RefreshDatabase;

/** @test */
public function can_prioritize_taxzones()
{
$postcode = 'SW1A 0AA';

$state = State::factory()->create([
'code' => 'AL',
'name' => 'Alabama',
]);

$country = Country::factory()->create([
'name' => 'Belgium',
]);

$taxZonePostcode = TaxZonePostcode::factory()->create([
'tax_zone_id' => TaxZone::factory(['default' => false]),
'postcode' => $postcode,
]);

$taxZoneState = TaxZoneState::factory()->create([
'tax_zone_id' => TaxZone::factory(['default' => false]),
'state_id' => $state->id,
]);

$taxZoneCountry = TaxZoneCountry::factory()->create([
'tax_zone_id' => TaxZone::factory(['default' => false]),
'country_id' => $country->id,
]);

$defaultTaxZone = TaxZone::factory(['default' => true])->create();

// postcode, state and country match => postcode tax zone should be returned
$addressWithAllMatching = Address::factory()->create([
'postcode' => $postcode,
'state' => $state->name,
'country_id' => $country->id,
]);

$zone1 = app(GetTaxZone::class)->execute($addressWithAllMatching);

$this->assertEquals($taxZonePostcode->tax_zone_id, $zone1->id);

// only state and country match => state tax zone should be returned
$addressWithOnlyStateAndCountryMatching = Address::factory()->create([
'postcode' => '1234AB',
'state' => $state->name,
'country_id' => $country->id,
]);

$zone2 = app(GetTaxZone::class)->execute($addressWithOnlyStateAndCountryMatching);

$this->assertEquals($taxZoneState->tax_zone_id, $zone2->id);

// only country matches => country tax zone should be returned
$addressWithOnlyCountryMatching = Address::factory()->create([
'postcode' => '1234AB',
'state' => 'Alaska',
'country_id' => $country->id,
]);

$zone3 = app(GetTaxZone::class)->execute($addressWithOnlyCountryMatching);

$this->assertEquals($taxZoneCountry->tax_zone_id, $zone3->id);

// nothing matches => default tax zone should be returned
$addressWithOnlyCountryMatching = Address::factory()->create([
'postcode' => '1234AB',
'state' => 'Alaska',
'country_id' => 123,
]);

$zone3 = app(GetTaxZone::class)->execute($addressWithOnlyCountryMatching);

$this->assertEquals($defaultTaxZone->id, $zone3->id);
}
}
85 changes: 82 additions & 3 deletions packages/core/tests/Unit/DiscountTypes/AmountOffTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Foundation\Testing\RefreshDatabase;
use Lunar\DiscountTypes\AmountOff;
use Lunar\Facades\CartSession;
use Lunar\Models\Brand;
use Lunar\Models\Cart;
use Lunar\Models\Channel;
Expand Down Expand Up @@ -704,7 +705,7 @@ public function cannot_apply_discount_coupon_without_coupon_code()
$this->assertEquals(0, $cart->discountTotal->value);
$this->assertEquals(2400, $cart->total->value);
$this->assertEquals(400, $cart->taxTotal->value);
$this->assertNull($cart->discounts);
$this->assertTrue($cart->discounts->isEmpty());
}

/**
Expand Down Expand Up @@ -982,7 +983,7 @@ public function cannot_apply_discount_with_min_spend()
$this->assertEquals(2000, $cart->subTotal->value);
$this->assertEquals(2400, $cart->total->value);
$this->assertEquals(400, $cart->taxTotal->value);
$this->assertNull($cart->discounts);
$this->assertTrue($cart->discounts->isEmpty());
}

/**
Expand Down Expand Up @@ -1221,7 +1222,7 @@ public function cannot_apply_discount_with_max_user_uses()
$this->assertEquals(2400, $cart->total->value);
$this->assertEquals(2000, $cart->subTotal->value);
}

/**
* @test
*/
Expand Down Expand Up @@ -1362,4 +1363,82 @@ public function fixed_amount_discount_distributes_across_cart_lines_with_differe
$this->assertEquals(357, $lastLine->discountTotal->value);
$this->assertEquals(1500, $cart->discountTotal->value);
}

/**
* @test
*/
public function can_apply_discount_dynamically()
{
$currency = Currency::getDefault();

$customerGroup = CustomerGroup::getDefault();

$channel = Channel::getDefault();

$cart = Cart::factory()->create([
'currency_id' => $currency->id,
'channel_id' => $channel->id,
]);

$purchasableA = ProductVariant::factory()->create();

Price::factory()->create([
'price' => 1000, // £10
'tier' => 1,
'currency_id' => $currency->id,
'priceable_type' => get_class($purchasableA),
'priceable_id' => $purchasableA->id,
]);

$cart->lines()->create([
'purchasable_type' => get_class($purchasableA),
'purchasable_id' => $purchasableA->id,
'quantity' => 2,
]);

$discount = Discount::factory()->create([
'type' => AmountOff::class,
'name' => 'Test Coupon',
'coupon' => '10OFF',
'data' => [
'fixed_value' => true,
'fixed_values' => [
'GBP' => 10.5,
],
],
]);

$discount->customerGroups()->sync([
$customerGroup->id => [
'enabled' => true,
'starts_at' => now(),
],
]);

$discount->channels()->sync([
$channel->id => [
'enabled' => true,
'starts_at' => now()->subHour(),
],
]);

// Calculate method called for the first time
CartSession::use($cart)->calculate();

// Update cart with coupon code
$cart->update([
'coupon_code' => '10OFF',
]);

// Get current cart which runs the calculate method for the second time
$cart = CartSession::current();

// Calculate method called for the third time
$cart = $cart->calculate();

$this->assertEquals(1050, $cart->discountTotal->value);
$this->assertEquals(1140, $cart->total->value);
$this->assertEquals(190, $cart->taxTotal->value);
$this->assertCount(1, $cart->discounts);
}
}