¨4.0.1¨
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -21,6 +21,7 @@ class CreateTaxClassesTable extends Migration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@ class CreateTaxClassTranslationsTable extends Migration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
|
||||
@@ -29,6 +29,7 @@ class CreateTaxRatesTable extends Migration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@ class CreateTaxRateTranslationsTable extends Migration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
|
||||
@@ -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 = [])
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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%' },
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
<script type="module">
|
||||
keypressAction([
|
||||
{ key: 'b', route: "{{ route('admin.taxes.index') }}" }
|
||||
]);
|
||||
|
||||
@@ -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"></i>
|
||||
<i class="fa"></i>
|
||||
</span>
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user