diff options
| author | Lester Caine <lester@lsces.co.uk> | 2026-06-14 10:49:24 +0100 |
|---|---|---|
| committer | Lester Caine <lester@lsces.co.uk> | 2026-06-14 10:49:24 +0100 |
| commit | e8aa652c4f0d2f780171d7bbd2c351c05a1025e9 (patch) | |
| tree | 2ee249d771ee88e7d3d1cc209a3048fd37161b56 | |
| parent | 3866f6c02cfae647d04e9123392b608e0d0aa3a6 (diff) | |
| download | stock-e8aa652c4f0d2f780171d7bbd2c351c05a1025e9.tar.gz stock-e8aa652c4f0d2f780171d7bbd2c351c05a1025e9.tar.bz2 stock-e8aa652c4f0d2f780171d7bbd2c351c05a1025e9.zip | |
Add multi-user (kitelf) stock filtering and PBLD prebuild movement type
- list_movements/list_stock: filter by user_id (kitelf) with breadcrumb
navigation; creator names in list_movements are clickable filter links
- list_movements: unified part_content_id replaces separate
assembly_content_id/component_content_id URL params; type-aware
breadcrumb and qty column (assembly kit count vs component qty)
- StockMovement::getList(): $partId/$partIsAsm collapse cmp/asm into one
variable; unified part_qty/part_qty_type SELECT; PBLD added to all
ref_type IN() lists and sort subqueries; lc.user_id added to SELECT
- New PBLD (Prebuild) movement type: add_prebuild.php/tpl creates PBLD
movements (assemblies only, BOM exploded, optional note); add_requisition
retired from UI; PBLD handled in edit/view with isBuild/isPbld flags;
view/edit show Build Date/Completed labels for PBLD
- schema_inc.php: PBLD registered in stockmovement reference xref items
- view_movement.tpl: updated to <header>/<section> pattern with kitelf
breadcrumb; getDirection() explicit for PBLD
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rw-r--r-- | add_prebuild.php | 112 | ||||
| -rwxr-xr-x | admin/schema_inc.php | 3 | ||||
| -rw-r--r-- | edit_movement.php | 13 | ||||
| -rw-r--r-- | includes/classes/StockMovement.php | 68 | ||||
| -rw-r--r-- | list_movements.php | 72 | ||||
| -rw-r--r-- | list_stock.php | 32 | ||||
| -rw-r--r-- | templates/add_prebuild.tpl | 119 | ||||
| -rw-r--r-- | templates/edit_movement.tpl | 10 | ||||
| -rw-r--r-- | templates/list_movements.tpl | 31 | ||||
| -rw-r--r-- | templates/list_stock.tpl | 11 | ||||
| -rwxr-xr-x | templates/menu_stock.tpl | 2 | ||||
| -rwxr-xr-x | templates/stock_simple_list_inc.tpl | 2 | ||||
| -rwxr-xr-x | templates/view_component.tpl | 2 | ||||
| -rw-r--r-- | templates/view_movement.tpl | 22 | ||||
| -rw-r--r-- | view_movement.php | 5 |
15 files changed, 412 insertions, 92 deletions
diff --git a/add_prebuild.php b/add_prebuild.php new file mode 100644 index 0000000..2c0e9fe --- /dev/null +++ b/add_prebuild.php @@ -0,0 +1,112 @@ +<?php +/** + * @package stock + * @subpackage functions + */ + +namespace Bitweaver\Stock; + +use Bitweaver\KernelTools; + +require_once '../kernel/includes/setup_inc.php'; + +global $gBitSystem, $gBitSmarty, $gBitUser, $gBitDb; + +$gBitSystem->verifyPermission( 'p_stock_create' ); + +if( !empty( $_REQUEST['fCancel'] ) ) { + header( 'Location: '.STOCK_PKG_URL.'list_movements.php' ); + die; +} + +if( !empty( $_REQUEST['fCreate'] ) ) { + $targetContentId = isset( $_REQUEST['assembly_content_id'] ) && is_numeric( $_REQUEST['assembly_content_id'] ) + ? (int)$_REQUEST['assembly_content_id'] : null; + $kitCount = isset( $_REQUEST['kit_count'] ) && is_numeric( $_REQUEST['kit_count'] ) && (float)$_REQUEST['kit_count'] > 0 + ? (float)$_REQUEST['kit_count'] : 1; + $title = trim( $_REQUEST['title'] ?? '' ); + $rqRef = trim( $_REQUEST['rq_ref'] ?? '' ); + + if( !$targetContentId ) { + $errors[] = KernelTools::tra( 'Please select an assembly.' ); + } elseif( $title === '' ) { + $errors[] = KernelTools::tra( 'Please enter a build reference.' ); + } else { + $targetRow = $gBitDb->getRow( + "SELECT `title` FROM `".BIT_DB_PREFIX."liberty_content` + WHERE `content_id` = ? AND `content_type_guid` = 'stockassembly'", + [ $targetContentId ] + ); + if( !$targetRow ) { + $errors[] = KernelTools::tra( 'Assembly not found.' ); + } else { + $movement = new StockMovement(); + $paramHash = [ + 'title' => $title, + 'content_type_guid' => STOCKMOVEMENT_CONTENT_TYPE_GUID, + 'edit' => $rqRef, + ]; + if( $movement->store( $paramHash ) ) { + $pbldHash = [ + 'content_id' => $movement->mContentId, + 'item' => 'PBLD', + 'xkey' => $title, + 'fAddXref' => 1, + ]; + $movement->storeXref( $pbldHash ); + $assemblyHash = [ + 'content_id' => $movement->mContentId, + 'item' => 'ASSEMBLY', + 'xref' => $targetContentId, + 'xkey' => (string)$kitCount, + 'xkey_ext' => $targetRow['title'], + 'edit' => 'stockassembly', + 'fAddXref' => 1, + ]; + $movement->storeXref( $assemblyHash ); + $movement->explodeFromAssembly( $targetContentId, $kitCount ); + header( 'Location: '.STOCK_PKG_URL.'edit_movement.php?content_id='.$movement->mContentId ); + die; + } + $errors = $movement->mErrors; + } + } +} + +$assembly = new StockAssembly(); +$asmHash = [ 'show_empty' => true, 'sort_mode' => 'title_asc', 'max_records' => 1000 ]; +$assemblyList = $assembly->getList( $asmHash ); + +$preselect = isset( $_REQUEST['assembly_content_id'] ) && is_numeric( $_REQUEST['assembly_content_id'] ) + ? (int)$_REQUEST['assembly_content_id'] : null; +$kitCount = isset( $_REQUEST['kit_count'] ) && is_numeric( $_REQUEST['kit_count'] ) + ? (float)$_REQUEST['kit_count'] : 1; + +$itemIds = array_column( $assemblyList, 'content_id' ); +$klidMap = []; +if( $itemIds ) { + $klidRows = $gBitDb->getAll( + "SELECT x.`content_id`, x.`xkey` FROM `".BIT_DB_PREFIX."liberty_xref` x + WHERE x.`item` = 'KLID' AND x.`content_id` IN (".implode( ',', array_fill( 0, count( $itemIds ), '?' ) ).")", + $itemIds + ); + foreach( $klidRows as $r ) { $klidMap[$r['content_id']] = $r['xkey']; } +} +$itemListJson = json_encode( array_map( + fn( $i ) => [ 'id' => (int)$i['content_id'], 'text' => $i['title'], 'klid' => $klidMap[$i['content_id']] ?? '' ], + $assemblyList +) ); +$preselectTitle = ''; +if( $preselect ) { + foreach( $assemblyList as $item ) { + if( (int)$item['content_id'] === $preselect ) { $preselectTitle = $item['title']; break; } + } +} + +$gBitSmarty->assign( 'itemListJson', $itemListJson ); +$gBitSmarty->assign( 'preselect', $preselect ); +$gBitSmarty->assign( 'preselectTitle', $preselectTitle ); +$gBitSmarty->assign( 'kitCount', $kitCount ); +$gBitSmarty->assign( 'errors', $errors ?? [] ); + +$gBitSystem->display( 'bitpackage:stock/add_prebuild.tpl', KernelTools::tra( 'Create Prebuild' ), [ 'display_mode' => 'edit' ] ); diff --git a/admin/schema_inc.php b/admin/schema_inc.php index edf8463..e9ab919 100755 --- a/admin/schema_inc.php +++ b/admin/schema_inc.php @@ -163,8 +163,9 @@ $xrefTypes[] = "INSERT INTO `{$X}liberty_xref_group` (`x_group`,`content_type_gu // assembly item — links the movement to its assembly or component (multiple=1 for future multi-item reqns) $xrefItems[] = "INSERT INTO `{$X}liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES ('ASSEMBLY','stockmovement','assembly','Assembly',1,3,'','assembly',NULL)"; -// reference items — REQN=out, TRANS=in from elf, ORDER=in from supplier +// reference items — REQN=out to kitlocker, PBLD=out prebuild, TRANS=in from elf, ORDER=in from supplier $xrefItems[] = "INSERT INTO `{$X}liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES ('REQN', 'stockmovement','reference','Requisition',1,3,'','text',NULL)"; +$xrefItems[] = "INSERT INTO `{$X}liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES ('PBLD','stockmovement','reference','Prebuild', 1,3,'','text',NULL)"; $xrefItems[] = "INSERT INTO `{$X}liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES ('TRANS','stockmovement','reference','Transfer', 1,3,'','text',NULL)"; $xrefItems[] = "INSERT INTO `{$X}liberty_xref_item` (`item`,`content_type_guid`,`x_group`,`cross_ref_title`,`multiple`,`role_id`,`cross_ref_href`,`template`,`data`) VALUES ('ORDER','stockmovement','reference','Order', 1,3,'','text',NULL)"; diff --git a/edit_movement.php b/edit_movement.php index 1167efd..defc9f4 100644 --- a/edit_movement.php +++ b/edit_movement.php @@ -47,7 +47,7 @@ if( !empty( $_REQUEST['fSave'] ) ) { if( !empty( $_REQUEST['movement_type'] ) && isset( $refTypes[$_REQUEST['movement_type']] ) ) { $existingRef = $gBitDb->getRow( "SELECT `xref_id` FROM `".BIT_DB_PREFIX."liberty_xref` - WHERE `content_id`=? AND `item` IN ('REQN','TRANS','ORDER') ORDER BY `xorder`", + WHERE `content_id`=? AND `item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY `xorder`", [ $gContent->mContentId ] ); $refHash = [ @@ -66,7 +66,7 @@ if( !empty( $_REQUEST['fSave'] ) ) { if( !empty( $_REQUEST['ordered_date'] ) && ($ts = parseMovementDate( $_REQUEST['ordered_date'] )) ) { $gBitDb->query( "UPDATE `".BIT_DB_PREFIX."liberty_xref` SET `start_date`=? - WHERE `content_id`=? AND `item` IN ('REQN','TRANS','ORDER')", + WHERE `content_id`=? AND `item` IN ('REQN','TRANS','ORDER','PBLD')", [ date( 'Y-m-d H:i:s', $ts ), $gContent->mContentId ] ); } @@ -187,8 +187,11 @@ $gBitSmarty->assign( 'orderedDateVal', $orderedDateVal ); $gBitSmarty->assign( 'receivedDateVal', $receivedDateVal ); $gBitSmarty->assign( 'contactLookupUrl', CONTACT_PKG_URL.'includes/lookup_contact.php' ); -$isReqn = ( ( $gContent->mInfo['ref_type'] ?? '' ) === 'REQN' ); -if( $isReqn ) { +$refType = $gContent->mInfo['ref_type'] ?? ''; +$isReqn = $refType === 'REQN'; +$isPbld = $refType === 'PBLD'; +$isBuild = in_array( $refType, [ 'REQN', 'PBLD' ] ); +if( $isBuild ) { $assembly = new StockAssembly(); $asmHash = [ 'show_empty' => true, 'sort_mode' => 'title_asc', 'max_records' => 1000 ]; $assemblyList = $assembly->getList( $asmHash ); @@ -212,6 +215,8 @@ if( $isReqn ) { ) ); } $gBitSmarty->assign( 'isReqn', $isReqn ); +$gBitSmarty->assign( 'isPbld', $isPbld ); +$gBitSmarty->assign( 'isBuild', $isBuild ); $gBitSmarty->assign( 'refTypes', $refTypes ); $gBitSmarty->assign( 'errors', $gContent->mErrors ); diff --git a/includes/classes/StockMovement.php b/includes/classes/StockMovement.php index 57e8146..178944d 100644 --- a/includes/classes/StockMovement.php +++ b/includes/classes/StockMovement.php @@ -93,24 +93,24 @@ class StockMovement extends LibertyContent { , uue.`login` AS `modifier_user`, uue.`real_name` AS `modifier_real_name` , uuc.`login` AS `creator_user`, uuc.`real_name` AS `creator_real_name` , (SELECT FIRST 1 x.`start_date` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_start_date , (SELECT FIRST 1 xi.`cross_ref_title` FROM `{$X}liberty_xref` x JOIN `{$X}liberty_xref_item` xi ON xi.`item` = x.`item` AND xi.`content_type_guid` = 'stockmovement' - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_type_title , (SELECT FIRST 1 x.`xref` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_contact_id , (SELECT FIRST 1 lc2.`title` FROM `{$X}liberty_xref` x JOIN `{$X}liberty_content` lc2 ON lc2.`content_id` = x.`xref` - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_contact_name , (SELECT FIRST 1 x.`item` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_type , (SELECT FIRST 1 x.`data` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_from_data FROM `".BIT_DB_PREFIX."liberty_content` lc LEFT JOIN `".BIT_DB_PREFIX."users_users` uue ON uue.`user_id` = lc.`modifier_user_id` @@ -208,9 +208,9 @@ class StockMovement extends LibertyContent { */ public function getDirection(): string { $refType = $this->mInfo['ref_type'] ?? null; - if( $refType === 'REQN' ) return 'O'; + if( in_array( $refType, [ 'REQN', 'PBLD' ] ) ) return 'O'; if( in_array( $refType, [ 'TRANS', 'ORDER' ] ) ) return 'I'; - return 'O'; + return ''; } /** @return bool TRUE when lc.event_time is non-zero (movement has been received). */ @@ -301,19 +301,22 @@ class StockMovement extends LibertyContent { $whereSql = " AND lc.`content_type_guid` = '".STOCKMOVEMENT_CONTENT_TYPE_GUID."'"; - if( !empty( $pListHash['ref_type'] ) && in_array( $pListHash['ref_type'], [ 'REQN', 'TRANS', 'ORDER' ] ) ) { + if( !empty( $pListHash['ref_type'] ) && in_array( $pListHash['ref_type'], [ 'REQN', 'TRANS', 'ORDER', 'PBLD' ] ) ) { $joinSql .= " INNER JOIN `".BIT_DB_PREFIX."liberty_xref` xrf ON xrf.`content_id` = lc.`content_id` AND xrf.`item` = ?"; $bindVars[] = $pListHash['ref_type']; } + $partId = 0; + $partIsAsm = false; if( $this->verifyId( $pListHash['assembly_content_id'] ?? 0 ) ) { + $partId = (int)$pListHash['assembly_content_id']; + $partIsAsm = true; $joinSql .= " INNER JOIN `".BIT_DB_PREFIX."liberty_xref` xasm ON xasm.`content_id` = lc.`content_id` AND xasm.`item` = 'ASSEMBLY' AND xasm.`xref` = ?"; - $bindVars[] = (int)$pListHash['assembly_content_id']; - } - $cmpContentId = $this->verifyId( $pListHash['component_content_id'] ?? 0 ) ? (int)$pListHash['component_content_id'] : 0; - if( $cmpContentId ) { + $bindVars[] = $partId; + } elseif( $this->verifyId( $pListHash['component_content_id'] ?? 0 ) ) { + $partId = (int)$pListHash['component_content_id']; $whereSql .= " AND EXISTS (SELECT 1 FROM `".BIT_DB_PREFIX."liberty_xref` xcf - WHERE xcf.`content_id` = lc.`content_id` AND xcf.`item` IN ('SGL','PRT','SHT','VOL') AND xcf.`xref` = $cmpContentId)"; + WHERE xcf.`content_id` = lc.`content_id` AND xcf.`item` IN ('SGL','PRT','SHT','VOL') AND xcf.`xref` = $partId)"; } if( $this->verifyId( $pListHash['user_id'] ?? 0 ) ) { $whereSql .= " AND lc.`user_id` = ?"; @@ -330,8 +333,8 @@ class StockMovement extends LibertyContent { $orderby = match( $sortMode ) { 'event_time_asc' => ' ORDER BY lc.event_time ASC', 'event_time_desc' => ' ORDER BY lc.event_time DESC', - 'ref_start_date_asc' => ' ORDER BY (SELECT FIRST 1 x.start_date FROM '.BIT_DB_PREFIX.'liberty_xref x WHERE x.content_id=lc.content_id AND x.item IN (\'REQN\',\'TRANS\',\'ORDER\') ORDER BY x.xorder) ASC', - 'ref_start_date_desc' => ' ORDER BY (SELECT FIRST 1 x.start_date FROM '.BIT_DB_PREFIX.'liberty_xref x WHERE x.content_id=lc.content_id AND x.item IN (\'REQN\',\'TRANS\',\'ORDER\') ORDER BY x.xorder) DESC', + 'ref_start_date_asc' => ' ORDER BY (SELECT FIRST 1 x.start_date FROM '.BIT_DB_PREFIX.'liberty_xref x WHERE x.content_id=lc.content_id AND x.item IN (\'REQN\',\'TRANS\',\'ORDER\',\'PBLD\') ORDER BY x.xorder) ASC', + 'ref_start_date_desc' => ' ORDER BY (SELECT FIRST 1 x.start_date FROM '.BIT_DB_PREFIX.'liberty_xref x WHERE x.content_id=lc.content_id AND x.item IN (\'REQN\',\'TRANS\',\'ORDER\',\'PBLD\') ORDER BY x.xorder) DESC', default => !empty( $sortMode ) ? ' ORDER BY '.$this->mDb->convertSortmode( $sortMode ) : ' ORDER BY lc.last_modified DESC', @@ -351,26 +354,31 @@ class StockMovement extends LibertyContent { ); $X = BIT_DB_PREFIX; - $cmpQtySelect = $cmpContentId - ? ", (SELECT FIRST 1 x.`item` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('SGL','PRT','SHT','VOL') AND x.`xref` = $cmpContentId - ORDER BY x.`xorder`) AS cmp_qty_type, - (SELECT SUM(CAST(x.`xkey` AS DOUBLE PRECISION)) FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('SGL','PRT','SHT','VOL') AND x.`xref` = $cmpContentId) AS cmp_qty" - : ", CAST(NULL AS VARCHAR(4)) AS cmp_qty_type, CAST(NULL AS DOUBLE PRECISION) AS cmp_qty"; + if( $partIsAsm ) { + $partQtySelect = ", CAST(NULL AS VARCHAR(4)) AS part_qty_type + , CAST(xasm.`xkey` AS DOUBLE PRECISION) AS part_qty"; + } elseif( $partId ) { + $partQtySelect = ", (SELECT FIRST 1 x.`item` FROM `{$X}liberty_xref` x + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('SGL','PRT','SHT','VOL') AND x.`xref` = $partId + ORDER BY x.`xorder`) AS part_qty_type + , (SELECT SUM(CAST(x.`xkey` AS DOUBLE PRECISION)) FROM `{$X}liberty_xref` x + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('SGL','PRT','SHT','VOL') AND x.`xref` = $partId) AS part_qty"; + } else { + $partQtySelect = ", CAST(NULL AS VARCHAR(4)) AS part_qty_type, CAST(NULL AS DOUBLE PRECISION) AS part_qty"; + } $query = "SELECT lc.`content_id`, lc.`title`, lc.`created`, lc.`last_modified`, lc.`event_time`, - uu.`login`, uu.`real_name`, + lc.`user_id`, uu.`login`, uu.`real_name`, (SELECT FIRST 1 x.`item` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_type, (SELECT FIRST 1 x.`xkey` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_key, (SELECT FIRST 1 x.`start_date` FROM `{$X}liberty_xref` x - WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER') + WHERE x.`content_id` = lc.`content_id` AND x.`item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY x.`xorder`) AS ref_start_date - $cmpQtySelect + $partQtySelect $selectSql FROM `{$X}liberty_content` lc INNER JOIN `{$X}users_users` uu ON uu.`user_id` = lc.`user_id` @@ -456,7 +464,7 @@ class StockMovement extends LibertyContent { if( $ref !== '' ) { $existingRow = $this->mDb->getRow( "SELECT `xref_id`, `item` FROM `".BIT_DB_PREFIX."liberty_xref` - WHERE `content_id` = ? AND `item` IN ('REQN','TRANS','ORDER') ORDER BY `xorder`", + WHERE `content_id` = ? AND `item` IN ('REQN','TRANS','ORDER','PBLD') ORDER BY `xorder`", [ $this->mContentId ] ); // Preserve existing type if already set; default to TRANS for new rows @@ -482,7 +490,7 @@ class StockMovement extends LibertyContent { $this->mDb->query( "UPDATE `".BIT_DB_PREFIX."liberty_xref` SET `start_date` = ? - WHERE `content_id` = ? AND `item` IN ('REQN','TRANS','ORDER')", + WHERE `content_id` = ? AND `item` IN ('REQN','TRANS','ORDER','PBLD')", [ date( 'Y-m-d H:i:s', $ts ), $this->mContentId ] ); } diff --git a/list_movements.php b/list_movements.php index 1172fd3..700c824 100644 --- a/list_movements.php +++ b/list_movements.php @@ -11,34 +11,62 @@ global $gBitSystem, $gBitSmarty, $gBitDb; $gBitSystem->verifyPermission( 'p_stock_view' ); -$componentContentId = isset( $_REQUEST['component_content_id'] ) && is_numeric( $_REQUEST['component_content_id'] ) - ? (int)$_REQUEST['component_content_id'] : null; +$partContentId = isset( $_REQUEST['part_content_id'] ) && is_numeric( $_REQUEST['part_content_id'] ) + ? (int)$_REQUEST['part_content_id'] : null; + +$partTitle = ''; +$partType = ''; +$partSize = null; +if( $partContentId ) { + $pRow = $gBitDb->getRow( + "SELECT `title`, `content_type_guid` FROM `".BIT_DB_PREFIX."liberty_content` WHERE `content_id` = ?", + [ $partContentId ] + ); + $partTitle = $pRow['title'] ?? ''; + $partType = match( $pRow['content_type_guid'] ?? '' ) { + 'stockassembly' => 'assembly', + 'stockcomponent' => 'component', + default => '', + }; + if( $partType === 'component' ) { + $ps = $gBitDb->getOne( + "SELECT CAST(x.`xkey` AS DOUBLE PRECISION) FROM `".BIT_DB_PREFIX."liberty_xref` x + WHERE x.`content_id` = ? AND x.`item` = 'PRT'", + [ $partContentId ] + ); + $partSize = $ps ? (float)$ps : null; + } +} + +$listHash = $_REQUEST; +if( $partContentId && $partType === 'assembly' ) { + $listHash['assembly_content_id'] = $partContentId; +} elseif( $partContentId && $partType === 'component' ) { + $listHash['component_content_id'] = $partContentId; +} +unset( $listHash['part_content_id'] ); $movement = new StockMovement(); -$listHash = $_REQUEST; $movementList = $movement->getList( $listHash ); -$componentTitle = ''; -$partSize = null; -if( $componentContentId ) { - $componentTitle = $gBitDb->getOne( - "SELECT `title` FROM `".BIT_DB_PREFIX."liberty_content` WHERE `content_id` = ?", - [ $componentContentId ] - ) ?: ''; - $ps = $gBitDb->getOne( - "SELECT CAST(x.`xkey` AS DOUBLE PRECISION) FROM `".BIT_DB_PREFIX."liberty_xref` x - WHERE x.`content_id` = ? AND x.`item` = 'PRT'", - [ $componentContentId ] +$filterUserId = isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) ? (int)$_REQUEST['user_id'] : null; +$filterUserName = ''; +if( $filterUserId ) { + $uRow = $gBitDb->getRow( + "SELECT `login`, `real_name` FROM `".BIT_DB_PREFIX."users_users` WHERE `user_id` = ?", + [ $filterUserId ] ); - $partSize = $ps ? (float)$ps : null; + $filterUserName = $uRow['real_name'] ?: $uRow['login'] ?: ''; } -$gBitSmarty->assign( 'listInfo', $listHash['listInfo'] ); -$gBitSmarty->assign( 'movementList', $movementList ); -$gBitSmarty->assign( 'filterType', $_REQUEST['ref_type'] ?? '' ); -$gBitSmarty->assign( 'assemblyContentId', isset( $_REQUEST['assembly_content_id'] ) && is_numeric( $_REQUEST['assembly_content_id'] ) ? (int)$_REQUEST['assembly_content_id'] : null ); -$gBitSmarty->assign( 'componentContentId', $componentContentId ); -$gBitSmarty->assign( 'componentTitle', $componentTitle ); -$gBitSmarty->assign( 'partSize', $partSize ); +$gBitSmarty->assign( 'listInfo', $listHash['listInfo'] ); +$gBitSmarty->assign( 'movementList', $movementList ); +$gBitSmarty->assign( 'filterType', $_REQUEST['ref_type'] ?? '' ); +$gBitSmarty->assign( 'partContentId', $partContentId ); +$gBitSmarty->assign( 'partTitle', $partTitle ); +$gBitSmarty->assign( 'partType', $partType ); +$gBitSmarty->assign( 'partSize', $partSize ); +$gBitSmarty->assign( 'filterUserId', $filterUserId ); +$gBitSmarty->assign( 'filterUserName', $filterUserName ); $gBitSystem->display( 'bitpackage:stock/list_movements.tpl', 'Movements', [ 'display_mode' => 'list' ] ); diff --git a/list_stock.php b/list_stock.php index 796161d..6ad176e 100644 --- a/list_stock.php +++ b/list_stock.php @@ -18,15 +18,31 @@ $assemblyContentId = isset( $_REQUEST['assembly_content_id'] ) && is_numeric( $_ ? (int)$_REQUEST['assembly_content_id'] : null; $kitCount = isset( $_REQUEST['kit_count'] ) && is_numeric( $_REQUEST['kit_count'] ) && (float)$_REQUEST['kit_count'] > 0 ? (float)$_REQUEST['kit_count'] : 1; +$filterUserId = isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) + ? (int)$_REQUEST['user_id'] : null; +$filterUserName = ''; +if( $filterUserId ) { + $uRow = $gBitDb->getRow( + "SELECT `login`, `real_name` FROM `".BIT_DB_PREFIX."users_users` WHERE `user_id` = ?", + [ $filterUserId ] + ); + $filterUserName = $uRow['real_name'] ?: $uRow['login'] ?: ''; +} $X = BIT_DB_PREFIX; $bindVars = []; if( $assemblyContentId ) { - // BOM view: start from BOM items so components with no movements still appear + // BOM view: start from BOM items so components with no movements still appear. + // Bind var order must match ? positions in the SQL: user_id (in subquery SELECT) first, + // then assemblyContentId (in FROM JOIN), then find (in WHERE). + $userSubSql = ''; + if( $filterUserId ) { + $userSubSql = " AND mc.`user_id` = ?"; + $bindVars[] = $filterUserId; + } $findSql = $find !== '' ? " AND UPPER(lc.`title`) LIKE ?" : ''; - if( $find !== '' ) $bindVars[] = '%'.strtoupper( $find ).'%'; $query = "SELECT lc.`content_id`, lc.`title`, lc.`data`, bom.`item` AS qty_type, @@ -49,7 +65,8 @@ if( $assemblyContentId ) { AND mc.`content_type_guid` = 'stockmovement' WHERE mx.`xref` = lc.`content_id` AND mx.`item` = bom.`item` - AND mx.`xkey` SIMILAR TO '[0-9]+(\.[0-9]+)?') AS stock_level + AND mx.`xkey` SIMILAR TO '[0-9]+(\.[0-9]+)?' + $userSubSql) AS stock_level FROM `{$X}liberty_content` lc INNER JOIN `{$X}liberty_xref` bom ON bom.`content_id` = ? AND bom.`item` IN ('SGL','PRT','SHT','VOL') @@ -58,11 +75,16 @@ if( $assemblyContentId ) { $findSql ORDER BY bom.`xorder`"; $bindVars[] = $assemblyContentId; + if( $find !== '' ) $bindVars[] = '%'.strtoupper( $find ).'%'; } else { // General list: only components with movement history $whereSql = ''; + if( $filterUserId ) { + $whereSql .= " AND mc.`user_id` = ?"; + $bindVars[] = $filterUserId; + } if( $find !== '' ) { - $whereSql = " AND UPPER(lc.`title`) LIKE ?"; + $whereSql .= " AND UPPER(lc.`title`) LIKE ?"; $bindVars[] = '%'.strtoupper( $find ).'%'; } @@ -187,5 +209,7 @@ $gBitSmarty->assign( 'find', $find ); $gBitSmarty->assign( 'showBom', (bool)$assemblyContentId ); $gBitSmarty->assign( 'showShortages', $showShortages ); $gBitSmarty->assign( 'kitCount', $kitCount ); +$gBitSmarty->assign( 'filterUserId', $filterUserId ); +$gBitSmarty->assign( 'filterUserName', $filterUserName ); $gBitSystem->display( 'bitpackage:stock/list_stock.tpl', 'Stock Levels', [ 'display_mode' => 'list' ] ); diff --git a/templates/add_prebuild.tpl b/templates/add_prebuild.tpl new file mode 100644 index 0000000..2f1755b --- /dev/null +++ b/templates/add_prebuild.tpl @@ -0,0 +1,119 @@ +{strip} +<div class="edit stock"> + <div class="header"> + <h1>{tr}Create Prebuild{/tr}</h1> + </div> + + <div class="body"> + {formfeedback error=$errors} + + {form id="addPrebuildForm" ipackage="stock" ifile="add_prebuild.php"} + + <div class="form-group"> + {formlabel label="Build Ref" for="title" mandatory="y"} + {forminput} + <input type="text" class="form-control" name="title" id="title" + value="{$smarty.request.title|escape}" placeholder="BUILD-2026-001" /> + {/forminput} + </div> + + <div class="form-group"> + {formlabel label="Assembly" for="assembly_search" mandatory="y"} + {forminput} + <input type="hidden" name="assembly_content_id" id="assembly_content_id" + value="{$preselect|default:''|escape}" /> + <div style="position:relative"> + <input type="text" class="form-control" id="assembly_search" + autocomplete="off" + value="{$preselectTitle|escape}" + placeholder="Type to search…" /> + <ul id="assembly_dropdown" class="dropdown-menu" + style="display:none;position:absolute;width:100%;z-index:1000;max-height:220px;overflow-y:auto"></ul> + </div> + {/forminput} + </div> + + <div class="form-group"> + {formlabel label="Qty" for="kit_count"} + {forminput} + <input type="number" class="form-control input-sm" name="kit_count" + id="kit_count" min="1" step="1" style="width:6em" + value="{$kitCount|escape}" /> + {/forminput} + </div> + + <div class="form-group"> + {formlabel label="Against RQ" for="rq_ref"} + {forminput} + <input type="text" class="form-control" name="rq_ref" id="rq_ref" + value="{$smarty.request.rq_ref|escape}" + placeholder="RQ number if building against a requisition" /> + {/forminput} + </div> + + <div class="form-group submit"> + <input type="submit" class="btn btn-default" name="fCancel" value="{tr}Cancel{/tr}" /> + <input type="submit" class="btn btn-primary" name="fCreate" value="{tr}Create Prebuild{/tr}" /> + </div> + + {/form} + </div> +</div> +{/strip} +<script> +(function($) { + var items = {$itemListJson}; + var $input = $('#assembly_search'); + var $hidden = $('#assembly_content_id'); + var $dd = $('#assembly_dropdown'); + + $input.on('input', function() { + var q = this.value.toLowerCase().trim(); + $dd.hide().empty(); + $hidden.val(''); + if (!q) return; + var matched = items.filter(function(i) { + return i.text.toLowerCase().indexOf(q) !== -1 || (i.klid && i.klid.toLowerCase().indexOf(q) !== -1); + }); + if (!matched.length) return; + matched.forEach(function(i) { + var label = i.text + (i.klid ? ' (' + i.klid + ')' : ''); + $dd.append($('<li>').append( + $('<a>').attr('href', '#').data('id', i.id).data('text', i.text).text(label) + )); + }); + $dd.show(); + }); + + $(document).on('mousedown', '#assembly_dropdown a', function(e) { + e.preventDefault(); + $input.val($(this).data('text')); + $hidden.val($(this).data('id')); + $dd.hide().empty(); + }); + + $input.on('blur', function() { + setTimeout(function() { $dd.hide(); }, 150); + }); + + $input.on('keydown', function(e) { + if (!$dd.is(':visible')) return; + var $links = $dd.find('a'); + var idx = $links.index($dd.find('li.active a')); + if (e.key === 'ArrowDown') { + e.preventDefault(); + $links.parent().removeClass('active'); + $links.eq(idx + 1 < $links.length ? idx + 1 : 0).parent().addClass('active'); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + $links.parent().removeClass('active'); + $links.eq(idx > 0 ? idx - 1 : $links.length - 1).parent().addClass('active'); + } else if (e.key === 'Enter') { + var $active = $dd.find('li.active a'); + if ($active.length) { e.preventDefault(); $active.trigger('mousedown'); } + } else if (e.key === 'Escape') { + $dd.hide(); + } + }); +}(jQuery)); +</script> diff --git a/templates/edit_movement.tpl b/templates/edit_movement.tpl index c4081dc..19dc70d 100644 --- a/templates/edit_movement.tpl +++ b/templates/edit_movement.tpl @@ -24,7 +24,7 @@ {/forminput} </div> - {if !$isReqn} + {if !$isBuild} {if $refTypes} <div class="form-group"> {formlabel label="Movement Type" mandatory="y"} @@ -65,7 +65,7 @@ {/if} <div class="form-group"> - {formlabel label="Ordered" for="ordered_date"} + {formlabel label="{if $isPbld}Build Date{else}Ordered{/if}" for="ordered_date"} {forminput} <input type="text" class="form-control input-small" name="ordered_date" id="ordered_date" placeholder="dd/mm/yyyy" value="{$orderedDateVal|escape}" maxlength="10" /> @@ -73,7 +73,7 @@ </div> <div class="form-group"> - {formlabel label="Received" for="received_date"} + {formlabel label="{if $isPbld}Completed{else}Received{/if}" for="received_date"} {forminput} <input type="text" class="form-control input-small" name="received_date" id="received_date" placeholder="dd/mm/yyyy" value="{$receivedDateVal|escape}" maxlength="10" /> @@ -110,7 +110,7 @@ {if $gXrefInfo->mGroups} {jstabs} {foreach $gXrefInfo->mGroups as $xrefGroup} - {if $xrefGroup->mXGroup neq 'reference' && ($xrefGroup->mXGroup neq 'assembly' || $isReqn)} + {if $xrefGroup->mXGroup neq 'reference' && ($xrefGroup->mXGroup neq 'assembly' || $isBuild)} {include file=$gContent->getXrefListTemplate($xrefGroup->mTemplate) xrefGroup=$xrefGroup allow_add=true @@ -120,7 +120,7 @@ {/jstabs} {/if} - {if !$isReqn} + {if !$isBuild} {* ── Upload CSV (orders/transfers only) ── *} <h4>{tr}Upload CSV{/tr}</h4> {form enctype="multipart/form-data" ipackage="stock" ifile="edit_movement.php"} diff --git a/templates/list_movements.tpl b/templates/list_movements.tpl index 442f29d..424fff9 100644 --- a/templates/list_movements.tpl +++ b/templates/list_movements.tpl @@ -4,16 +4,18 @@ <div class="floaticon hidden-print"> <button type="button" class="btn btn-link" onclick="window.print()">{biticon ipackage="icons" iname="document-print" iexplain="Print"}</button> {if $gBitUser->hasPermission('p_stock_create')} - <a href="{$smarty.const.STOCK_PKG_URL}add_requisition.php">{biticon ipackage="icons" iname="list-add" iexplain="Add Requisition"}</a> + <a href="{$smarty.const.STOCK_PKG_URL}add_prebuild.php">{biticon ipackage="icons" iname="package-x-generic" iexplain="Add Prebuild"}</a> <a href="{$smarty.const.STOCK_PKG_URL}edit_movement.php">{biticon ipackage="icons" iname="view-task-add" iexplain="Add Movement"}</a> {/if} <form class="minifind" action="{$smarty.const.STOCK_PKG_URL}list_movements.php" method="get"> - {if $componentContentId}<input type="hidden" name="component_content_id" value="{$componentContentId|escape}" />{/if} + {if $partContentId}<input type="hidden" name="part_content_id" value="{$partContentId|escape}" />{/if} + {if $filterUserId}<input type="hidden" name="user_id" value="{$filterUserId|escape}" />{/if} <div class="form-inline"> <div class="form-group"> <select name="ref_type" class="form-control input-sm"> <option value="">{tr}All types{/tr}</option> <option value="REQN"{if $filterType eq 'REQN'} selected="selected"{/if}>{tr}Requisition (out){/tr}</option> + <option value="PBLD"{if $filterType eq 'PBLD'} selected="selected"{/if}>{tr}Prebuild (out){/tr}</option> <option value="TRANS"{if $filterType eq 'TRANS'} selected="selected"{/if}>{tr}Transfer (in){/tr}</option> <option value="ORDER"{if $filterType eq 'ORDER'} selected="selected"{/if}>{tr}Order (in){/tr}</option> </select> @@ -27,13 +29,18 @@ </div> </form> </div> - <h1>{tr}Movements{/tr}{if $componentTitle} — {$componentTitle|escape}{/if}</h1> + <h1>{tr}Movements{/tr}{if $partTitle} — {$partTitle|escape}{/if}</h1> + <small> + <a href="{$smarty.const.STOCK_PKG_URL}list_movements.php">{tr}Movements{/tr}</a> + {if $partTitle}› <a href="{$smarty.const.STOCK_PKG_URL}view_{$partType}.php?content_id={$partContentId}">{$partTitle|escape}</a>{/if} + {if $filterUserName}› <a href="{$smarty.const.STOCK_PKG_URL}list_movements.php?user_id={$filterUserId}">{$filterUserName|escape}</a>{/if} + </small> </header> <section class="body"> - {if $componentContentId} - <p><a class="btn btn-xs btn-default" href="{$smarty.const.STOCK_PKG_URL}view_component.php?content_id={$componentContentId}">← {tr}Back to component{/tr}</a></p> + {if $partContentId} + <p><a class="btn btn-xs btn-default" href="{$smarty.const.STOCK_PKG_URL}view_{$partType}.php?content_id={$partContentId}">← {if $partType eq 'assembly'}{tr}Back to assembly{/tr}{else}{tr}Back to component{/tr}{/if}</a></p> {/if} <table class="table table-striped table-hover"> @@ -41,7 +48,7 @@ <tr> <th>{smartlink ititle="Reference" isort="title"}</th> <th>{tr}Type{/tr}</th> - {if $componentContentId}<th class="text-right">{tr}Qty{/tr}</th>{/if} + {if $partContentId}<th class="text-right">{tr}Qty{/tr}</th>{/if} <th>{smartlink ititle="Ordered" isort="ref_start_date" ifile="list_movements.php" ipackage="stock"}</th> <th>{smartlink ititle="Received" isort="event_time" ifile="list_movements.php" ipackage="stock"}</th> <th>{smartlink ititle="Date" isort="created_desc"}</th> @@ -54,13 +61,17 @@ <tr> <td><a href="{$mov.display_url|escape}">{$mov.title|escape}</a></td> <td>{$mov.ref_type|escape|default:'—'}</td> - {if $componentContentId} - <td class="text-right">{if $mov.cmp_qty_type eq 'PRT' && $partSize > 0}{math equation="q/p" q=$mov.cmp_qty p=$partSize format="%.2f"}{elseif $mov.cmp_qty_type eq 'SHT'}{$mov.cmp_qty|string_format:"%.2f"}{else}{$mov.cmp_qty|string_format:"%.0f"}{/if} {$mov.cmp_qty_type|escape}</td> + {if $partContentId} + {if $partType eq 'assembly'} + <td class="text-right">{$mov.part_qty|string_format:"%.0f"}</td> + {else} + <td class="text-right">{if $mov.part_qty_type eq 'PRT' && $partSize > 0}{math equation="q/p" q=$mov.part_qty p=$partSize format="%.2f"}{elseif $mov.part_qty_type eq 'SHT'}{$mov.part_qty|string_format:"%.2f"}{else}{$mov.part_qty|string_format:"%.0f"}{/if} {$mov.part_qty_type|escape}</td> + {/if} {/if} <td>{if $mov.ref_start_date}{$mov.ref_start_date|bit_short_date}{else}—{/if}</td> <td>{if $mov.event_time}{$mov.event_time|bit_short_date}{else}—{/if}</td> <td>{$mov.created|bit_short_date}</td> - <td>{$mov.real_name|default:$mov.login|escape}</td> + <td><a href="{$smarty.const.STOCK_PKG_URL}list_movements.php?user_id={$mov.user_id}">{$mov.real_name|default:$mov.login|escape}</a></td> {if $gBitUser->hasPermission('p_stock_update')} <td> <a href="{$smarty.const.STOCK_PKG_URL}edit_movement.php?content_id={$mov.content_id}">{biticon ipackage="icons" iname="edit" iexplain="Edit"}</a> @@ -74,7 +85,7 @@ </table> <nav> - {pagination ref_type=$filterType find=$smarty.request.find|default:'' component_content_id=$componentContentId|default:'' assembly_content_id=$assemblyContentId|default:''} + {pagination ref_type=$filterType find=$smarty.request.find|default:'' part_content_id=$partContentId|default:'' user_id=$filterUserId|default:''} </nav> </section> diff --git a/templates/list_stock.tpl b/templates/list_stock.tpl index 3250427..5a992f3 100644 --- a/templates/list_stock.tpl +++ b/templates/list_stock.tpl @@ -5,13 +5,14 @@ <button type="button" class="btn btn-link" onclick="window.print()">{biticon ipackage="icons" iname="document-print" iexplain="Print"}</button> {if $showShortages} <a class="btn btn-link" - href="{$smarty.const.STOCK_PKG_URL}list_stock.php?shortages=1{if $assemblyContentId}&assembly_content_id={$assemblyContentId|escape:'url'}&kit_count={$kitCount|escape:'url'}{/if}&format=csv">{biticon ipackage="icons" iname="text-csv" iexplain="Download CSV"}</a> + href="{$smarty.const.STOCK_PKG_URL}list_stock.php?shortages=1{if $assemblyContentId}&assembly_content_id={$assemblyContentId|escape:'url'}&kit_count={$kitCount|escape:'url'}{/if}{if $filterUserId}&user_id={$filterUserId|escape:'url'}{/if}&format=csv">{biticon ipackage="icons" iname="text-csv" iexplain="Download CSV"}</a> {if $gBitUser->hasPermission('p_stock_create')} <a class="btn btn-link" - href="{$smarty.const.STOCK_PKG_URL}add_order.php?shortages=1{if $assemblyContentId}&assembly_content_id={$assemblyContentId|escape:'url'}&kit_count={$kitCount|escape:'url'}{/if}{if $find}&find={$find|escape:'url'}{/if}">{biticon ipackage="icons" iname="view-task-add" iexplain="Create Order"}</a> + href="{$smarty.const.STOCK_PKG_URL}add_order.php?shortages=1{if $assemblyContentId}&assembly_content_id={$assemblyContentId|escape:'url'}&kit_count={$kitCount|escape:'url'}{/if}{if $find}&find={$find|escape:'url'}{/if}{if $filterUserId}&user_id={$filterUserId|escape:'url'}{/if}">{biticon ipackage="icons" iname="view-task-add" iexplain="Create Order"}</a> {/if} {/if} <form class="minifind" action="{$smarty.const.STOCK_PKG_URL}list_stock.php" method="get"> + {if $filterUserId}<input type="hidden" name="user_id" value="{$filterUserId|escape}" />{/if} <div class="form-inline"> <div class="form-group"> <input type="hidden" name="assembly_content_id" id="ls_asm_id" value="{$assemblyContentId|default:''|escape}" /> @@ -45,12 +46,16 @@ <button type="submit" class="btn btn-default btn-sm">{tr}Go{/tr}</button> {if $showBom && $gBitUser->hasPermission('p_stock_create')} <a class="btn btn-warning btn-sm" - href="{$smarty.const.STOCK_PKG_URL}add_requisition.php?assembly_content_id={$assemblyContentId}&kit_count={$kitCount}">{tr}Create Requisition{/tr}</a> + href="{$smarty.const.STOCK_PKG_URL}add_prebuild.php?assembly_content_id={$assemblyContentId}&kit_count={$kitCount}{if $filterUserId}&user_id={$filterUserId}{/if}">{tr}Create Prebuild{/tr}</a> {/if} </div> </form> </div> <h1>{tr}Stock Levels{/tr}{if $assemblyTitle} — {$assemblyTitle|escape}{/if}</h1> + <small> + <a href="{$smarty.const.STOCK_PKG_URL}list_stock.php">{tr}Stock Levels{/tr}</a> + {if $filterUserName}› <a href="{$smarty.const.STOCK_PKG_URL}list_stock.php?user_id={$filterUserId}">{$filterUserName|escape}</a>{/if} + </small> </header> <section class="body"> diff --git a/templates/menu_stock.tpl b/templates/menu_stock.tpl index 2f8a327..8794dbf 100755 --- a/templates/menu_stock.tpl +++ b/templates/menu_stock.tpl @@ -12,7 +12,7 @@ <li><a class="item" href="{$smarty.const.STOCK_PKG_URL}edit_component.php">{biticon ipackage="icons" iname="kt-add-filters" iexplain="Create a Component" ilocation=menu}</a></li> <li><a class="item" href="{$smarty.const.STOCK_PKG_URL}edit_assembly.php">{biticon ipackage="icons" iname="view-list-icons" iexplain="Create an Assembly" ilocation=menu}</a></li> <li><a class="item" href="{$smarty.const.STOCK_PKG_URL}edit_movement.php">{biticon ipackage="icons" iname="view-task-add" iexplain="Add Movement" ilocation=menu}</a></li> - <li><a class="item" href="{$smarty.const.STOCK_PKG_URL}add_requisition.php">{biticon ipackage="icons" iname="view-task-child-add" iexplain="Create Requisition" ilocation=menu}</a></li> + <li><a class="item" href="{$smarty.const.STOCK_PKG_URL}add_prebuild.php">{biticon ipackage="icons" iname="package-x-generic" iexplain="Create Prebuild" ilocation=menu}</a></li> {/if} </ul> {/strip} diff --git a/templates/stock_simple_list_inc.tpl b/templates/stock_simple_list_inc.tpl index 8ff0126..4f3347f 100755 --- a/templates/stock_simple_list_inc.tpl +++ b/templates/stock_simple_list_inc.tpl @@ -8,7 +8,7 @@ {/if} <a title="{tr}Print Parts List{/tr}" href="{$smarty.const.STOCK_PKG_URL}print_bom.php?content_id={$gContent->mContentId}">{biticon ipackage="icons" iname="document-print" iexplain="Print Parts List"}</a> <a title="{tr}View Stock{/tr}" href="{$smarty.const.STOCK_PKG_URL}list_stock.php?assembly_content_id={$gContent->mContentId}">{biticon ipackage="icons" iname="package-x-generic" iexplain="View Stock"}</a> - <a title="{tr}View Movements{/tr}" href="{$smarty.const.STOCK_PKG_URL}list_movements.php?assembly_content_id={$gContent->mContentId}">{biticon ipackage="icons" iname="go-next" iexplain="View Movements"}</a> + <a title="{tr}View Movements{/tr}" href="{$smarty.const.STOCK_PKG_URL}list_movements.php?part_content_id={$gContent->mContentId}">{biticon ipackage="icons" iname="go-next" iexplain="View Movements"}</a> {if $gContent->hasAdminPermission()} <a title="{tr}Delete Assembly{/tr}" href="{$smarty.const.STOCK_PKG_URL}edit_assembly.php?content_id={$gContent->mContentId}&delete=1">{biticon ipackage="icons" iname="user-trash" iexplain="Delete Assembly"}</a> {/if} diff --git a/templates/view_component.tpl b/templates/view_component.tpl index 80466e7..c5d94b5 100755 --- a/templates/view_component.tpl +++ b/templates/view_component.tpl @@ -59,7 +59,7 @@ {/if} </tbody> </table> - <a class="btn btn-default btn-xs" href="{$smarty.const.STOCK_PKG_URL}list_movements.php?component_content_id={$gContent->mContentId}">{tr}Stock history{/tr}</a> + <a class="btn btn-default btn-xs" href="{$smarty.const.STOCK_PKG_URL}list_movements.php?part_content_id={$gContent->mContentId}">{tr}Stock history{/tr}</a> {/jstab} {/jstabs} </section> diff --git a/templates/view_movement.tpl b/templates/view_movement.tpl index f038cb6..b815618 100644 --- a/templates/view_movement.tpl +++ b/templates/view_movement.tpl @@ -1,15 +1,19 @@ {strip} <div class="display stock"> - <div class="header"> + <header> <div class="floaticon"> - {if $gBitUser->hasPermission('p_stock_create')} + {if $gContent->hasUpdatePermission()} <a title="{tr}Edit{/tr}" href="{$smarty.const.STOCK_PKG_URL}edit_movement.php?content_id={$gContent->mContentId}">{biticon ipackage="icons" iname="edit" iexplain="Edit Movement"}</a> {/if} </div> <h1>{$gContent->getTitle()|escape}</h1> - </div> + <small> + <a href="{$smarty.const.STOCK_PKG_URL}list_movements.php">{tr}Movements{/tr}</a> + › <a href="{$smarty.const.STOCK_PKG_URL}list_movements.php?user_id={$gContent->mInfo.user_id}">{$gContent->mInfo.creator|escape}</a> + </small> + </header> - <div class="body"> + <section class="body"> <dl class="dl-horizontal"> <dt>{tr}Type{/tr}</dt> @@ -26,11 +30,11 @@ <dt>{tr}Created{/tr}</dt> <dd>{$gContent->mInfo.created|bit_short_datetime} {tr}by{/tr} {$gContent->mInfo.creator|escape}</dd> {if $gContent->mInfo.ref_start_date} - <dt>{tr}Ordered{/tr}</dt> + <dt>{if $isPbld}{tr}Build Date{/tr}{else}{tr}Ordered{/tr}{/if}</dt> <dd>{$gContent->mInfo.ref_start_date|bit_short_date}</dd> {/if} - <dt>{tr}Received{/tr}</dt> - <dd>{if $gContent->isReceived()}{$gContent->mInfo.event_time|bit_short_date}{else}{tr}Pending{/tr}{/if}</dd> + <dt>{if $isPbld}{tr}Completed{/tr}{else}{tr}Received{/tr}{/if}</dt> + <dd>{if $gContent->isReceived()}{$gContent->mInfo.event_time|bit_short_date}{else}{if $isPbld}{tr}In progress{/tr}{else}{tr}Pending{/tr}{/if}{/if}</dd> {if $gContent->mInfo.last_modified neq $gContent->mInfo.created} <dt>{tr}Modified{/tr}</dt> <dd>{$gContent->mInfo.last_modified|bit_short_datetime} {tr}by{/tr} {$gContent->mInfo.editor|escape}</dd> @@ -44,7 +48,7 @@ {if $gXrefInfo->mGroups} {jstabs} {foreach $gXrefInfo->mGroups as $xrefGroup} - {if $xrefGroup->mXGroup neq 'reference' && ($xrefGroup->mXGroup neq 'assembly' || $isReqn)} + {if $xrefGroup->mXGroup neq 'reference' && ($xrefGroup->mXGroup neq 'assembly' || $isBuild)} {include file=$gContent->getXrefListTemplate($xrefGroup->mTemplate) xrefGroup=$xrefGroup allow_add=false @@ -54,6 +58,6 @@ {/jstabs} {/if} - </div><!-- end .body --> + </section><!-- end .body --> </div><!-- end .stock --> {/strip} diff --git a/view_movement.php b/view_movement.php index 395fce0..eca7f01 100644 --- a/view_movement.php +++ b/view_movement.php @@ -23,6 +23,9 @@ $gBitSystem->setCanonicalLink( $gContent->getDisplayUrl() ); $gContent->loadXrefInfo(); $gBitSmarty->assign( 'gXrefInfo', $gContent->mXrefInfo ); -$gBitSmarty->assign( 'isReqn', ( ( $gContent->mInfo['ref_type'] ?? '' ) === 'REQN' ) ); +$refType = $gContent->mInfo['ref_type'] ?? ''; +$gBitSmarty->assign( 'isReqn', $refType === 'REQN' ); +$gBitSmarty->assign( 'isPbld', $refType === 'PBLD' ); +$gBitSmarty->assign( 'isBuild', in_array( $refType, [ 'REQN', 'PBLD' ] ) ); $gBitSystem->display( 'bitpackage:stock/view_movement.tpl', $gContent->getTitle() ); |
