Skip to content

Commit

Permalink
tax rework
Browse files Browse the repository at this point in the history
  • Loading branch information
iamgergo committed Sep 25, 2024
1 parent 6cc3ecb commit 95db1b6
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 147 deletions.
39 changes: 0 additions & 39 deletions database/factories/TaxFactory.php

This file was deleted.

4 changes: 3 additions & 1 deletion database/factories/TaxRateFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ public function modelName(): string
public function definition(): array
{
return [
//
'value' => $value = mt_rand(10, 30),
'name' => sprintf('%d%% Tax Rate', $value),
'shipping' => false,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function up(): void
Schema::create('bazar_tax_rates', static function (Blueprint $table): void {
$table->id();
$table->string('name');
$table->integer('value')->unsigned();
$table->float('value')->unsigned();
$table->boolean('shipping')->default(false);
$table->timestamps();
});
Expand Down
10 changes: 5 additions & 5 deletions src/Interfaces/Buyable.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Cone\Bazar\Interfaces;

use Cone\Bazar\Models\Item;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Support\Collection;

interface Buyable
{
Expand All @@ -13,12 +13,12 @@ interface Buyable
public function buyable(Checkoutable $checkoutable): bool;

/**
* Get the tax rates for the variant.
* Get the item representation of the buyable instance.
*/
public function taxRates(): MorphToMany;
public function toItem(Checkoutable $checkoutable, array $attributes = []): Item;

/**
* Get the item representation of the buyable instance.
* Get the applicable tax rates.
*/
public function toItem(Checkoutable $checkoutable, array $attributes = []): Item;
public function getApplicableTaxRates(): Collection;
}
2 changes: 1 addition & 1 deletion src/Interfaces/Inventoryable.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface Inventoryable
/**
* Get the formatted dimensions.
*/
public function getFormattedDimensions(string $glue = 'x'): ?string;
public function getFormattedDimensions(): ?string;

/**
* Get the formatted weight.
Expand Down
13 changes: 0 additions & 13 deletions src/Interfaces/Models/Tax.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,8 @@

namespace Cone\Bazar\Interfaces\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;

interface Tax
{
/**
* Get the taxable model for the model.
*/
public function taxable(): MorphTo;

/**
* Get the tax rate for the model.
*/
public function taxRate(): BelongsTo;

/**
* Get the formatted tax.
*/
Expand Down
7 changes: 6 additions & 1 deletion src/Interfaces/Models/TaxRate.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace Cone\Bazar\Interfaces\Models;

use Cone\Bazar\Interfaces\Taxable;

interface TaxRate
{
//
/**
* Calculate the tax for the taxable model.
*/
public function calculate(Taxable $taxable): float;
}
4 changes: 2 additions & 2 deletions src/Interfaces/Taxable.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

namespace Cone\Bazar\Interfaces;

use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

interface Taxable
{
/**
* Get the taxes for the model.
*/
public function taxes(): MorphMany;
public function taxes(): MorphToMany;

/**
* Get the tax base.
Expand Down
8 changes: 5 additions & 3 deletions src/Models/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,12 @@ public function isFee(): bool
*/
public function calculateTaxes(): float
{
$this->buyable->taxRates->each(function (TaxRate $taxRate): void {
$taxRate->calculate($this);
$taxes = $this->buyable->getApplicableTaxRates()->mapWithKeys(function (TaxRate $taxRate): array {
return [$taxRate->getKey() => ['value' => $taxRate->calculate($this)]];
});

return $this->getTaxTotal();
$this->taxes()->sync($taxes);

return $taxes->sum('value');
}
}
11 changes: 10 additions & 1 deletion src/Models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Collection;

class Product extends Model implements Contract
{
Expand Down Expand Up @@ -92,13 +93,21 @@ public function variants(): HasMany
}

/**
* Get the tax rates.
* Get the tax rates for the product.
*/
public function taxRates(): MorphToMany
{
return $this->morphToMany(TaxRate::getProxiedClass(), 'buyable', 'bazar_buyable_tax_rate');
}

/**
* Get the applicable tax rates.
*/
public function getApplicableTaxRates(): Collection
{
return $this->taxRates;
}

/**
* Determine whether the buyable object is available for the checkoutable instance.
*/
Expand Down
15 changes: 10 additions & 5 deletions src/Models/Shipping.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
use Cone\Bazar\Traits\InteractsWithTaxes;
use Cone\Root\Traits\InteractsWithProxy;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
Expand Down Expand Up @@ -291,10 +290,16 @@ public function calculateFee(): float
*/
public function calculateTaxes(): float
{
TaxRate::proxy()->newQuery()->applicableForShipping()->cursor()->each(function (TaxRate $taxRate): void {
$taxRate->calculate($this);
});
$taxes = TaxRate::proxy()
->newQuery()
->applicableForShipping()
->get()
->mapWithKeys(function (TaxRate $taxRate): array {
return [$taxRate->getKey() => ['value' => $taxRate->calculate($this)]];
});

$this->taxes()->sync($taxes);

return $this->getTaxTotal();
return $taxes->sum('value');
}
}
35 changes: 3 additions & 32 deletions src/Models/Tax.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,14 @@

namespace Cone\Bazar\Models;

use Cone\Bazar\Database\Factories\TaxFactory;
use Cone\Bazar\Interfaces\Models\Tax as Contract;
use Cone\Bazar\Support\Currency;
use Cone\Root\Traits\InteractsWithProxy;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\MorphPivot;

class Tax extends Model implements Contract
class Tax extends MorphPivot implements Contract
{
use HasFactory;
use InteractsWithProxy;

/**
Expand Down Expand Up @@ -59,30 +54,6 @@ public static function getProxiedInterface(): string
return Contract::class;
}

/**
* Create a new factory instance for the model.
*/
protected static function newFactory(): TaxFactory
{
return TaxFactory::new();
}

/**
* Get the taxable model for the model.
*/
public function taxable(): MorphTo
{
return $this->morphTo();
}

/**
* Get the tax rate for the model.
*/
public function taxRate(): BelongsTo
{
return $this->belongsTo(TaxRate::getProxiedClass());
}

/**
* Get the formatted value attribute.
*/
Expand All @@ -98,6 +69,6 @@ protected function formattedValue(): Attribute
*/
public function format(): string
{
return (new Currency($this->value, $this->taxable?->checkoutable?->getCurrency()))->format();
return (new Currency($this->value, $this->pivotParent?->checkoutable?->getCurrency()))->format();
}
}
69 changes: 63 additions & 6 deletions src/Models/TaxRate.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,56 @@
use Cone\Bazar\Interfaces\Taxable;
use Cone\Root\Traits\InteractsWithProxy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Number;

class TaxRate extends Model implements Contract
{
use HasFactory;
use InteractsWithProxy;

/**
* The accessors to append to the model's array form.
*
* @var list<string>
*/
protected $appends = [
'formatted_value',
'rate',
];

/**
* The attributes that should have default values.
*
* @var array<string, mixed>
*/
protected $attributes = [
'shipping' => false,
];

/**
* The attributes that should be cast to native types.
*
* @var array<string, string>
*/
protected $casts = [
'shipping' => 'bool',
'value' => 'float',
];

/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'shipping',
'value',
];

/**
* The table associated with the model.
*
Expand All @@ -39,18 +81,33 @@ protected static function newFactory(): TaxRateFactory
}

/**
* Calculate the tax for the taxable model.
* Get the rate attribute.
*/
public function calculate(Taxable $taxable): Tax
protected function rate(): Attribute
{
$value = round($taxable->getTaxBase() * $this->rate, 2);
return new Attribute(
get: fn (): float => round($this->value / 100, 2)
);
}

return $taxable->taxes()->updateOrCreate(
['tax_rate_id' => $this->getKey()],
['value' => $value]
/**
* Get the formatted value attribute.
*/
protected function formattedValue(): Attribute
{
return new Attribute(
get: fn (): string => Number::percentage($this->value)
);
}

/**
* Calculate the tax for the taxable model.
*/
public function calculate(Taxable $taxable): float
{
return round($taxable->getTaxBase() * $this->rate, 2);
}

/**
* Scope the query for the results that are applicable for shipping.
*/
Expand Down
Loading

0 comments on commit 95db1b6

Please sign in to comment.