Product Form - Add Custom Sub-Part
Forum rules
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Always add your Laravel, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Product Form - Add Custom Sub-Part
Hi,
Please, guide me how to add a new sub-part into Product edit form in Admin Dashboard? See screen-shot:
Regards!
Please, guide me how to add a new sub-part into Product edit form in Admin Dashboard? See screen-shot:
Regards!
Re: Product Form - Add Custom Sub-Part
Add a new implementation named after your project (not "Standard") in your own extension in this directory:
./admin/jqadm/src/Admin/JQAdm/Product/<subpart name>/<project name>.php
Implement the <project name>.php according to an existing class in the product subdirectories that fits your need best:
https://github.com/aimeos/ai-admin-jqad ... dm/Product
Add a template named ./admin/jqadm/templates/product/item-<subpart name>-<project name>.php in your own extension like one of these:
https://github.com/aimeos/ai-admin-jqad ... es/product
Configure the name of your new class in the ./config/admin.php file of your extension using ./admin/jqadm/product/<subpart name>/name like this one:
https://aimeos.org/docs/Configuration/C ... egory/name
Configure the new subpart name in the ./config/admin.php file of your extension:
https://aimeos.org/docs/Configuration/C ... d/subparts
./admin/jqadm/src/Admin/JQAdm/Product/<subpart name>/<project name>.php
Implement the <project name>.php according to an existing class in the product subdirectories that fits your need best:
https://github.com/aimeos/ai-admin-jqad ... dm/Product
Add a template named ./admin/jqadm/templates/product/item-<subpart name>-<project name>.php in your own extension like one of these:
https://github.com/aimeos/ai-admin-jqad ... es/product
Configure the name of your new class in the ./config/admin.php file of your extension using ./admin/jqadm/product/<subpart name>/name like this one:
https://aimeos.org/docs/Configuration/C ... egory/name
Configure the new subpart name in the ./config/admin.php file of your extension:
https://aimeos.org/docs/Configuration/C ... d/subparts
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,
![Image](https://aimeos.org/fileadmin/aimeos.org/icons/star.png)
Re: Product Form - Add Custom Sub-Part
Hi,aimeos wrote:Add a new implementation named after your project (not "Standard") in your own extension in this directory:
./admin/jqadm/src/Admin/JQAdm/Product/<subpart name>/<project name>.php
Implement the <project name>.php according to an existing class in the product subdirectories that fits your need best:
https://github.com/aimeos/ai-admin-jqad ... dm/Product
Add a template named ./admin/jqadm/templates/product/item-<subpart name>-<project name>.php in your own extension like one of these:
https://github.com/aimeos/ai-admin-jqad ... es/product
Configure the name of your new class in the ./config/admin.php file of your extension using ./admin/jqadm/product/<subpart name>/name like this one:
https://aimeos.org/docs/Configuration/C ... gory/namee
Configure the new subpart name in the ./config/admin.php file of your extension:
https://aimeos.org/docs/Configuration/C ... d/subparts
Thank you very much for the reply! I am again stuck! :'(
Anyhow, I have made changes in code according to your instructions but I am getting following error:
Class "\Aimeos\MShop\Salestax\Manager\Factory" not available
Please, look at my code below and correct me where I am doing wrong...
So, according to your 1st & 2nd instructions, I added a new implementation. Please, check code below...aimeos wrote: Add a new implementation named after your project (not "Standard") in your own extension in this directory:
./admin/jqadm/src/Admin/JQAdm/Product/<subpart name>/<project name>.php
Implement the <project name>.php according to an existing class in the product subdirectories that fits your need best:
https://github.com/aimeos/ai-admin-jqad ... dm/Product
./ext/myextension/admin/jqadm/src/Admin/JQAdm/Product/Salestax/Mysalestax.php
Code: Select all
namespace Aimeos\Admin\JQAdm\Product\Salestax;
sprintf('salestax'); // for translation
/**
* Default implementation of product salestax JQAdm client.
*
* @package Admin
* @subpackage JQAdm
*/
class Mysalestax
extends \Aimeos\Admin\JQAdm\Common\Admin\Factory\Base
implements \Aimeos\Admin\JQAdm\Common\Admin\Factory\Iface
{
private $subPartPath = 'admin/jqadm/product/salestax/mysalestax/subparts';
private $subPartNames = [];
/**
* Copies a resource
*
* @return string HTML output
*/
public function copy()
{
$view = $this->addViewData( $this->getView() );
$view->salestaxData = $this->toArray( $view->item, true );
$view->salestaxBody = '';
foreach( $this->getSubClients() as $client ) {
$view->salestaxBody .= $client->copy();
}
return $this->render( $view );
}
/**
* Creates a new resource
*
* @return string HTML output
*/
public function create()
{
$view = $this->addViewData( $this->getView() );
$siteid = $this->getContext()->getLocale()->getSiteId();
$data = $view->param( 'salestax', [] );
foreach( $view->value( $data, 'salestax.id', [] ) as $idx => $value ) {
$data['salestax.siteid'][$idx] = $siteid;
}
$view->salestaxData = $data;
$view->salestaxBody = '';
foreach( $this->getSubClients() as $client ) {
$view->salestaxBody .= $client->create();
}
return $this->render( $view );
}
/**
* Deletes a resource
*/
public function delete()
{
parent::delete();
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'salestax' );
$code = $this->getView()->item->getCode();
$search = $manager->createSearch()->setSlice( 0, 0x7fffffff );
$search->setConditions( $search->compare( '==', 'salestax.productcode', $code ) );
$manager->deleteItems( array_keys( $manager->searchItems( $search ) ) );
}
/**
* Returns a single resource
*
* @return string HTML output
*/
public function get()
{
$view = $this->addViewData( $this->getView() );
$view->salestaxData = $this->toArray( $view->item );
$view->salestaxBody = '';
foreach( $this->getSubClients() as $client ) {
$view->salestaxBody .= $client->get();
}
return $this->render( $view );
}
/**
* Saves the data
*/
public function save()
{
$view = $this->getView();
$context = $this->getContext();
$manager = \Aimeos\MShop\Factory::createManager( $context, 'salestax' );
$manager->begin();
try
{
$this->fromArray( $view->item, $view->param( 'salestax', [] ) );
$view->salestaxBody = '';
foreach( $this->getSubClients() as $client ) {
$view->salestaxBody .= $client->save();
}
$manager->commit();
return;
}
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'product-item-salestax' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'product-item-salestax' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
$manager->rollback();
throw new \Aimeos\Admin\JQAdm\Exception();
}
/**
* Returns the sub-client given by its name.
*
* @param string $type Name of the client type
* @param string|null $name Name of the sub-client (Default if null)
* @return \Aimeos\Admin\JQAdm\Iface Sub-client object
*/
public function getSubClient( $type, $name = null )
{
return $this->createSubClient( 'product/salestax/' . $type, $name );
}
/**
* Adds the required data used in the salestax template
*
* @param \Aimeos\MW\View\Iface $view View object
* @return \Aimeos\MW\View\Iface View object with assigned parameters
*/
protected function addViewData( \Aimeos\MW\View\Iface $view )
{
$typeManager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'salestax/type' );
$view->salestaxTypes = $typeManager->searchItems( $typeManager->createSearch() );
return $view;
}
/**
* Returns the list of sub-client names configured for the client.
*
* @return array List of JQAdm client names
*/
protected function getSubClientNames()
{
return $this->getContext()->getConfig()->get( $this->subPartPath, $this->subPartNames );
}
/**
* Creates new and updates existing items using the data array
*
* @param \Aimeos\MShop\Product\Item\Iface $item Product item object without referenced domain items
* @param string[] $data Data array
*/
protected function fromArray( \Aimeos\MShop\Product\Item\Iface $item, array $data )
{
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'salestax' );
$search = $manager->createSearch();
$search->setConditions( $search->compare( '==', 'salestax.productcode', $item->getCode() ) );
$salestaxItems = $manager->searchitems( $search );
$list = (array) $this->getValue( $data, 'salestax.id', [] );
$manager->deleteItems( array_diff( array_keys( $salestaxItems ), $list ) );
foreach( $list as $idx => $id )
{
if( !isset( $salestaxItems[$id] ) ) {
$salestaxItem = $manager->createItem();
} else {
$salestaxItem = $salestaxItems[$id];
}
$salestaxItem->setProductCode( $item->getCode() );
$salestaxItem->setTypeId( $this->getValue( $data, 'salestax.typeid/' . $idx ) );
$salestaxItem->setSalestaxlevel( $this->getValue( $data, 'salestax.salestaxlevel/' . $idx ) );
$salestaxItem->setDateBack( $this->getValue( $data, 'salestax.dateback/' . $idx ) );
$manager->saveItem( $salestaxItem, false );
}
}
/**
* Constructs the data array for the view from the given item
*
* @param \Aimeos\MShop\Product\Item\Iface $item Product item object including referenced domain items
* @param boolean $copy True if items should be copied, false if not
* @return string[] Multi-dimensional associative list of item data
*/
protected function toArray( \Aimeos\MShop\Product\Item\Iface $item, $copy = false )
{
$data = [];
$context = $this->getContext();
$siteId = $context->getLocale()->getSiteId();
$manager = \Aimeos\MShop\Factory::createManager( $context, 'salestax' );
$search = $manager->createSearch();
$search->setConditions( $search->compare( '==', 'salestax.productcode', $item->getCode() ) );
$search->setSortations( array( $search->sort( '+', 'salestax.type.code' ) ) );
foreach( $manager->searchItems( $search ) as $salestaxItem )
{
$list = $salestaxItem->toArray( true );
if( $copy === true )
{
$list['salestax.siteid'] = $siteId;
$list['salestax.id'] = '';
}
$list['salestax.dateback'] = str_replace( ' ', 'T', $list['salestax.dateback'] );
foreach( $list as $key => $value ) {
$data[$key][] = $value;
}
}
return $data;
}
/**
* Returns the rendered template including the view data
*
* @param \Aimeos\MW\View\Iface $view View object with data assigned
* @return string HTML output
*/
protected function render( \Aimeos\MW\View\Iface $view )
{
$tplconf = 'admin/jqadm/product/salestax/template-item';
$default = 'product/item-salestax-mysalestax.php';
return $view->render( $view->config( $tplconf, $default ) );
}
}
Following 3rd instructions. Please, check code below!aimeos wrote: Add a template named ./admin/jqadm/templates/product/item-<subpart name>-<project name>.php in your own extension like one of these:
https://github.com/aimeos/ai-admin-jqad ... es/product
./ext/myextension/admin/jqadm/templates/product/item-salestax-mysalestax.php
Code: Select all
$enc = $this->encoder();
$salestaxTypes = $this->get( 'salestaxTypes', [] );
$keys = ['salestax.id', 'salestax.siteid', 'salestax.typeid', 'salestax.salestaxlevel', 'salestax.dateback'];
?>
<div id="salestax" class="item-salestax content-block tab-pane fade" role="tabpanel" aria-labelledby="salestax">
<table class="salestax-list table table-default"
data-items="<?= $enc->attr( json_encode( $this->get( 'salestaxData', [] ) ) ); ?>"
data-keys="<?= $enc->attr( json_encode( $keys ) ) ?>"
data-prefix="salestax."
data-siteid="<?= $this->site()->siteid() ?>"
data-numtypes="<?= count( $salestaxTypes ) ?>" >
<thead>
<tr>
<?php if( count( $salestaxTypes ) > 1 ) : ?>
<th class="salestax-type">
<span class="help"><?= $enc->html( $this->translate( 'admin', 'Type' ) ); ?></span>
<div class="form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Warehouse or local store if your articles are available at several locations' ) ); ?>
</div>
</th>
<?php endif; ?>
<th class="salestax-salestaxlevel">
<span class="help"><?= $enc->html( $this->translate( 'admin', 'Salestax level' ) ); ?></span>
<div class="form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Number of articles currently in salestax, leave empty for an unlimited quantity' ) ); ?>
</div>
</th>
<th class="salestax-databack">
<span class="help"><?= $enc->html( $this->translate( 'admin', 'Back in salestax' ) ); ?></span>
<div class="form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Shown if the article reached a salestax level of zero' ) ); ?>
</div>
</th>
<th class="actions">
<div v-if="(items['salestax.id'] || []).length < numtypes" class="btn act-add fa" tabindex="<?= $this->get( 'tabindex' ); ?>"
title="<?= $enc->attr( $this->translate( 'admin', 'Insert new entry (Ctrl+I)') ); ?>"
v-on:click="addItem()">
</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(id, idx) in items['salestax.id']" v-bind:key="idx" class="salestax-row">
<?php if( count( $salestaxTypes ) > 1 ) : ?>
<td class="salestax-type mandatory">
<select class="form-control custom-select item-typeid" required="required" tabindex="<?= $this->get( 'tabindex' ); ?>"
name="<?= $enc->attr( $this->formparam( array( 'salestax', 'salestax.typeid', '' ) ) ); ?>"
v-bind:readonly="checkSite('salestax.siteid', idx)"
v-model="items['salestax.typeid'][idx]" >
<option value="" disable>
<?= $enc->html( $this->translate( 'admin', 'Please select' ) ); ?>
</option>
<?php foreach( $salestaxTypes as $typeId => $typeItem ) : ?>
<option value="<?= $enc->attr( $typeId ); ?>" v-bind:selected="items['salestax.typeid'][idx] == '<?= $enc->attr( $typeId ) ?>'">
<?= $enc->html( $typeItem->getLabel() ) ?>
</option>
<?php endforeach; ?>
</select>
</td>
<?php else : ?>
<input class="item-typeid" type="hidden"
name="<?= $enc->attr( $this->formparam( array( 'salestax', 'salestax.typeid', '' ) ) ); ?>"
value="<?= $enc->attr( key( $salestaxTypes ) ); ?>" />
<?php endif; ?>
<td class="salestax-salestaxlevel optional">
<input class="form-control item-salestaxlevel" type="number" step="1" min="0" tabindex="<?= $this->get( 'tabindex' ); ?>"
name="<?= $enc->attr( $this->formparam( array( 'salestax', 'salestax.salestaxlevel', '' ) ) ); ?>"
v-bind:readonly="checkSite('salestax.siteid', idx)"
v-model="items['salestax.salestaxlevel'][idx]" />
</td>
<td class="salestax-databack optional">
<input class="form-control item-dateback" type="datetime-local" tabindex="<?= $this->get( 'tabindex' ); ?>"
name="<?= $enc->attr( $this->formparam( array( 'salestax', 'salestax.dateback', '' ) ) ); ?>"
placeholder="<?= $enc->attr( $this->translate( 'admin', 'YYYY-MM-DD hh:mm:ss (optional)' ) ); ?>"
v-bind:readonly="checkSite('salestax.siteid', idx)"
v-model="items['salestax.dateback'][idx]" />
</td>
<td class="actions">
<input class="item-id" type="hidden" v-model="items['salestax.id'][idx]"
name="<?= $enc->attr( $this->formparam( array( 'salestax', 'salestax.id', '' ) ) ); ?>" />
<div v-if="!checkSite('salestax.siteid', idx)" class="btn act-delete fa" tabindex="<?= $this->get( 'tabindex' ); ?>"
title="<?= $enc->attr( $this->translate( 'admin', 'Delete this entry') ); ?>"
v-on:click.stop="removeItem(idx)">
</div>
</td>
</tr>
</tbody>
</table>
<?= $this->get( 'salestaxBody' ); ?>
</div>
./ext/myextension/config/admin.phpaimeos wrote: Configure the name of your new class in the ./config/admin.php file of your extension using ./admin/jqadm/product/<subpart name>/name like this one:
https://aimeos.org/docs/Configuration/C ... gory/namee
Configure the new subpart name in the ./config/admin.php file of your extension:
https://aimeos.org/docs/Configuration/C ... d/subparts
Code: Select all
return [
'jqadm' => [
'product' => array(
'salestax' => array(
'name' => 'Mysalestax'
),
'standard' => array(
'subparts' => array(
'selection',
'bundle',
'image',
'text',
'price',
'stock',
'category',
'characteristic',
'option',
'related',
'physical',
'download',
'subscription',
'special',
'salestax'
)
)
)
],
'jsonadm' => [
],
];
Thanks!
Re: Product Form - Add Custom Sub-Part
Where is the sales tax data stored? You are trying to use a new manager that doesn't exist yet.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,
![Image](https://aimeos.org/fileadmin/aimeos.org/icons/star.png)
Re: Product Form - Add Custom Sub-Part
Hi,aimeos wrote:Where is the sales tax data stored? You are trying to use a new manager that doesn't exist yet.
Thanks for reply! Sales Tax data is not stored anywhere because there was no form to insert data. Plus, I have created a Schema file (see below) but this file doesn't create a new table when I run "php artisan aimeos:setup."
./ext/myextension/lib/custom/setup/default/schema/salestax.php
Code: Select all
return array(
'table' => array(
'mshop_salestax_type' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->createTable( 'mshop_salestax_type' );
$table->addColumn( 'id', 'integer', array( 'autoincrement' => true ) );
$table->addColumn( 'siteid', 'integer', [] );
$table->addColumn( 'domain', 'string', array( 'length' => 32 ) );
$table->addColumn( 'code', 'string', array( 'length' => 32 ) );
$table->addColumn( 'label', 'string', array( 'length' => 255 ) );
$table->addColumn( 'status', 'smallint', [] );
$table->addColumn( 'mtime', 'datetime', [] );
$table->addColumn( 'ctime', 'datetime', [] );
$table->addColumn( 'editor', 'string', array( 'length' => 255 ) );
$table->setPrimaryKey( array( 'id' ), 'pk_msstoty_id' );
$table->addUniqueIndex( array( 'siteid', 'domain', 'code' ), 'unq_msstoty_sid_dom_code' );
$table->addIndex( array( 'siteid', 'status' ), 'idx_msstoty_sid_status' );
$table->addIndex( array( 'siteid', 'label' ), 'idx_msstoty_sid_label' );
$table->addIndex( array( 'siteid', 'code' ), 'idx_msstoty_sid_code' );
return $schema;
},
'mshop_salestax' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->createTable( 'mshop_salestax' );
$table->addColumn( 'id', 'integer', array( 'autoincrement' => true ) );
$table->addColumn( 'siteid', 'integer', [] );
$table->addColumn( 'typeid', 'integer', [] );
$table->addColumn( 'productcode', 'string', array( 'length' => 32 ) );
$table->addColumn( 'salestaxlevel', 'integer', array( 'notnull' => false ) );
$table->addColumn( 'backdate', 'datetime', array( 'notnull' => false ) );
$table->addColumn( 'mtime', 'datetime', [] );
$table->addColumn( 'ctime', 'datetime', [] );
$table->addColumn( 'editor', 'string', array( 'length' => 255 ) );
$table->setPrimaryKey( array( 'id' ), 'pk_mssto_id' );
$table->addUniqueIndex( array( 'siteid', 'productcode', 'typeid' ), 'unq_mssto_sid_pcode_tid' );
$table->addIndex( array( 'siteid', 'salestaxlevel' ), 'idx_mssto_sid_salestaxlevel' );
$table->addIndex( array( 'siteid', 'backdate' ), 'idx_mssto_sid_backdate' );
$table->addIndex( array( 'typeid' ), 'fk_mssto_typeid' );
$table->addForeignKeyConstraint( 'mshop_salestax_type', array( 'typeid' ), array( 'id' ),
array( 'onUpdate' => 'CASCADE', 'onDelete' => 'CASCADE' ), 'fk_mssto_typeid' );
return $schema;
},
),
);
Thanks!
Re: Product Form - Add Custom Sub-Part
Hi,aimeos wrote:Where is the sales tax data stored? You are trying to use a new manager that doesn't exist yet.
How I can create this new manager? Please, explain in details because there is no resource available on internet.
Thanks!
Re: Product Form - Add Custom Sub-Part
For creating tables in new domains, you should read this:
https://aimeos.org/docs/Developers/Libr ... ew_domains
To create new managers and items for a new domains, you can copy/paste code from an existing domain. The stock domain fits best in your case:
https://github.com/aimeos/aimeos-core/t ... Shop/Stock
https://aimeos.org/docs/Developers/Libr ... ew_domains
To create new managers and items for a new domains, you can copy/paste code from an existing domain. The stock domain fits best in your case:
https://github.com/aimeos/aimeos-core/t ... Shop/Stock
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,
![Image](https://aimeos.org/fileadmin/aimeos.org/icons/star.png)
Re: Product Form - Add Custom Sub-Part
Hi,aimeos wrote:For creating tables in new domains, you should read this:
https://aimeos.org/docs/Developers/Libr ... ew_domains
To create new managers and items for a new domains, you can copy/paste code from an existing domain. The stock domain fits best in your case:
https://github.com/aimeos/aimeos-core/t ... Shop/Stock
Thanks for the reply! I shall implement this and will let you know if I still struggle.
Thanks!
Re: Product Form - Add Custom Sub-Part
Hello,
Can you tell me if the location for the new manager has to be done like this:
ext/<MYEXTENSION>/lib/mshoplib/src/MShop/<MYMANAGER>
Oops, sorry I found the answer there:
https://aimeos.org/docs/Developers/Libr ... gers_items
Thank you a lot !
sbn
Can you tell me if the location for the new manager has to be done like this:
ext/<MYEXTENSION>/lib/mshoplib/src/MShop/<MYMANAGER>
Oops, sorry I found the answer there:
https://aimeos.org/docs/Developers/Libr ... gers_items
Thank you a lot !
sbn
Re: Product Form - Add Custom Sub-Part
Hi,sixbynine wrote:Hello,
Can you tell me if the location for the new manager has to be done like this:
ext/<MYEXTENSION>/lib/mshoplib/src/MShop/<MYMANAGER>
Oops, sorry I found the answer there:
https://aimeos.org/docs/Developers/Libr ... gers_items
Thank you a lot !
sbn
So, you solved your problem? Sorry, I was busy on other stuff and couldn't reply you earlier.
Thanks!