Rework on product name/description and translate

This commit is contained in:
Deon George 2022-10-18 23:23:45 +11:00
parent bfd17b0686
commit b719efb58c
15 changed files with 148 additions and 62 deletions

View File

@ -84,7 +84,7 @@ class ProductController extends Controller
public function details_addedit(ProductAddEdit $request,Product $o) 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->{$key} = $item;
$o->active = (bool)$request->active; $o->active = (bool)$request->active;
@ -95,13 +95,12 @@ class ProductController extends Controller
return redirect()->back()->withErrors($e->getMessage())->withInput(); return redirect()->back()->withErrors($e->getMessage())->withInput();
} }
$o->load(['description']); $o->load(['translate']);
$oo = $o->description ?: new ProductTranslate; $oo = $o->translate ?: new ProductTranslate;
foreach ($request->get('translate',[]) as $key => $item)
foreach ($request->get('description',[]) as $key => $item)
$oo->{$key} = $item; $oo->{$key} = $item;
$o->description()->save($oo); $o->translate()->save($oo);
return redirect()->back() return redirect()->back()
->with('success','Product saved'); ->with('success','Product saved');

View File

@ -28,7 +28,9 @@ class ProductAddEdit extends FormRequest
public function rules() public function rules()
{ {
return [ 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', 'active' => 'sometimes|accepted',
'model' => 'sometimes|string', // @todo Check that it is a valid model type '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 'model_id' => 'sometimes|int', // @todo Check that it is a valid model type

View File

@ -31,9 +31,10 @@ use App\Traits\{ProductDetails,SiteID};
* + category_name : Type of product supplied (Friendly Name for display, not for internal logic) * + category_name : Type of product supplied (Friendly Name for display, not for internal logic)
* + supplied : Supplier product provided for this offering * + supplied : Supplier product provided for this offering
* + supplier : Supplier 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 : Brief Name for our product with name_detail
* + name_short : Product ID for our Product * + name_short : Product ID for our Product (description.name => name_short)
* + name_long : Long Name for our product * + 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 : Default Billing Interval
* + billing_interval_string: Default Billing Interval in human-readable form * + billing_interval_string: Default Billing Interval in human-readable form
* + setup_charge : Charge to setup this product * + setup_charge : Charge to setup this product
@ -73,21 +74,10 @@ class Product extends Model implements IDs
'pricing'=>'collection', 'pricing'=>'collection',
]; ];
protected $with = ['description']; protected $with = ['translate'];
/* RELATIONS */ /* 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 * Which services are configured with this product
* *
@ -98,6 +88,17 @@ class Product extends Model implements IDs
return $this->hasMany(Service::class); 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 * Return a child model with details of the service
* This will return a product/* model. * This will return a product/* model.
@ -211,6 +212,16 @@ class Product extends Model implements IDs
return $this->type->getContractTermAttribute(); 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 * Get the minimum cost of this product
* *
@ -243,7 +254,17 @@ class Product extends Model implements IDs
*/ */
public function getNameAttribute(): string 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 public function getNameShortAttribute(): string
{ {
return $this->description ? $this->description->name : 'Unknown PID'; return $this->translate ? $this->translate->name_short : 'Unknown PID';
}
/**
* This product full description
*
* @return string
*/
public function getNameLongAttribute(): string
{
return $this->description->description_full;
} }
/** /**
* Suppliers * Suppliers
* *
* @return Model * @return Model|null
*/ */
public function getSupplierAttribute(): ?Model public function getSupplierAttribute(): ?Model
{ {
@ -279,7 +290,7 @@ class Product extends Model implements IDs
/** /**
* Suppliers product * Suppliers product
* *
* @return Model * @return Model|null
*/ */
public function getSuppliedAttribute(): ?Model public function getSuppliedAttribute(): ?Model
{ {

View File

@ -6,12 +6,7 @@ use Illuminate\Database\Eloquent\Model;
class ProductTranslate extends Model class ProductTranslate extends Model
{ {
protected $table = 'ab_product_translate'; protected $table = 'product_translate';
public $timestamps = FALSE; public $timestamps = FALSE;
public function getDescriptionFullAttribute($value)
{
return unserialize($value);
}
} }

View File

@ -328,7 +328,7 @@ class User extends Authenticatable implements IDs
} }
$result->load([ $result->load([
'product.description', 'product.translate',
'service.type', 'service.type',
]); ]);

View File

@ -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');
}
};

View File

@ -3,24 +3,56 @@
<div class="col-12"> <div class="col-12">
<h3>Product Details @include('adminlte::widget.success_button')</h3> <h3>Product Details @include('adminlte::widget.success_button')</h3>
<hr> <hr>
@dump($errors)
<form class="g-0 needs-validation" method="POST" enctype="multipart/form-data" role="form"> <form class="g-0 needs-validation" method="POST" enctype="multipart/form-data" role="form">
@csrf @csrf
<div class="row"> <div class="row">
<!-- Product Name --> <!-- Product ID -->
<div class="col-12 col-sm-9 col-md-12 col-xl-6"> <div class="col-12 col-sm-9 col-md-4 col-xl-3">
@include('adminlte::widget.form_text',[ @include('adminlte::widget.form_text',[
'label'=>'Product Name', 'label'=>'Product ID',
'icon'=>'fas fa-atom', 'icon'=>'fas fa-atom',
'id'=>'description.name', 'id'=>'translate.name_short',
'old'=>'description.name', 'old'=>'translate.name_short',
'name'=>'description[name]', 'name'=>'translate[name_short]',
'value'=>$o->name ?? '', 'value'=>$o->name_short ?? '',
]) ])
</div> </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 --> <!-- Active -->
<div class="col-3"> <div class="col-3">
@include('adminlte::widget.form_toggle',[ @include('adminlte::widget.form_toggle',[
@ -43,7 +75,7 @@
'old'=>'model', 'old'=>'model',
'name'=>'model', 'name'=>'model',
'options'=>$o->availableTypes()->transform(function($item) { return ['id'=>$item,'value'=>$item]; }), '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>
</div> </div>
@ -97,7 +129,9 @@
@section('page-scripts') @section('page-scripts')
@css(select2) @css(select2)
@css(simplemde)
@js(select2,autofocus) @js(select2,autofocus)
@js(simplemde)
<script type="text/javascript"> <script type="text/javascript">
// Get a list of supplier items matching this type to populate model_id // Get a list of supplier items matching this type to populate model_id
@ -129,6 +163,8 @@
} }
$(document).ready(function() { $(document).ready(function() {
new SimpleMDE({ element: $('.textarea')[0], forceSync: true });
$('#model').on('change',function(item) { $('#model').on('change',function(item) {
if ($(this).val()) { if ($(this).val()) {
$('#supplier_product').show(); $('#supplier_product').show();

View File

@ -8,7 +8,7 @@
@endsection @endsection
@section('contentheader_title') @section('contentheader_title')
Service: {{ $o->sid }} <strong>{{ $o->product->name }}</strong> Service: {{ $o->sid }} <strong>{{ $o->product->name_detail }}</strong>
@endsection @endsection
@section('contentheader_description') @section('contentheader_description')
{{ $o->name }} {{ $o->name }}

View File

@ -24,7 +24,7 @@
<td><a href="{{ url('u/service',[$oo->id]) }}">{{ $oo->sid }}</a></td> <td><a href="{{ url('u/service',[$oo->id]) }}">{{ $oo->sid }}</a></td>
<td>{{ $oo->product->category_name }}</td> <td>{{ $oo->product->category_name }}</td>
<td>{{ $oo->name_short }}</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> <td>{{ $oo->external_billing ? '-' : $oo->invoice_next->format('Y-m-d') }}</td>
</tr> </tr>
@endforeach @endforeach

View File

@ -36,8 +36,8 @@
@foreach($xx=$offering->items->with(['products.product.services'])->get() as $oo) @foreach($xx=$offering->items->with(['products.product.services'])->get() as $oo)
<tr> <tr>
<td>{{ $oo->id }}</td> <td>{{ $oo->id }}</td>
<td>{{ $oo->name }}</td> <td>{{ $oo->name_short }}</td>
<td>{{ $oo->name_long }}</td> <td>{{ $oo->name_detail }}</td>
<td class="text-right">{{ $oo->active ? 'YES' : 'NO' }}</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->setup_cost_taxable,2) }}</td>
<td class="text-right">{{ number_format($oo->base_cost_taxable,2) }}</td> <td class="text-right">{{ number_format($oo->base_cost_taxable,2) }}</td>

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class --> <!-- $o = Product::class -->
<div class="col-md-12"> <div class="col-md-12">
<p>{!! $o->name_long !!}</p> <p>{!! $o->name_detail !!}</p>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class --> <!-- $o = Product::class -->
<div class="col-md-12"> <div class="col-md-12">
<p>{!! $o->name_long !!}</p> <p>{!! $o->name_detail !!}</p>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class --> <!-- $o = Product::class -->
<div class="col-md-12"> <div class="col-md-12">
<p>{!! $o->name_long !!}</p> <p>{!! $o->name_detail !!}</p>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class --> <!-- $o = Product::class -->
<div class="col-md-12"> <div class="col-md-12">
<p>{!! $o->name_long !!}</p> <p>{!! $o->name_detail !!}</p>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -1,6 +1,6 @@
<!-- $o = Product::class --> <!-- $o = Product::class -->
<div class="col-md-12"> <div class="col-md-12">
<p>{!! $o->name_long !!}</p> <p>{!! $o->name_detail !!}</p>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">