summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xedit.php80
-rwxr-xr-xincludes/classes/StockAssembly.php25
-rwxr-xr-xtemplates/edit_assembly.tpl73
-rwxr-xr-xtemplates/view_assembly.tpl8
4 files changed, 184 insertions, 2 deletions
diff --git a/edit.php b/edit.php
index d48ec6f..74655d9 100755
--- a/edit.php
+++ b/edit.php
@@ -12,7 +12,7 @@ namespace Bitweaver\Stock;
require_once '../kernel/includes/setup_inc.php';
use Bitweaver\KernelTools;
-global $gBitSystem;
+global $gBitSystem, $gBitDb;
include_once LIBERTY_PKG_INCLUDE_PATH.'liberty_lib.php';
include_once STOCK_PKG_INCLUDE_PATH.'assembly_lookup_inc.php';
@@ -61,11 +61,89 @@ if( !empty( $_REQUEST['savegallery'] ) ) {
} elseif( !empty($_REQUEST['cancelgallery'] ) ) {
header( 'Location: '.$gContent->getDisplayUrl() );
die();
+
+} elseif( $gContent->isValid() && !empty( $_REQUEST['add_component'] ) ) {
+ $title = trim( $_REQUEST['component_title'] ?? '' );
+ if( $title !== '' ) {
+ $row = $gBitDb->getRow(
+ "SELECT lc.`content_id` FROM `".BIT_DB_PREFIX."liberty_content` lc
+ WHERE UPPER(lc.`title`) = UPPER(?) AND lc.`content_type_guid` = 'stockcomponent'",
+ [ $title ]
+ );
+ if( $row ) {
+ $nextPos = ((int)$gBitDb->getOne(
+ "SELECT MAX(`item_position`) FROM `".BIT_DB_PREFIX."stock_assembly_component_map` WHERE `assembly_content_id`=?",
+ [ $gContent->mContentId ]
+ )) + 1;
+ if( !$gContent->addItem( $row['content_id'], $nextPos ) ) {
+ $stockErrors[] = KernelTools::tra('Component already in this assembly:').' '.htmlspecialchars($title);
+ }
+ } else {
+ $stockErrors[] = KernelTools::tra('Component not found:').' '.htmlspecialchars($title);
+ }
+ }
+ if( empty( $stockErrors ) ) {
+ header( 'Location: '.STOCK_PKG_URL.'edit.php?content_id='.$gContent->mContentId );
+ die();
+ }
+
+} elseif( $gContent->isValid() && !empty( $_REQUEST['upload_components_csv'] ) ) {
+ $csvLoaded = $csvSkipped = 0;
+ $csvErrors = [];
+ if( !empty( $_FILES['csv_file']['tmp_name'] ) && is_uploaded_file( $_FILES['csv_file']['tmp_name'] ) ) {
+ $nextPos = ((int)$gBitDb->getOne(
+ "SELECT MAX(`item_position`) FROM `".BIT_DB_PREFIX."stock_assembly_component_map` WHERE `assembly_content_id`=?",
+ [ $gContent->mContentId ]
+ )) + 1;
+ if( ($fh = fopen( $_FILES['csv_file']['tmp_name'], 'r' )) !== false ) {
+ while( ($cols = fgetcsv($fh)) !== false ) {
+ $title = trim($cols[0]);
+ if( $title === '' || strtolower($title) === 'title' ) continue;
+ $row = $gBitDb->getRow(
+ "SELECT lc.`content_id` FROM `".BIT_DB_PREFIX."liberty_content` lc
+ WHERE UPPER(lc.`title`) = UPPER(?) AND lc.`content_type_guid` = 'stockcomponent'",
+ [ $title ]
+ );
+ if( $row ) {
+ if( $gContent->addItem( $row['content_id'], $nextPos ) ) {
+ $nextPos++;
+ $csvLoaded++;
+ } else {
+ $csvSkipped++;
+ }
+ } else {
+ $csvErrors[] = KernelTools::tra('Not found:').' '.htmlspecialchars($title);
+ }
+ }
+ fclose($fh);
+ }
+ }
+ $gBitSmarty->assign( 'csvLoaded', $csvLoaded );
+ $gBitSmarty->assign( 'csvSkipped', $csvSkipped );
+ $gBitSmarty->assign( 'csvErrors', $csvErrors );
+
+} elseif( $gContent->isValid() ) {
+ foreach( $_REQUEST as $k => $v ) {
+ if( preg_match( '/^remove_component_(\d+)$/', $k, $m ) ) {
+ $gContent->removeItem( (int)$m[1] );
+ header( 'Location: '.STOCK_PKG_URL.'edit.php?content_id='.$gContent->mContentId );
+ die();
+ }
+ }
}
// Initalize the errors list which contains any errors which occured during storage
$errors = !empty($gContent->mErrors) ? $gContent->mErrors : [];
$gBitSmarty->assign('errors', $errors);
+if( !empty($stockErrors) ) {
+ $gBitSmarty->assign('stockWarnings', $stockErrors);
+}
+
+if( $gContent->isValid() ) {
+ $sortMode = $_REQUEST['sort_mode'] ?? 'item_position_asc';
+ $gBitSmarty->assign( 'componentMap', $gContent->getComponentMapList($sortMode) );
+ $gBitSmarty->assign( 'sortMode', $sortMode );
+}
$gContent->mInfo['stockassembly_types'] = $gContent->getXrefGroupList();
diff --git a/includes/classes/StockAssembly.php b/includes/classes/StockAssembly.php
index f0cd5f3..3d11e64 100755
--- a/includes/classes/StockAssembly.php
+++ b/includes/classes/StockAssembly.php
@@ -495,6 +495,31 @@ class StockAssembly extends StockBase {
return count($this->mErrors) == 0;
}
+ public function getComponentMapList( string $pSortMode = 'item_position_asc' ): array {
+ $ret = [];
+ if( $this->verifyId( $this->mContentId ) ) {
+ $orderby = match( $pSortMode ) {
+ 'title_asc' => 'lc.`title` ASC',
+ 'title_desc' => 'lc.`title` DESC',
+ 'item_position_desc' => 'fgim.`item_position` DESC, fgim.`item_content_id` DESC',
+ default => 'fgim.`item_position` ASC, fgim.`item_content_id` ASC',
+ };
+ if( $rows = $this->mDb->query(
+ "SELECT fgim.`item_content_id`, fgim.`item_position`, lc.`title`
+ FROM `".BIT_DB_PREFIX."stock_assembly_component_map` fgim
+ INNER JOIN `".BIT_DB_PREFIX."liberty_content` lc ON (lc.`content_id` = fgim.`item_content_id`)
+ WHERE fgim.`assembly_content_id` = ?
+ ORDER BY $orderby",
+ [ $this->mContentId ]
+ ) ) {
+ foreach( $rows as $row ) {
+ $ret[$row['item_content_id']] = $row;
+ }
+ }
+ }
+ return $ret;
+ }
+
public function removeItem( $pContentId ) {
$ret = false;
if( $this->isValid() && @$this->verifyId( $pContentId ) ) {
diff --git a/templates/edit_assembly.tpl b/templates/edit_assembly.tpl
index 8ace0d9..4adec06 100755
--- a/templates/edit_assembly.tpl
+++ b/templates/edit_assembly.tpl
@@ -50,6 +50,79 @@
</div>
{/form}
+ {* ── Components section ── *}
+ {if $gContent->isValid()}
+ <hr/>
+ <h3>{tr}Components{/tr}</h3>
+
+ {* CSV upload results *}
+ {if isset($csvLoaded)}
+ <div class="alert alert-info">
+ {tr}Loaded{/tr}: <strong>{$csvLoaded}</strong>
+ {if $csvSkipped} &nbsp; {tr}Skipped (duplicate){/tr}: <strong>{$csvSkipped}</strong>{/if}
+ </div>
+ {if $csvErrors}
+ <ul class="text-warning">
+ {foreach from=$csvErrors item=msg}<li>{$msg|escape}</li>{/foreach}
+ </ul>
+ {/if}
+ {/if}
+
+ {* Components table *}
+ {if $componentMap}
+ {form ipackage="stock" ifile="edit.php"}
+ <input type="hidden" name="content_id" value="{$gContent->mContentId|escape}"/>
+ <table class="table table-condensed table-striped">
+ <thead>
+ <tr>
+ <th>{smartlink ititle="Pos" isort="item_position" ifile="edit.php" ipackage="stock" idefault=1 content_id=$gContent->mContentId}</th>
+ <th>{smartlink ititle="Component" isort="title" ifile="edit.php" ipackage="stock" content_id=$gContent->mContentId}</th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ {foreach from=$componentMap key=contentId item=comp}
+ <tr>
+ <td>{$comp.item_position|escape}</td>
+ <td>{$comp.title|escape}</td>
+ <td>
+ <input type="submit" class="btn btn-xs btn-default"
+ name="remove_component_{$contentId}" value="{tr}Remove{/tr}"/>
+ </td>
+ </tr>
+ {/foreach}
+ </tbody>
+ </table>
+ {/form}
+ {else}
+ <p class="muted">{tr}No components yet.{/tr}</p>
+ {/if}
+
+ {* ── Add single component ── *}
+ <h4>{tr}Add Component{/tr}</h4>
+ {form ipackage="stock" ifile="edit.php"}
+ <input type="hidden" name="content_id" value="{$gContent->mContentId|escape}"/>
+ <div class="form-inline">
+ <div class="form-group">
+ <input type="text" class="form-control" name="component_title"
+ placeholder="{tr}Component title{/tr}" size="40"/>
+ </div>
+ <input type="submit" class="btn btn-default" name="add_component" value="{tr}Add{/tr}"/>
+ </div>
+ {/form}
+
+ {* ── Upload CSV ── *}
+ <h4>{tr}Upload Components CSV{/tr}</h4>
+ <p class="help-block">{tr}One component title per line (or comma-separated with title in first column).{/tr}</p>
+ {form enctype="multipart/form-data" ipackage="stock" ifile="edit.php"}
+ <input type="hidden" name="content_id" value="{$gContent->mContentId|escape}"/>
+ <div class="form-inline">
+ <input type="file" name="csv_file" accept=".csv,text/csv"/>
+ <input type="submit" class="btn btn-default" name="upload_components_csv" value="{tr}Upload{/tr}"/>
+ </div>
+ {/form}
+ {/if}
+
</div><!-- end .body -->
</div><!-- end .stock -->
{/strip}
diff --git a/templates/view_assembly.tpl b/templates/view_assembly.tpl
index f5e850c..bba6f74 100755
--- a/templates/view_assembly.tpl
+++ b/templates/view_assembly.tpl
@@ -1,4 +1,9 @@
{assign var=galLayout value=$gContent->getLayout()}
+{if $gBitUser->hasPermission('p_stock_update')}
+ <div class="floaticon">
+ <a title="{tr}Edit{/tr}" href="{$smarty.const.STOCK_PKG_URL}edit.php?content_id={$gContent->mContentId}">{booticon iname="fa-pen-to-square" iexplain="Edit Assembly"}</a>
+ </div>
+{/if}
{include file="`$smarty.const.STOCK_PKG_PATH`assembly_views/`$galLayout`/stock_`$galLayout`_inc.tpl"}
{if $gContent->mInfo.stockassembly_types}
@@ -7,7 +12,8 @@
{include file="bitpackage:liberty/list_xref.tpl"
source=$gContent->mInfo.stockassembly_types[xrefGroup].source
source_title=$gContent->mInfo.stockassembly_types[xrefGroup].title
- group=$gContent->mInfo.stockassembly_types[xrefGroup].sort_order}
+ group=$gContent->mInfo.stockassembly_types[xrefGroup].sort_order
+ allow_edit=false}
{/section}
{/jstabs}
{/if}