Rework on product name/description and translate
This commit is contained in:
parent
bfd17b0686
commit
b719efb58c
@ -84,7 +84,7 @@ class ProductController extends Controller
|
||||
|
||||
public function details_addedit(ProductAddEdit $request,Product $o)
|
||||
{
|
||||
foreach ($request->except(['_token','submit','description']) as $key => $item)
|
||||
foreach ($request->except(['_token','submit','translate']) as $key => $item)
|
||||
$o->{$key} = $item;
|
||||
|
||||
$o->active = (bool)$request->active;
|
||||
@ -95,13 +95,12 @@ class ProductController extends Controller
|
||||
return redirect()->back()->withErrors($e->getMessage())->withInput();
|
||||
}
|
||||
|
||||
$o->load(['description']);
|
||||
$oo = $o->description ?: new ProductTranslate;
|
||||
|
||||
foreach ($request->get('description',[]) as $key => $item)
|
||||
$o->load(['translate']);
|
||||
$oo = $o->translate ?: new ProductTranslate;
|
||||
foreach ($request->get('translate',[]) as $key => $item)
|
||||
$oo->{$key} = $item;
|
||||
|
||||
$o->description()->save($oo);
|
||||
$o->translate()->save($oo);
|
||||
|
||||
return redirect()->back()
|
||||
->with('success','Product saved');
|
||||
|
@ -28,7 +28,9 @@ class ProductAddEdit extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'description.name' => 'required|string|min:2|max:100',
|
||||
'translate.name_short' => 'required|string|min:2|max:100',
|
||||
'translate.name_detail' => 'required|string|min:2|max:100',
|
||||
'translate.description' => 'required|string|min:2|max:255',
|
||||
'active' => 'sometimes|accepted',
|
||||
'model' => 'sometimes|string', // @todo Check that it is a valid model type
|
||||
'model_id' => 'sometimes|int', // @todo Check that it is a valid model type
|
||||
|
@ -31,9 +31,10 @@ use App\Traits\{ProductDetails,SiteID};
|
||||
* + category_name : Type of product supplied (Friendly Name for display, not for internal logic)
|
||||
* + supplied : Supplier product provided for this offering
|
||||
* + supplier : Supplier for this offering
|
||||
* + name : Brief Name for our product // @todo we should change this to be consistent with service
|
||||
* + name_short : Product ID for our Product
|
||||
* + name_long : Long Name for our product
|
||||
* + name : Brief Name for our product with name_detail
|
||||
* + name_short : Product ID for our Product (description.name => name_short)
|
||||
* + name_detail : Details of our product (description.description_short => name_detail)
|
||||
* + description : Product description (description.description_full => description_full)
|
||||
* + billing_interval : Default Billing Interval
|
||||
* + billing_interval_string: Default Billing Interval in human-readable form
|
||||
* + setup_charge : Charge to setup this product
|
||||
@ -73,21 +74,10 @@ class Product extends Model implements IDs
|
||||
'pricing'=>'collection',
|
||||
];
|
||||
|
||||
protected $with = ['description'];
|
||||
protected $with = ['translate'];
|
||||
|
||||
/* RELATIONS */
|
||||
|
||||
/**
|
||||
* Get the product name in the users language, and if the user isnt logged in, the sites language
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function description()
|
||||
{
|
||||
return $this->hasOne(ProductTranslate::class)
|
||||
->where('language_id',(Auth::user() && Auth::user()->language_id) ? Auth::user()->language_id : config('site')->language_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Which services are configured with this product
|
||||
*
|
||||
@ -98,6 +88,17 @@ class Product extends Model implements IDs
|
||||
return $this->hasMany(Service::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product name in the users language, and if the user isnt logged in, the sites language
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function translate()
|
||||
{
|
||||
return $this->hasOne(ProductTranslate::class)
|
||||
->where('language_id',(Auth::user() && Auth::user()->language_id) ? Auth::user()->language_id : config('site')->language_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a child model with details of the service
|
||||
* This will return a product/* model.
|
||||
@ -211,6 +212,16 @@ class Product extends Model implements IDs
|
||||
return $this->type->getContractTermAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* This product full description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescriptionAttribute(): string
|
||||
{
|
||||
return (($x=$this->translate) && $x->description) ? $x->description : 'No Description';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum cost of this product
|
||||
*
|
||||
@ -243,7 +254,17 @@ class Product extends Model implements IDs
|
||||
*/
|
||||
public function getNameAttribute(): string
|
||||
{
|
||||
return $this->description ? $this->description->description_short : 'Unknown PRODUCT';
|
||||
return $this->getNameShortAttribute().(($x=$this->getNameDetailAttribute()) ? ': '.$x : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Our products Long Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNameDetailAttribute(): string
|
||||
{
|
||||
return $this->translate ? $this->translate->name_detail : 'Unknown Name';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -253,23 +274,13 @@ class Product extends Model implements IDs
|
||||
*/
|
||||
public function getNameShortAttribute(): string
|
||||
{
|
||||
return $this->description ? $this->description->name : 'Unknown PID';
|
||||
}
|
||||
|
||||
/**
|
||||
* This product full description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNameLongAttribute(): string
|
||||
{
|
||||
return $this->description->description_full;
|
||||
return $this->translate ? $this->translate->name_short : 'Unknown PID';
|
||||
}
|
||||
|
||||
/**
|
||||
* Suppliers
|
||||
*
|
||||
* @return Model
|
||||
* @return Model|null
|
||||
*/
|
||||
public function getSupplierAttribute(): ?Model
|
||||
{
|
||||
@ -279,7 +290,7 @@ class Product extends Model implements IDs
|
||||
/**
|
||||
* Suppliers product
|
||||
*
|
||||
* @return Model
|
||||
* @return Model|null
|
||||
*/
|
||||
public function getSuppliedAttribute(): ?Model
|
||||
{
|
||||
|
@ -6,12 +6,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ProductTranslate extends Model
|
||||
{
|
||||
protected $table = 'ab_product_translate';
|
||||
protected $table = 'product_translate';
|
||||
|
||||
public $timestamps = FALSE;
|
||||
|
||||
public function getDescriptionFullAttribute($value)
|
||||
{
|
||||
return unserialize($value);
|
||||
}
|
||||
}
|
@ -328,7 +328,7 @@ class User extends Authenticatable implements IDs
|
||||
}
|
||||
|
||||
$result->load([
|
||||
'product.description',
|
||||
'product.translate',
|
||||
'service.type',
|
||||
]);
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::statement('RENAME TABLE ab_product_translate TO product_translate');
|
||||
DB::statement('ALTER TABLE product_translate MODIFY product_id int unsigned DEFAULT NULL');
|
||||
DB::statement('ALTER TABLE product_translate MODIFY language_id int unsigned DEFAULT NULL');
|
||||
|
||||
DB::statement('ALTER TABLE product_translate RENAME COLUMN name TO name_short');
|
||||
DB::statement('ALTER TABLE product_translate RENAME COLUMN description_short TO name_detail');
|
||||
DB::statement('ALTER TABLE product_translate RENAME COLUMN description_full TO description');
|
||||
|
||||
Schema::table('product_translate', function (Blueprint $table) {
|
||||
$table->dropForeign('ab_product_translate_site_id_foreign');
|
||||
$table->dropIndex('ab_product_translate_id_site_id_index');
|
||||
$table->dropIndex('ab_product_translate_site_id_foreign');
|
||||
|
||||
$table->foreign(['language_id'])->references(['id'])->on('languages');
|
||||
$table->foreign(['product_id','site_id'])->references(['id','site_id'])->on('products');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
abort(500,'Cant go back');
|
||||
}
|
||||
};
|
@ -3,24 +3,56 @@
|
||||
<div class="col-12">
|
||||
<h3>Product Details @include('adminlte::widget.success_button')</h3>
|
||||
<hr>
|
||||
|
||||
|
||||
@dump($errors)
|
||||
<form class="g-0 needs-validation" method="POST" enctype="multipart/form-data" role="form">
|
||||
@csrf
|
||||
|
||||
<div class="row">
|
||||
<!-- Product Name -->
|
||||
<div class="col-12 col-sm-9 col-md-12 col-xl-6">
|
||||
<!-- Product ID -->
|
||||
<div class="col-12 col-sm-9 col-md-4 col-xl-3">
|
||||
@include('adminlte::widget.form_text',[
|
||||
'label'=>'Product Name',
|
||||
'label'=>'Product ID',
|
||||
'icon'=>'fas fa-atom',
|
||||
'id'=>'description.name',
|
||||
'old'=>'description.name',
|
||||
'name'=>'description[name]',
|
||||
'value'=>$o->name ?? '',
|
||||
'id'=>'translate.name_short',
|
||||
'old'=>'translate.name_short',
|
||||
'name'=>'translate[name_short]',
|
||||
'value'=>$o->name_short ?? '',
|
||||
])
|
||||
</div>
|
||||
|
||||
<!-- Product Name -->
|
||||
<div class="col-12 col-sm-9 col-md-8 col-xl-9">
|
||||
@include('adminlte::widget.form_text',[
|
||||
'label'=>'Product Name',
|
||||
'icon'=>'fas fa-atom',
|
||||
'id'=>'translate.name_detail',
|
||||
'old'=>'translate.name_detail',
|
||||
'name'=>'translate[name_detail]',
|
||||
'value'=>$o->name_detail ?? '',
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="form-group @error('description') is-invalid @enderror">
|
||||
<!-- Product Description -->
|
||||
<label for="description_full" class="col-form-label">Product Description</label>
|
||||
<div class="input-group">
|
||||
<div class="w-100">
|
||||
<textarea class="textarea" id="description" name="translate[description]" placeholder="Full Description">{!! old('description',$o->description) ?? '' !!}</textarea>
|
||||
<span class="invalid-feedback" role="alert">
|
||||
@error('description')
|
||||
{{ $message }}
|
||||
@enderror
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Active -->
|
||||
<div class="col-3">
|
||||
@include('adminlte::widget.form_toggle',[
|
||||
@ -43,7 +75,7 @@
|
||||
'old'=>'model',
|
||||
'name'=>'model',
|
||||
'options'=>$o->availableTypes()->transform(function($item) { return ['id'=>$item,'value'=>$item]; }),
|
||||
'value'=>get_class($o->type) ?? '',
|
||||
'value'=>($o->type && $x=get_class($o->type)) ? $x : '',
|
||||
])
|
||||
</div>
|
||||
</div>
|
||||
@ -97,7 +129,9 @@
|
||||
|
||||
@section('page-scripts')
|
||||
@css(select2)
|
||||
@css(simplemde)
|
||||
@js(select2,autofocus)
|
||||
@js(simplemde)
|
||||
|
||||
<script type="text/javascript">
|
||||
// Get a list of supplier items matching this type to populate model_id
|
||||
@ -129,6 +163,8 @@
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
new SimpleMDE({ element: $('.textarea')[0], forceSync: true });
|
||||
|
||||
$('#model').on('change',function(item) {
|
||||
if ($(this).val()) {
|
||||
$('#supplier_product').show();
|
||||
|
@ -8,7 +8,7 @@
|
||||
@endsection
|
||||
|
||||
@section('contentheader_title')
|
||||
Service: {{ $o->sid }} <strong>{{ $o->product->name }}</strong>
|
||||
Service: {{ $o->sid }} <strong>{{ $o->product->name_detail }}</strong>
|
||||
@endsection
|
||||
@section('contentheader_description')
|
||||
{{ $o->name }}
|
||||
|
@ -24,7 +24,7 @@
|
||||
<td><a href="{{ url('u/service',[$oo->id]) }}">{{ $oo->sid }}</a></td>
|
||||
<td>{{ $oo->product->category_name }}</td>
|
||||
<td>{{ $oo->name_short }}</td>
|
||||
<td>{{ $oo->product->name }}</td>
|
||||
<td>{{ $oo->product->name_short }}</td>
|
||||
<td>{{ $oo->external_billing ? '-' : $oo->invoice_next->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
@ -36,8 +36,8 @@
|
||||
@foreach($xx=$offering->items->with(['products.product.services'])->get() as $oo)
|
||||
<tr>
|
||||
<td>{{ $oo->id }}</td>
|
||||
<td>{{ $oo->name }}</td>
|
||||
<td>{{ $oo->name_long }}</td>
|
||||
<td>{{ $oo->name_short }}</td>
|
||||
<td>{{ $oo->name_detail }}</td>
|
||||
<td class="text-right">{{ $oo->active ? 'YES' : 'NO' }}</td>
|
||||
<td class="text-right">{{ number_format($oo->setup_cost_taxable,2) }}</td>
|
||||
<td class="text-right">{{ number_format($oo->base_cost_taxable,2) }}</td>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_long !!}</p>
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_long !!}</p>
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_long !!}</p>
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_long !!}</p>
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<!-- $o = Product::class -->
|
||||
<div class="col-md-12">
|
||||
<p>{!! $o->name_long !!}</p>
|
||||
<p>{!! $o->name_detail !!}</p>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
Loading…
Reference in New Issue
Block a user