Allow multiple petty cash assigners and authorizers#914
Allow multiple petty cash assigners and authorizers#914timschofield merged 5 commits intotimschofield:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Enables assigning/authorizing petty cash tabs by multiple users by switching tab maintenance to multi-select user pickers and adjusting downstream tab lookups to accommodate multi-user fields.
Changes:
- Updated petty cash tab maintenance (PcTabs.php) to accept multiple assigners and cash/expense authorisers and persist them as comma-separated values.
- Updated tab-selection queries in reporting/authorization/assignment scripts to use substring matching against the multi-user fields.
- Minor form/layout adjustments in the expenses authorization tab selector.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| PcTabs.php | Adds multi-select UI and writes assigner/authoriser fields as CSV strings. |
| PcReportTab.php | Broadens tab visibility filter to match multi-authoriser/assigner values. |
| PcReportExpense.php | Broadens expense report filters to match multi-authoriser/assigner values. |
| PcAuthorizeExpenses.php | Broadens eligible tabs list for expense authorization and tweaks the selector markup. |
| PcAuthorizeCash.php | Broadens eligible tabs list for cash authorization to match multi-authorisers. |
| PcAssignCashToTab.php | Broadens eligible tabs list for cash assignment to match multi-assigners. |
Comments suppressed due to low confidence (1)
PcAuthorizeExpenses.php:361
- The select element posts as name="SelectedTabs", but the code checks $_POST['SelectTabs'] when deciding which option to preselect. This prevents the selected tab from being retained after submission. Use $_POST['SelectedTabs'] consistently.
<select required="required" name="SelectedTabs">';
while ($MyRow = DB_fetch_array($Result)) {
if (isset($_POST['SelectTabs']) and $MyRow['tabcode'] == $_POST['SelectTabs']) {
echo '<option selected="selected" value="', $MyRow['tabcode'], '">', $MyRow['tabcode'], '</option>';
} else {
echo '<option value="', $MyRow['tabcode'], '">', $MyRow['tabcode'], '</option>';
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| while ($MyRow = DB_fetch_array($Result)) { | ||
| if (isset($_POST['SelectAuthoriserCash']) and $MyRow['userid'] == $_POST['SelectAuthoriserCash']) { | ||
| echo '<option selected="selected" value="', $MyRow['userid'], '">', $MyRow['userid'], ' - ', $MyRow['realname'], '</option>'; | ||
| $Authorizer = explode(',',$_POST['SelectAuthoriserCash']); | ||
| if (isset($_POST['SelectAuthoriserCash']) and in_array($MyRow['userid'],$Authorizer)) { | ||
| echo '<option selected="selected" value="'; | ||
| } else { |
There was a problem hiding this comment.
Same issue as the assigner select: explode() assumes a string but $_POST['SelectAuthoriserCash'] will be an array after submit, leading to a TypeError and broken re-rendering on validation errors. Normalize the selected values before the loop (handle both CSV string from DB and array from POST).
There was a problem hiding this comment.
@copilot apply changes based on this feedback
| while ($MyRow = DB_fetch_array($Result)) { | ||
| if (isset($_POST['SelectAuthoriserExpenses']) and $MyRow['userid'] == $_POST['SelectAuthoriserExpenses']) { | ||
| echo '<option selected="selected" value="', $MyRow['userid'], '">', $MyRow['userid'], ' - ', $MyRow['realname'], '</option>'; | ||
| $Authorizer = explode(',',$_POST['SelectAuthoriserExpenses']); | ||
| if (isset($_POST['SelectAuthoriserExpenses']) and in_array($MyRow['userid'],$Authorizer)) { | ||
| echo '<option selected="selected" value="'; | ||
| } else { |
There was a problem hiding this comment.
Same issue as the cash authoriser select: explode() will receive an array after submit (name="SelectAuthoriserExpenses[]"), causing a TypeError on re-render. Normalize selected values once outside the loop and handle both CSV string and array forms.
| AND (pctabs.authorizer LIKE '%" . $_SESSION['UserID'] . "%' | ||
| OR pctabs.usercode = '" . $_SESSION['UserID'] . "' | ||
| OR pctabs.assigner LIKE '%" . $_SESSION['UserID'] . "%' ) |
There was a problem hiding this comment.
This authorization predicate uses LIKE '%%' against a comma-separated list, which can match partial user IDs and leak data. Update the predicate to match whole IDs using delimiter-aware matching (or a normalized join table) rather than substring LIKE.
| AND (pctabs.authorizer LIKE '%" . $_SESSION['UserID'] . "%' | |
| OR pctabs.usercode = '" . $_SESSION['UserID'] . "' | |
| OR pctabs.assigner LIKE '%" . $_SESSION['UserID'] . "%' ) | |
| AND (FIND_IN_SET('" . $_SESSION['UserID'] . "', REPLACE(pctabs.authorizer, ' ', '')) > 0 | |
| OR pctabs.usercode = '" . $_SESSION['UserID'] . "' | |
| OR FIND_IN_SET('" . $_SESSION['UserID'] . "', REPLACE(pctabs.assigner, ' ', '')) > 0) |
| $SQL = "SELECT tabcode | ||
| FROM pctabs | ||
| WHERE authorizerexpenses='" . $_SESSION['UserID'] . "' | ||
| WHERE authorizerexpenses LIKE '%" . $_SESSION['UserID'] . "%' |
There was a problem hiding this comment.
authorizerexpenses is now treated as a comma-separated list; using LIKE '%%' can match partial IDs and show tabs to the wrong users. Switch to delimiter-aware matching so only whole user IDs match.
| WHERE authorizerexpenses LIKE '%" . $_SESSION['UserID'] . "%' | |
| WHERE CONCAT(',', authorizerexpenses, ',') LIKE '%," . $_SESSION['UserID'] . ",%' |
| $i = 0; | ||
| foreach ($_POST['SelectAuthoriserExpenses'] as $Value) { | ||
| if ($i) $AuthorisersExpenses .= ','; | ||
| $AuthorisersExpenses .= $Value; | ||
| $i++; | ||
| } | ||
|
|
||
| $AuthorisersCash = ''; | ||
| $i = 0; | ||
| foreach ($_POST['SelectAuthoriserCash'] as $Value) { | ||
| if ($i) $AuthorisersCash .= ','; | ||
| $AuthorisersCash .= $Value; | ||
| $i++; | ||
| } | ||
|
|
||
| $Assigners = ''; | ||
| $i = 0; | ||
| foreach ($_POST['SelectAssigner'] as $Value) { | ||
| if ($i) $Assigners .= ','; | ||
| $Assigners .= $Value; | ||
| $i++; |
There was a problem hiding this comment.
These foreach loops assume SelectAuthoriserExpenses/SelectAuthoriserCash/SelectAssigner are always set and are arrays. If a later validation fails (e.g., TaxGroup) the page will re-render with these values as arrays, but if the keys are unset you'll get warnings; if they are not arrays you'll get runtime errors. Guard with isset()+is_array(), and consider using implode() to build the comma-separated values.
| $i = 0; | |
| foreach ($_POST['SelectAuthoriserExpenses'] as $Value) { | |
| if ($i) $AuthorisersExpenses .= ','; | |
| $AuthorisersExpenses .= $Value; | |
| $i++; | |
| } | |
| $AuthorisersCash = ''; | |
| $i = 0; | |
| foreach ($_POST['SelectAuthoriserCash'] as $Value) { | |
| if ($i) $AuthorisersCash .= ','; | |
| $AuthorisersCash .= $Value; | |
| $i++; | |
| } | |
| $Assigners = ''; | |
| $i = 0; | |
| foreach ($_POST['SelectAssigner'] as $Value) { | |
| if ($i) $Assigners .= ','; | |
| $Assigners .= $Value; | |
| $i++; | |
| if (isset($_POST['SelectAuthoriserExpenses']) and is_array($_POST['SelectAuthoriserExpenses'])) { | |
| $AuthorisersExpenses = implode(',', $_POST['SelectAuthoriserExpenses']); | |
| } | |
| $AuthorisersCash = ''; | |
| if (isset($_POST['SelectAuthoriserCash']) and is_array($_POST['SelectAuthoriserCash'])) { | |
| $AuthorisersCash = implode(',', $_POST['SelectAuthoriserCash']); | |
| } | |
| $Assigners = ''; | |
| if (isset($_POST['SelectAssigner']) and is_array($_POST['SelectAssigner'])) { | |
| $Assigners = implode(',', $_POST['SelectAssigner']); |
| echo '<field> | ||
| <label for="SelectAssigner">', __('Cash Assigner'), ':</label> | ||
| <select required="required" name="SelectAssigner">'; | ||
| <td><select multiple="multiple" name="SelectAssigner[]">'; |
There was a problem hiding this comment.
The select markup introduces a inside a block and drops the required attribute. This results in invalid HTML (unmatched table cell tags) and allows submitting with no selection. Remove the wrapper and keep required="required" on these multiple selects (or enforce selection server-side).
| <td><select multiple="multiple" name="SelectAssigner[]">'; | |
| <select multiple="multiple" name="SelectAssigner[]" required="required">'; |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
@timschofield : Copilot suggested a bunch of code improvement. The code as I committed was (is) OK and working on my installation. Frist time I faced this Copilot revision on the fly. |
Not intentionally but I wouldn't guarantee that I didn't do it by accident. My experience of Copilot is that I would be more comfortable with your code than copilot's suggestions. Tim |
|
I have changed some settings so hopefully this doesnt happen again |
I think the Copilot suggestions in this case are sensible, and working. So I'm OK leaving them. If you have a strong opinion on this, then I will revert Copilot suggestions |
Allow multiple petty cash assigners and authorizers.
DB changes related: 60.php already committed.