¨4.0.1¨

This commit is contained in:
¨NW¨
2023-12-03 14:07:47 +00:00
parent c08b36d1b6
commit f35052522d
1112 changed files with 43019 additions and 24987 deletions

View File

@@ -16,6 +16,7 @@ class TaxTabs extends Tabs
->add($this->rates());
}
private function general()
{
return tap(new Tab('general', trans('tax::taxes.tabs.general')), function (Tab $tab) {
@@ -26,6 +27,7 @@ class TaxTabs extends Tabs
});
}
private function rates()
{
return tap(new Tab('rates', trans('tax::taxes.tabs.rates')), function (Tab $tab) {

View File

@@ -21,6 +21,7 @@ class CreateTaxClassesTable extends Migration
});
}
/**
* Reverse the migrations.
*

View File

@@ -24,6 +24,7 @@ class CreateTaxClassTranslationsTable extends Migration
});
}
/**
* Reverse the migrations.
*

View File

@@ -29,6 +29,7 @@ class CreateTaxRatesTable extends Migration
});
}
/**
* Reverse the migrations.
*

View File

@@ -24,6 +24,7 @@ class CreateTaxRateTranslationsTable extends Migration
});
}
/**
* Reverse the migrations.
*

View File

@@ -7,6 +7,7 @@ use Modules\Support\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Modules\Product\Entities\Product;
use Modules\Support\Eloquent\Translatable;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\SoftDeletes;
class TaxClass extends Model
@@ -16,21 +17,24 @@ class TaxClass extends Model
const SHIPPING_ADDRESS = 'shipping_address';
const BILLING_ADDRESS = 'billing_address';
const STORE_ADDRESS = 'store_address';
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = ['label'];
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['based_on'];
/**
* The attributes that should be mutated to dates.
*
@@ -38,12 +42,19 @@ class TaxClass extends Model
*/
protected $dates = ['start_date', 'end_date', 'deleted_at'];
/**
* The attributes that are translatable.
* Get tag list.
*
* @var array
* @return Collection
*/
public $translatedAttributes = ['label'];
public static function list()
{
return Cache::tags('tax_classes')->rememberForever(md5('tax_classes.list:' . locale()), function () {
return self::all()->sortBy('label')->pluck('label', 'id');
});
}
/**
* Perform any actions required after the model boots.
@@ -57,18 +68,30 @@ class TaxClass extends Model
});
}
/**
* Get tag list.
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public static function list()
public function saveRates($rates = [])
{
return Cache::tags('tax_classes')->rememberForever(md5('tax_classes.list:' . locale()), function () {
return self::all()->sortBy('label')->pluck('label', 'id');
});
$ids = $this->getDeleteCandidates($rates);
if ($ids->isNotEmpty()) {
$this->taxRates()->whereIn('id', $ids)->delete();
}
foreach (array_reset_index($rates) as $index => $rate) {
$this->taxRates()->updateOrCreate(
['id' => $rate['id']],
$rate + ['position' => $index]
);
}
}
public function taxRates()
{
return $this->hasMany(TaxRate::class)->orderBy('position');
}
public function findTaxRate($addresses)
{
return $this->taxRates()
@@ -76,6 +99,7 @@ class TaxClass extends Model
->first();
}
public function determineAddress($addresses)
{
if ($this->based_on === self::SHIPPING_ADDRESS) {
@@ -100,36 +124,18 @@ class TaxClass extends Model
return [];
}
public function taxRates()
{
return $this->hasMany(TaxRate::class)->orderBy('position');
}
public function products()
{
return $this->hasMany(Product::class);
}
public function table()
{
return new AdminTable($this->newQuery());
}
public function saveRates($rates = [])
{
$ids = $this->getDeleteCandidates($rates);
if ($ids->isNotEmpty()) {
$this->taxRates()->whereIn('id', $ids)->delete();
}
foreach (array_reset_index($rates) as $index => $rate) {
$this->taxRates()->updateOrCreate(
['id' => $rate['id']],
$rate + ['position' => $index]
);
}
}
private function getDeleteCandidates($rates = [])
{

View File

@@ -13,20 +13,24 @@ class TaxRate extends Model
{
use Translatable, SoftDeletes;
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = ['name'];
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['country', 'state', 'city', 'zip', 'rate', 'position'];
/**
* The attributes that should be mutated to dates.
*
@@ -34,12 +38,6 @@ class TaxRate extends Model
*/
protected $dates = ['start_date', 'end_date', 'deleted_at'];
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = ['name'];
public function orders()
{
@@ -49,6 +47,7 @@ class TaxRate extends Model
->withPivot('amount');
}
public function scopeFindByAddress($query, $address)
{
$address = $this->mergeDefaultAddress($address);
@@ -66,11 +65,69 @@ class TaxRate extends Model
->orderBy('position');
}
public function getCountryAttribute($country)
{
return $country === '*' ? null : $country;
}
public function setCountryAttribute($country)
{
$this->attributes['country'] = $country ?: '*';
}
public function getStateAttribute($state)
{
return $state === '*' ? null : $state;
}
public function setStateAttribute($state)
{
$this->attributes['state'] = $state ?: '*';
}
public function getCityAttribute($city)
{
return $city === '*' ? null : $city;
}
public function setCityAttribute($city)
{
$this->attributes['city'] = $city ?: '*';
}
public function getZipAttribute($zip)
{
return $zip === '*' ? null : $zip;
}
public function setZipAttribute($zip)
{
$this->attributes['zip'] = $zip ?: '*';
}
public function getTotalAttribute($total)
{
return Money::inDefaultCurrency($total);
}
private function mergeDefaultAddress($address)
{
return $address += ['country' => null, 'state' => null, 'city' => null, 'zip' => null];
$address += ['country' => null, 'state' => null, 'city' => null, 'zip' => null];
return $address;
}
private function rawOrderClause()
{
return "(
@@ -80,49 +137,4 @@ class TaxRate extends Model
CASE WHEN zip = ? THEN 1 ELSE 0 END
) DESC";
}
public function getCountryAttribute($country)
{
return $country === '*' ? null : $country;
}
public function setCountryAttribute($country)
{
$this->attributes['country'] = $country ?: '*';
}
public function getStateAttribute($state)
{
return $state === '*' ? null : $state;
}
public function setStateAttribute($state)
{
$this->attributes['state'] = $state ?: '*';
}
public function getCityAttribute($city)
{
return $city === '*' ? null : $city;
}
public function setCityAttribute($city)
{
$this->attributes['city'] = $city ?: '*';
}
public function getZipAttribute($zip)
{
return $zip === '*' ? null : $zip;
}
public function setZipAttribute($zip)
{
$this->attributes['zip'] = $zip ?: '*';
}
public function getTotalAttribute($total)
{
return Money::inDefaultCurrency($total);
}
}

View File

@@ -2,16 +2,47 @@
namespace Modules\Tax\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Modules\Cart\Facades\Cart;
use Illuminate\Pipeline\Pipeline;
use Modules\Coupon\Entities\Coupon;
use Modules\Coupon\Checkers\ValidCoupon;
use Modules\Coupon\Checkers\CouponExists;
use Modules\Coupon\Checkers\MinimumSpend;
use Modules\Coupon\Checkers\MaximumSpend;
use Modules\Coupon\Checkers\AlreadyApplied;
use Modules\Coupon\Checkers\ExcludedProducts;
use Modules\Coupon\Checkers\ApplicableProducts;
use Modules\Coupon\Checkers\ExcludedCategories;
use Modules\Coupon\Checkers\UsageLimitPerCoupon;
use Modules\Coupon\Checkers\ApplicableCategories;
use Modules\Coupon\Checkers\UsageLimitPerCustomer;
class CartTaxController
{
private array $checkers = [
CouponExists::class,
AlreadyApplied::class,
ValidCoupon::class,
MinimumSpend::class,
MaximumSpend::class,
ApplicableProducts::class,
ExcludedProducts::class,
ApplicableCategories::class,
ExcludedCategories::class,
UsageLimitPerCoupon::class,
UsageLimitPerCustomer::class,
];
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @param Request $request
*
* @return Response
*/
public function store(Request $request)
{
@@ -19,9 +50,30 @@ class CartTaxController
Cart::addTaxes($request);
return Cart::instance();
$cartWithCoupon = null;
$couponCode = request()->query('coupon_code');
if ($couponCode) {
$coupon = Coupon::findByCode($couponCode);
try {
resolve(Pipeline::class)
->send($coupon)
->through($this->checkers)
->then(function ($coupon) use (&$cartWithCoupon) {
Cart::applyCoupon($coupon);
$cartWithCoupon = json_encode(Cart::instance());
Cart::removeCoupon();
});
} catch (Exception) {
//Just suppressing the exception
}
}
return $cartWithCoupon ?? Cart::instance();
}
private function mergeShippingAddress($request)
{
$request->merge([

View File

@@ -15,6 +15,7 @@ class SaveTaxRequest extends Request
*/
protected $availableAttributes = 'tax::attributes';
/**
* Get the validation rules that apply to the request.
*
@@ -30,6 +31,7 @@ class SaveTaxRequest extends Request
];
}
/**
* Get data to be validated from the request.
*
@@ -42,16 +44,18 @@ class SaveTaxRequest extends Request
])->all();
}
/**
* Filter tax rates.
*
* @param array $rates
*
* @return array
*/
private function filter($rates = [])
{
return array_filter($rates, function ($rate) {
return ! is_null($rate['name']) || ! is_null($rate['rate']);
return !is_null($rate['name']) || !is_null($rate['rate']);
});
}
}

View File

@@ -3,14 +3,11 @@
namespace Modules\Tax\Providers;
use Modules\Tax\Admin\TaxTabs;
use Modules\Support\Traits\AddsAsset;
use Illuminate\Support\ServiceProvider;
use Modules\Admin\Ui\Facades\TabManager;
class TaxServiceProvider extends ServiceProvider
{
use AddsAsset;
/**
* Bootstrap the application services.
*
@@ -19,7 +16,5 @@ class TaxServiceProvider extends ServiceProvider
public function boot()
{
TabManager::register('tax_classes', TaxTabs::class);
$this->addAdminAssets('admin.taxes.(create|edit)', ['admin.tax.css', 'admin.tax.js']);
}
}

View File

@@ -4,13 +4,13 @@ export default class {
constructor() {
this.rateCount = 0;
this.addTaxRates(FleetCart.data['tax_rates']);
this.addTaxRates(FleetCart.data["tax_rates"]);
if (this.rateCount === 0) {
this.addTaxRate();
}
this.addTaxRatesErrors(FleetCart.errors['tax_rates']);
this.addTaxRatesErrors(FleetCart.errors["tax_rates"]);
this.eventListeners();
this.sortable();
@@ -18,14 +18,14 @@ export default class {
addTaxRates(rates) {
for (let rate of rates) {
this.addTaxRate(rate)
this.addTaxRate(rate);
}
}
addTaxRate(rate = {}) {
let textRate = new TaxRate(this.rateCount++, rate);
$('#tax-rates').append(textRate.html());
$("#tax-rates").append(textRate.html());
textRate.updateState();
@@ -37,18 +37,18 @@ export default class {
let id = $.escapeSelector(key);
let parent = $(`#${id}`).parent();
parent.addClass('has-error');
parent.addClass("has-error");
parent.append(`<span class="help-block">${errors[key][0]}</span>`);
}
}
eventListeners() {
$('#add-new-rate').on('click', () => this.addTaxRate());
$("#add-new-rate").on("click", () => this.addTaxRate());
}
sortable() {
Sortable.create(document.getElementById('tax-rates'), {
handle: '.drag-icon',
Sortable.create(document.getElementById("tax-rates"), {
handle: ".drag-handle",
animation: 150,
});
}

View File

@@ -5,9 +5,11 @@ use Modules\Tax\Entities\TaxClass;
return [
'tax' => 'Tax',
'taxes' => 'Taxes',
'table' => [
'tax_class' => 'Tax Class',
],
'tabs' => [
'group' => [
'tax_information' => 'Tax Information',
@@ -15,9 +17,11 @@ return [
'general' => 'General',
'rates' => 'Rates',
],
'form' => [
'add_new_rate' => 'Add New Rate',
'delete_rate' => 'Delete Rate',
'based_on' => [
TaxClass::SHIPPING_ADDRESS => 'Shipping Address',
TaxClass::BILLING_ADDRESS => 'Billing Address',

View File

@@ -16,3 +16,10 @@
@endsection
@include('tax::admin.taxes.partials.shortcuts')
@push('globals')
@vite([
'Modules/Tax/Resources/assets/admin/sass/main.scss',
'Modules/Tax/Resources/assets/admin/js/main.js'
])
@endpush

View File

@@ -18,3 +18,10 @@
@endsection
@include('tax::admin.taxes.partials.shortcuts')
@push('globals')
@vite([
'Modules/Tax/Resources/assets/admin/sass/main.scss',
'Modules/Tax/Resources/assets/admin/js/main.js'
])
@endpush

View File

@@ -25,7 +25,7 @@
@endcomponent
@push('scripts')
<script>
<script type="module">
new DataTable('#taxes-table .table', {
columns: [
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },

View File

@@ -6,7 +6,7 @@
@endpush
@push('scripts')
<script>
<script type="module">
keypressAction([
{ key: 'b', route: "{{ route('admin.taxes.index') }}" }
]);

View File

@@ -1,7 +1,7 @@
<script type="text/html" id="tax-rate-template">
<tr class="tax-rate">
<td class="text-center">
<span class="drag-icon">
<span class="drag-handle">
<i class="fa">&#xf142;</i>
<i class="fa">&#xf142;</i>
</span>

View File

@@ -8,6 +8,12 @@ Route::get('taxes', [
'middleware' => 'can:admin.taxes.index',
]);
Route::get('taxes/index/table', [
'as' => 'admin.taxes.table',
'uses' => 'TaxController@table',
'middleware' => 'can:admin.taxes.index',
]);
Route::get('taxes/create', [
'as' => 'admin.taxes.create',
'uses' => 'TaxController@create',