Skip to content

Commit

Permalink
Merge pull request #23 from Safemood/1.5.0
Browse files Browse the repository at this point in the history
1.5.0
  • Loading branch information
Safemood committed Apr 7, 2024
2 parents 21a1457 + 608af44 commit b819662
Show file tree
Hide file tree
Showing 36 changed files with 1,366 additions and 212 deletions.
8 changes: 5 additions & 3 deletions composer.json
Expand Up @@ -21,13 +21,14 @@
"illuminate/contracts": "^10|^11.1"
},
"require-dev": {
"laravel/pint": "^1.13.7",
"larastan/larastan": "^2.7.0",
"laravel/pint": "^1.13.7",
"nunomaduro/collision": "^7.0|^8.9",
"orchestra/testbench": "^8.21.1|^9.0.0",
"pestphp/pest": "^2.30",
"pestphp/pest-plugin-arch": "^2.5",
"pestphp/pest-plugin-laravel": "^2.2",
"pestphp/pest-plugin-type-coverage": "^2.8",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan-deprecation-rules": "^1.1.4"
},
Expand Down Expand Up @@ -58,8 +59,9 @@
],
"analyse": "vendor/bin/phpstan analyse",
"test": "vendor/bin/pest",
"test-coverage": "vendor/bin/pest --coverage",
"format": "vendor/bin/pint"
"test-coverage": "XDEBUG_MODE=coverage vendor/bin/pest --coverage",
"format": "vendor/bin/pint",
"type-coverage": "vendor/bin/pest --type-coverage"
},
"config": {
"sort-packages": true,
Expand Down
2 changes: 2 additions & 0 deletions config/discountify.php
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

return [
'condition_namespace' => 'App\\Conditions',
'condition_path' => app_path('Conditions'),
Expand Down
2 changes: 2 additions & 0 deletions database/factories/ModelFactory.php
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Safemood\Discountify\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
Expand Down
9 changes: 9 additions & 0 deletions phpstan-baseline.neon
@@ -0,0 +1,9 @@
parameters:
ignoreErrors:
-
message: "#^Out of 109 possible param types, only 104 \\- 95\\.4 %% actually have it\\. Add more param types to get over 99 %%$#"
path: src/Commands/ConditionMakeCommand.php

-
message: "#^Out of 109 possible param types, only 104 \\- 95\\.4 %% actually have it\\. Add more param types to get over 99 %%$#"
path: src/Discountify.php
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Expand Up @@ -2,7 +2,7 @@ includes:
- phpstan-baseline.neon

parameters:
level: 5
level: 8
paths:
- src
- config
Expand Down
6 changes: 6 additions & 0 deletions pint.json
@@ -0,0 +1,6 @@
{
"preset": "laravel",
"rules": {
"declare_strict_types": true
}
}
21 changes: 8 additions & 13 deletions src/Commands/ConditionMakeCommand.php
@@ -1,5 +1,7 @@
<?php

declare(strict_types=1);

namespace Safemood\Discountify\Commands;

use Illuminate\Console\GeneratorCommand;
Expand Down Expand Up @@ -32,10 +34,8 @@ class ConditionMakeCommand extends GeneratorCommand

/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
protected function getStub(): string
{
return file_exists($customPath = $this->laravel->basePath('stubs/condition.stub'))
? $customPath
Expand All @@ -46,9 +46,8 @@ protected function getStub()
* Get the default namespace for the class.
*
* @param string $rootNamespace
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
protected function getDefaultNamespace($rootNamespace): string
{
return "{$rootNamespace}\\Conditions";
}
Expand All @@ -57,9 +56,8 @@ protected function getDefaultNamespace($rootNamespace)
* Get the destination class path.
*
* @param string $name
* @return string
*/
protected function getPath($name)
protected function getPath($name): string
{

$customPath = config('discountify.condition_path');
Expand All @@ -69,10 +67,8 @@ protected function getPath($name)

/**
* Get the console command arguments.
*
* @return array
*/
protected function getOptions()
protected function getOptions(): array
{
return [
['discount', 'd', InputOption::VALUE_OPTIONAL, 'The discount for the condition', 0, []],
Expand All @@ -85,18 +81,17 @@ protected function getOptions()
* Build the class with the given name.
*
* @param string $name
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
protected function buildClass($name)
protected function buildClass($name): string
{
$stub = parent::buildClass($name);

return $this->customizeStub($stub);
}

protected function customizeStub($stub)
protected function customizeStub(string $stub): string
{
$slug = $this->option('slug') ?? $this->getNameInput();

Expand Down
151 changes: 98 additions & 53 deletions src/Concerns/HasCalculations.php
@@ -1,124 +1,169 @@
<?php

declare(strict_types=1);

namespace Safemood\Discountify\Concerns;

use Safemood\Discountify\Exceptions\ZeroQuantityException;

/**
* Trait HasCalculations
*
* This trait provides methods for performing various calculations within Discountify.
*/
trait HasCalculations
{
/**
* Calculate the global discount amount.
*
* @return float The global discount amount.
*/
private function calculateGlobalDiscount(): float
public function calculateGlobalDiscount(): float
{
return $this->calculateTotal() * ($this->globalDiscount / 100);
return $this->calculateSubtotal() * ($this->getGlobalDiscount() / 100);
}

/**
* Calculate total with global tax rate.
*
* @param float|null $globalTaxRate Optional. The global tax rate. Defaults to null.
* @return float The total with taxes.
*/
public function calculateTotalWithTaxes(?float $globalTaxRate = null): float
{
$this->globalTaxRate = $globalTaxRate ?? $this->globalTaxRate;
$this->globalTaxRate = $globalTaxRate ?? $this->getGlobalTaxRate();

$total = $this->calculateTotal();
$total = $this->calculateSubtotal();
$tax = $this->calculateGlobalTax();

return $total + $tax;
}

/**
* Calculate total with the discount.
* Calculate the total discount rate.
*
* @param float|null $globalDiscount Optional. The global discount rate. Defaults to null.
* @return float The total discount rate.
*/
public function calculateDiscount(?int $globalDiscount = null): float
public function discountRate(?float $globalDiscount = null): float
{
$this->globalDiscount = $globalDiscount ?? $this->globalDiscount;
$globalDiscount = $globalDiscount ?? $this->getGlobalDiscount();

$total = $this->calculateTotal();
$globalDiscount = $this->calculateGlobalDiscount();
$couponDiscount = ($this->couponManager->couponDiscount() / 100) * $total;
$discount = $globalDiscount + $couponDiscount + $this->evaluateConditions();
$couponDiscount = $this->couponManager->couponDiscount();
$conditionDiscount = $this->conditionDiscount();

return max(0, $total - $discount);
$totalDiscountRate = $globalDiscount + $conditionDiscount + $couponDiscount;

return min($totalDiscountRate, 100);
}

/**
* Calculate total with the discount after tax.
* Calculate the global tax amount.
*
* @param float|null $globalTaxRate Optional. The global tax rate. Defaults to null.
* @return float The global tax amount.
*/
public function calculateDiscountAfterTax(?int $globalDiscount = null): float
public function calculateGlobalTax(?float $globalTaxRate = null): float
{
$taxRate = $globalTaxRate ?? $this->getGlobalTaxRate();

$total = $this->calculateTotal() + $this->calculateGlobalTax();
$globalDiscount = $this->calculateGlobalDiscount();
$couponDiscount = ($this->couponManager->couponDiscount() / 100) * $total;
$discount = $globalDiscount + $couponDiscount + $this->evaluateConditions();
$total = $this->calculateSubtotal();

return max(0, $total - $discount);
return $total * ($taxRate / 100);
}

/**
* Calculate total with the discount before tax.
* Calculate the subtotal amount.
*
* @return float The subtotal amount.
*
* @throws ZeroQuantityException If any item in the cart has a quantity of zero.
*/
public function calculateDiscountBeforeTax(?int $globalDiscount = null): float
public function calculateSubtotal(): float
{
return $this->calculateDiscount($globalDiscount) + $this->calculateGlobalTax();

return array_reduce(
$this->items,
function ($total, $item) {
$quantity = $this->getField($item, 'quantity');
$price = $this->getField($item, 'price');

if ($quantity === 0) {
throw new ZeroQuantityException();
}

return $total + ($quantity * $price);
},
0
);
}

/**
* Calculate total with global tax rate.
* Calculate the tax amount.
*
* @param bool $afterDiscount Optional. Whether to calculate tax after applying discounts. Defaults to false.
* @return float The tax amount.
*/
public function calculateGlobalTax(?float $globalTaxRate = null): float
public function calculateTaxAmount(bool $afterDiscount = false): float
{
$this->globalTaxRate = $globalTaxRate ?? $this->globalTaxRate;
$subTotal = $afterDiscount ? $this->calculateTotalAfterDiscount() : $this->calculateSubtotal();

$total = $this->calculateTotal();

return $total * ($this->globalTaxRate / 100);
return $subTotal * ($this->getGlobalTaxRate() / 100);
}

/**
* Calculate total amount based on items.
* Calculate the savings amount.
*
* @param float|null $globalDiscount Optional. The global discount rate. Defaults to null.
* @return float The savings amount.
*/
private function calculateTotal(): float
public function calculateSavings(?float $globalDiscount = null): float
{
if (! is_array($this->items)) {
return 0;
}

return array_reduce(
$this->items,
function ($total, $item) {
return $total + ($this->getField($item, 'quantity') * $this->getField($item, 'price'));
},
0
);
return $this->calculateTotalWithTaxes() * ($this->discountRate($globalDiscount) / 100);
}

/**
* Get the subtotal amount.
* Calculate the total amount after applying discounts.
*
* @param float|null $globalDiscount Optional. The global discount rate. Defaults to null.
* @return float The total after applying discounts.
*/
public function calculateSubtotal(): float
public function calculateTotalAfterDiscount(?float $globalDiscount = null): float
{
return $this->calculateTotal();
$subTotal = $this->calculateSubtotal();

return $subTotal - ($subTotal * ($this->discountRate($globalDiscount) / 100));
}

/**
* Get the tax amount.
* Calculate the final total amount (after discounts and taxes).
*
* @return float The final total amount.
*/
public function taxAmout(): float
public function calculateFinalTotal(): float
{
return $this->calculateGlobalTax();
$total = $this->calculateTotalWithTaxes();
$discountRate = $this->discountRate();
$discountedTotal = $total * (1 - $discountRate / 100);

return max(0, $discountedTotal);
}

/**
* Get the total amount (after discounts and taxes).
* Calculate and return various details related to the final total.
*
* @return array An array containing various details related to the final total.
*/
public function calculateFinalTotal(bool $beforeTax = true): float
public function calculateFinalTotalDetails(): array
{

return $beforeTax ?
$this->calculateDiscountBeforeTax()
: $this->calculateDiscountAfterTax();
return [
'total' => round($this->calculateFinalTotal(), 3),
'subtotal' => $this->calculateSubtotal(),
'tax_amount' => $this->calculateTaxAmount(),
'total_after_discount' => $this->calculateTotalAfterDiscount(),
'savings' => round($this->calculateSavings(), 3),
'tax_rate' => $this->getGlobalTaxRate(),
'discount_rate' => $this->discountRate(),
];
}
}

0 comments on commit b819662

Please sign in to comment.