diff options
| author | Lester Caine <lester@lsces.co.uk> | 2026-06-09 16:48:25 +0100 |
|---|---|---|
| committer | Lester Caine <lester@lsces.co.uk> | 2026-06-09 16:48:25 +0100 |
| commit | e792a1a73506f2c09b60528418a36f2c3035f399 (patch) | |
| tree | 3b052d4b67d8db45cdacb69e0462c395cdc7ce7b /templates | |
| parent | 3ed604661c5e10dce6e14d73f0d78b80d9dca72b (diff) | |
| download | stock-e792a1a73506f2c09b60528418a36f2c3035f399.tar.gz stock-e792a1a73506f2c09b60528418a36f2c3035f399.tar.bz2 stock-e792a1a73506f2c09b60528418a36f2c3035f399.zip | |
stock: shortages CSV/order workflow; list header layout
- list_stock: CSV export and Create Order from shortages report;
floaticon icons for print/CSV/order; filter form moved into header
- add_order: new page — pre-populate draft ORDER movement from
shortages list, editable qty/delete per line, supplier autocomplete
- list_movements: print icon; filter form moved into floaticon header
- list_assemblies_simple: print icon added to floaticon
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'templates')
| -rw-r--r-- | templates/add_order.tpl | 163 | ||||
| -rw-r--r-- | templates/list_assemblies_simple.tpl | 1 | ||||
| -rw-r--r-- | templates/list_movements.tpl | 40 | ||||
| -rw-r--r-- | templates/list_stock.tpl | 26 |
4 files changed, 199 insertions, 31 deletions
diff --git a/templates/add_order.tpl b/templates/add_order.tpl new file mode 100644 index 0000000..db5aab8 --- /dev/null +++ b/templates/add_order.tpl @@ -0,0 +1,163 @@ +{strip} +<div class="listing stock"> + <header> + <h1>{tr}Create Order{/tr}</h1> + </header> + + <section class="body"> + + {if $errors} + <div class="alert alert-danger"> + {foreach $errors as $e}<p>{$e|escape}</p>{/foreach} + </div> + {/if} + + {form ipackage="stock" ifile="add_order.php" method="post"} + <div class="form-horizontal"> + + <div class="form-group"> + {formlabel label="Supplier" for="ref_from"} + {forminput} + <input type="hidden" name="supplier_contact_id" id="supplier_contact_id" + value="{$supplierCidVal|escape}" /> + <div style="position:relative"> + <input type="text" class="form-control" name="ref_from" id="ref_from" + autocomplete="off" placeholder="{tr}Type to search contacts…{/tr}" + value="{$supplierVal|escape}" maxlength="160" /> + <ul id="contact_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="Order Ref" for="ref_key"} + {forminput} + <input type="text" class="form-control" name="ref_key" id="ref_key" + value="{$refKeyVal|escape}" maxlength="160" /> + {/forminput} + </div> + + <div class="form-group"> + {formlabel label="Order Date" 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" /> + {/forminput} + </div> + + </div> + + {if $lines} + <table class="table table-condensed" id="order-lines"> + <thead> + <tr> + <th>{tr}Component{/tr}</th> + <th>{tr}Part No{/tr}</th> + <th>{tr}Type{/tr}</th> + <th class="text-right">{tr}Qty{/tr}</th> + <th></th> + </tr> + </thead> + <tbody> + {foreach $lines as $line} + <tr> + <td> + <input type="hidden" name="component_id[]" value="{$line.component_id|escape}" /> + <input type="hidden" name="qty_type[]" value="{$line.qty_type|escape}" /> + {$line.title|escape} + </td> + <td>{$line.part_number|escape}</td> + <td>{$line.qty_type|escape}</td> + <td class="text-right" style="width:7em"> + <input type="number" class="form-control input-sm text-right" name="qty[]" + value="{$line.qty|string_format:'%g'|escape}" min="0.001" step="any" + style="width:6em;display:inline-block" /> + </td> + <td style="width:2em"> + <button type="button" class="btn btn-link btn-xs bw-del-row" + title="{tr}Remove line{/tr}">✕</button> + </td> + </tr> + {/foreach} + </tbody> + </table> + {else} + <p class="muted">{tr}No shortage lines found.{/tr}</p> + {/if} + + <div class="form-group"> + <button type="submit" name="fCreate" value="1" class="btn btn-primary">{tr}Create Order{/tr}</button> + <button type="submit" name="fCancel" value="1" class="btn btn-default">{tr}Cancel{/tr}</button> + </div> + + {/form} + + </section> +</div> +{/strip} +<script> +(function($) { + $(document).on('click', '.bw-del-row', function() { + $(this).closest('tr').remove(); + }); + + var timer, contacts = []; + var $input = $('#ref_from'); + var $hidden = $('#supplier_contact_id'); + var $dd = $('#contact_dropdown'); + + $input.on('input', function() { + var q = $(this).val(); + clearTimeout(timer); + $dd.hide().empty(); + contacts = []; + if (q.length < 2) return; + timer = setTimeout(function() { + $.getJSON('{$contactLookupUrl}', {ldelim}q: q{rdelim}, function(data) { + contacts = data; + if (!data.length) return; + $.each(data, function(i, row) { + var label = row.title + (row.scref ? ' (' + row.scref + ')' : ''); + $dd.append($('<li>').append( + $('<a>').attr('href','#').data('id', row.content_id).data('label', label).text(label) + )); + }); + $dd.show(); + }); + }, 250); + }); + + $(document).on('mousedown', '#contact_dropdown a', function(e) { + e.preventDefault(); + $input.val($(this).data('label')); + $hidden.val($(this).data('id')); + $dd.hide().empty(); + contacts = []; + }); + + $input.on('blur', function() { + setTimeout(function() { $dd.hide(); }, 150); + }); + + $input.on('keydown', function(e) { + if (!$dd.is(':visible')) return; + var $items = $dd.find('a'); + var idx = $dd.find('li.active a').length ? $items.index($dd.find('li.active a')) : -1; + if (e.key === 'ArrowDown') { + e.preventDefault(); + $items.parent().removeClass('active'); + $items.eq(idx + 1 < $items.length ? idx + 1 : 0).parent().addClass('active'); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + $items.parent().removeClass('active'); + $items.eq(idx > 0 ? idx - 1 : $items.length - 1).parent().addClass('active'); + } else if (e.key === 'Enter') { + var $a = $dd.find('li.active a'); + if ($a.length) { e.preventDefault(); $a.trigger('mousedown'); } + } else if (e.key === 'Escape') { + $dd.hide(); + } + }); +}(jQuery)); +</script> diff --git a/templates/list_assemblies_simple.tpl b/templates/list_assemblies_simple.tpl index 7d2eddf..4e91b8c 100644 --- a/templates/list_assemblies_simple.tpl +++ b/templates/list_assemblies_simple.tpl @@ -2,6 +2,7 @@ <div class="listing stock"> <header> <div class="floaticon"> + <button type="button" class="btn btn-link" onclick="window.print()">{biticon ipackage="icons" iname="document-print" iexplain="Print"}</button> {minifind prompt="Assemblies" gallery_id=$smarty.request.gallery_id} </div> <h1>{tr}Assemblies{/tr}{if $gQueryUserId} {tr}by{/tr} {displayname user_id=$gQueryUserId}{/if}</h1> diff --git a/templates/list_movements.tpl b/templates/list_movements.tpl index e50979e..fe741ee 100644 --- a/templates/list_movements.tpl +++ b/templates/list_movements.tpl @@ -2,10 +2,30 @@ <div class="listing stock"> <header> <div class="floaticon"> + <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}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} + <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="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> + </div> + <div class="form-group"> + <input type="text" class="form-control input-sm" name="find" + placeholder="{tr}reference...{/tr}" + value="{$smarty.request.find|escape}" /> + </div> + <button type="submit" class="btn btn-default btn-sm">{tr}Go{/tr}</button> + </div> + </form> </div> <h1>{tr}Movements{/tr}{if $componentTitle} — {$componentTitle|escape}{/if}</h1> </header> @@ -14,28 +34,8 @@ {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> - <input type="hidden" name="component_content_id" value="{$componentContentId}" /> {/if} - {form ipackage="stock" ifile="list_movements.php" method="get"} - <div class="form-inline" style="margin-bottom:1em"> - <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="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> - </div> - <div class="form-group"> - <input type="text" class="form-control input-sm" name="find" - placeholder="{tr}reference...{/tr}" - value="{$smarty.request.find|escape}" /> - </div> - <button type="submit" class="btn btn-default btn-sm">{tr}Go{/tr}</button> - </div> - {/form} - <table class="table table-striped table-hover"> <thead> <tr> diff --git a/templates/list_stock.tpl b/templates/list_stock.tpl index d70c606..f42f435 100644 --- a/templates/list_stock.tpl +++ b/templates/list_stock.tpl @@ -3,14 +3,16 @@ <header> <div class="floaticon hidden-print"> <button type="button" class="btn btn-link" onclick="window.print()">{biticon ipackage="icons" iname="document-print" iexplain="Print"}</button> - </div> - <h1>{tr}Stock Levels{/tr}{if $assemblyTitle} — {$assemblyTitle|escape}{/if}</h1> - </header> - - <section class="body"> - - <form action="{$smarty.const.STOCK_PKG_URL}list_stock.php" method="get"> - <div class="form-inline" style="margin-bottom:1em"> + {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> + {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> + {/if} + {/if} + <form class="minifind" action="{$smarty.const.STOCK_PKG_URL}list_stock.php" method="get"> + <div class="form-inline"> <div class="form-group"> <input type="hidden" name="assembly_content_id" id="ls_asm_id" value="{$assemblyContentId|default:''|escape}" /> <div style="position:relative;display:inline-block;vertical-align:top"> @@ -41,15 +43,17 @@ </label> </div> <button type="submit" class="btn btn-default btn-sm">{tr}Go{/tr}</button> - {if $showShortages} - <button type="button" class="btn btn-default btn-sm" onclick="window.print()">{tr}Print{/tr}</button> - {/if} {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> {/if} </div> </form> + </div> + <h1>{tr}Stock Levels{/tr}{if $assemblyTitle} — {$assemblyTitle|escape}{/if}</h1> + </header> + + <section class="body"> {if $stockList} <table class="table table-hover table-condensed"> |
