public function printItemBody($id) { global $dbh; $return = '<section> <h2>Expenses</h2> <div class="sectionData"> <table class="dataTable stripe row-border"> <thead> <tr> <th class="dateTimeHeader textLeft">Time</th> <th class="textLeft">Order</th> <th class="textLeft">Employee</th> </tr> </thead> <tbody>'; $sth = $dbh->prepare('SELECT expenseID, employeeID, date FROM expenses WHERE supplierID = :supplierID AND active = 1'); $sth->execute([':supplierID' => $id]); while ($row = $sth->fetch()) { $return .= '<tr><td data-sort="' . $row['date'] . '">' . formatDateTime($row['date']) . '</td>'; $return .= '<td>' . getLinkedName('expense', $row['expenseID']) . '</td>'; $return .= '<td>' . getLinkedName('employee', $row['employeeID']) . '</td></tr>'; } $return .= '</tbody> </table> </div> </section>'; return $return; }
public function printItemBody($id) { global $dbh; global $TYPES; $return = '<section> <h2>Inventory</h2> <div class="sectionData"> <table class="dataTable stripe row-border"> <thead> <tr> <th class="textLeft">Location</th> <th class="textRight">Quantity</th> </tr> </thead> <tbody>'; $sth = $dbh->prepare('SELECT * FROM locations_products WHERE productID = :productID'); $sth->execute([':productID' => $id]); while ($row = $sth->fetch()) { $return .= '<tr><td>' . getLinkedName('location', $row['locationID']) . '</td>'; $return .= '<td class="textRight">' . $row['quantity'] . '</td></tr>'; } $return .= '</tbody> </table> </div> </section>'; return $return; }
function parseValue($type, $item) { //htmlspecialchars is in the object function global $TYPES; $factoryItem = Factory::createItem($type); $parsed = $factoryItem->parseValue($type, $item); foreach ($parsed as $field => $value) { if (isset($TYPES[$type]['fields'][$field]) && $TYPES[$type]['fields'][$field]['typeData'][0] == 'id') { $parsed[$field] = !is_null($value) ? getLinkedName($TYPES[$type]['fields'][$field]['typeData'][1], $value) : ''; } } return $parsed; }
public function printAttachments($type, $id) { global $dbh; global $SETTINGS; $return = ''; $allowsAttachments = in_array($type, ['employee', 'order', 'expense']); //anything that has an attachment, show it with a delete option $sth = $dbh->prepare('SELECT attachmentID, employeeID, uploadTime, name, extension FROM attachments WHERE type = :type AND id = :id'); $sth->execute([':type' => $type, ':id' => $id]); $result = $sth->fetchAll(); $hasAttachments = count($result) > 0 ? true : false; //if type currently allows attachments OR already has attachments, build the section if ($allowsAttachments || $hasAttachments) { $addStr = $allowsAttachments == true ? 'class="controlAdd addEnabled" href="#"' : 'class="controlAdd addDisabled" href="#" title="This item type is not currently configured to allow attachments."'; $return = '<section> <h2>Attachments</h2> <div class="sectionData"> <div class="customAddLink" id="addAttachment"><a ' . $addStr . '>Add Attachment</a></div> <table class="attachmentTable" style="width:100%;"> <thead> <tr> <th class="textLeft">Attachment</th> <th class="textLeft">Added By</th> <th class="textLeft">Uploaded</th> <th></th> </tr> </thead> <tbody>'; if ($hasAttachments) { foreach ($result as $row) { $return .= '<tr><td><a href="attachment.php?id=' . $row['attachmentID'] . '">' . $row['name'] . '.' . $row['extension'] . '</a></td>'; $return .= '<td>' . getLinkedName('employee', $row['employeeID']) . '</td>'; $return .= '<td>' . formatDateTime($row['uploadTime']) . '</td>'; $return .= '<td class="textCenter"><a class="controlDelete deleteEnabled" href="#" data-id="' . $row['attachmentID'] . '"></a></td></tr>'; } } $return .= '</tbody> </table> </div> </section>'; } return $return; }
public function parseSubTypeValue($subType, $action, $item, $format) { global $TYPES; $dataStr = ''; $parsed = []; foreach ($item as $field => $value) { //check to see if it's an id first, then do the switch statement if (isset($TYPES['order']['subTypes'][$subType]['fields'][$field]) && $TYPES['order']['subTypes'][$subType]['fields'][$field]['verifyData'][1] == 'id') { $parsed[$field] = !is_null($value) ? getLinkedName($TYPES['order']['subTypes'][$subType]['fields'][$field]['verifyData'][2], $value) : ''; } else { if ($subType == 'payment') { switch ($field) { case 'date': $parsed[$field] = formatDate($value); break; case 'paymentType': if ($value == 'CA') { $parsed[$field] = 'Cash'; } elseif ($value == 'CH') { $parsed[$field] = 'Check'; } elseif ($value == 'CR') { $parsed[$field] = 'Credit Card'; } break; case 'paymentAmount': $parsed[$field] = formatCurrency($value); break; default: $parsed[$field] = $value; } } elseif ($subType == 'product') { switch ($field) { case 'unitPrice': $parsed[$field] = formatCurrency($value); break; case 'quantity': $parsed[$field] = formatNumber($value); break; case 'recurring': if ($value == 'yes') { $parsed[$field] = 'Yes'; } elseif ($value == 'no') { $parsed[$field] = 'No'; } break; case 'interval': if ($value == 'monthly') { $parsed[$field] = 'Monthly'; } break; case 'startDate': case 'endDate': $parsed[$field] = formatDate($value); break; default: $parsed[$field] = $value; } } elseif ($subType == 'service') { switch ($field) { case 'unitPrice': $parsed[$field] = formatCurrency($value); break; case 'quantity': $parsed[$field] = formatNumber($value); break; case 'recurring': if ($value == 'yes') { $parsed[$field] = 'Yes'; } elseif ($value == 'no') { $parsed[$field] = 'No'; } break; case 'interval': if ($value == 'monthly') { $parsed[$field] = 'Monthly'; } break; case 'startDate': case 'endDate': $parsed[$field] = formatDate($value); break; default: $parsed[$field] = $value; } } elseif ($subType == 'discountOrder') { switch ($field) { case 'subID': break; default: $parsed[$field] = $value; } } else { $parsed[$field] = $value; } if (isset($parsed[$field]) && $field != 'paymentAmount' && $field != 'unitPrice') { $parsed[$field] = htmlspecialchars($parsed[$field], ENT_QUOTES | ENT_HTML5, 'UTF-8'); } } } if ($format == 'str') { //if we want a string format if ($action == 'A') { $dataStr = 'Added '; } elseif ($action == 'E') { $dataStr = 'Edited '; } elseif ($action == 'D') { $dataStr = 'Deleted '; } if ($subType == 'payment') { $dataStr .= 'payment. '; } elseif ($subType == 'product') { $dataStr .= 'product. '; } elseif ($subType == 'service') { $dataStr .= 'service. '; } elseif ($subType == 'discountOrder') { $dataStr .= $action == 'A' ? 'discount to the order. ' : 'discount from the order. '; } elseif ($subType == 'discountProduct' || $subType == 'discountService') { $dataStr .= 'discount. '; } elseif ($subType == 'attachment') { $dataStr .= 'attachment ' . $parsed['name'] . '.' . $parsed['extension'] . '.'; } foreach ($parsed as $key => $value) { if ($subType != 'attachment') { $dataStr .= '<b>' . $TYPES['order']['subTypes'][$subType]['fields'][$key]['formalName'] . ':</b> ' . $value . ' '; } } return $dataStr; } else { //otherwise return the array return $parsed; } }
if ($_POST['action'] == 'history') { $return = ['status' => 'success', 'html' => '']; $limit = (int) $_POST['limit']; //cast as int because we can't use a placeholder for LIMIT $limit = $limit < 0 || $limit > 10000 ? 10000 : $limit; $sth = $dbh->prepare('SELECT * FROM changes WHERE type = :type AND id = :id ORDER BY changeTime DESC LIMIT ' . $limit); $sth->execute([':type' => $_POST['type'], ':id' => $_POST['id']]); $result = $sth->fetchAll(); $parsed = parseHistory($_POST['type'], $result); foreach ($parsed as $row) { $return['html'] .= '<tr><td data-sort="' . $row['changeTime'] . '">' . formatDateTime($row['changeTime']) . '</td>'; $return['html'] .= '<td>' . getLinkedName('employee', $row['employeeID']) . '</td>'; $return['html'] .= '<td>' . $row['data'] . '</td></tr>'; } echo json_encode($return); } /* Function: addAttachment Inputs: Outputs: */ if ($_POST['action'] == 'addAttachment') { $return = ['status' => 'fail']; if ($_FILES['uploadFile']['error'] == 0) { $pos = strrpos($_FILES['uploadFile']['name'], '.'); $name = $pos !== false ? substr($_FILES['uploadFile']['name'], 0, $pos) : $_FILES['uploadFile']['name']; $extension = $pos !== false ? substr($_FILES['uploadFile']['name'], $pos + 1) : '';
<thead> <tr> <th class="textLeft">Expense</th> <th class="textLeft">Supplier</th> <th class="textRight">Amount</th> </tr> </thead> <tbody>'; //TODO: sort by expense creation date? $sth = $dbh->prepare('SELECT expenseID, supplierID, amountDue FROM expenses WHERE amountDue > 0 AND expenses.active = 1'); $sth->execute(); while ($row = $sth->fetch()) { $return['content'] .= '<tr><td><a href="item.php?type=expense&id=' . $row['expenseID'] . '">Expense #' . $row['expenseID'] . '</a></td>'; $return['content'] .= '<td>' . getLinkedName('supplier', $row['supplierID']) . '</td>'; $return['content'] .= '<td class="textRight">' . formatCurrency($row['amountDue']) . '</td></tr>'; } $return['content'] .= '</tbody> </table>'; echo json_encode($return); } /* Net Income */ if ($_POST['module'] == 'netIncome') { $return['title'] = 'Net Income'; $return['content'] = 'WIP'; $unix = mktime(0, 0, 0, 1, 1, date('Y')); if ($SETTINGS['accounting'] == 'cash') { //income $sth = $dbh->prepare('SELECT SUM(paymentAmount) AS total FROM orderPayments
?> </tr> </thead> <tbody> <?php $sth = $dbh->prepare('SELECT * FROM ' . $TYPES[$_GET['type']]['pluralName'] . ' WHERE active = 1'); $sth->execute(); while ($row = $sth->fetch()) { $id = $row[$TYPES[$_GET['type']]['idName']]; $item = parseValue($_GET['type'], $row); echo '<tr><td class="selectCol"><input type="checkbox" class="selectCheckbox" id="' . $id . '"></td>'; foreach ($columns as $column) { if ($column == 'name' || $column == 'orderID' || $column == 'expenseID') { $temp = getLinkedName($_GET['type'], $id); } else { $temp = $item[$column]; } echo '<td>' . $temp . '</td>'; } echo '</tr>'; } ?> </tbody> </table> <?php require 'footer.php'; ?> </div> <div class="popup" id="defaultPopup">
public function customAjax($id, $data) { global $dbh; global $TYPES; global $SETTINGS; $return = ['status' => 'success']; if ($data['subAction'] == 'view') { //view subAction if ($data['subType'] == 'paystub') { $sth = $dbh->prepare('SELECT date, grossPay, firstDate, lastDate, payType, payAmount FROM paystubs, timesheets WHERE paystubID = :paystubID AND paystubs.timesheetID = timesheets.timesheetID'); $sth->execute([':paystubID' => $data['subID']]); $row = $sth->fetch(); $return['date'] = formatDate($row['date']); $return['grossPay'] = formatCurrency($row['grossPay'], true); $return['startDate'] = formatDate($row['firstDate']); $return['endDate'] = formatDate($row['lastDate']); $parsed = self::parseValue('employee', ['payType' => $row['payType'], 'payAmount' => $row['payAmount']]); $return['payType'] = $parsed['payType']; $return['payAmount'] = $parsed['payAmount']; $sth = $dbh->prepare('SELECT SUM(regularHours) AS regularHours, SUM(overtimeHours) AS overtimeHours, SUM(holidayHours) AS holidayHours, SUM(vacationHours) AS vacationHours FROM timesheetHours, paystubs WHERE paystubID = :paystubID AND paystubs.timesheetID = timesheetHours.timesheetID'); $sth->execute([':paystubID' => $data['subID']]); $row = $sth->fetch(); $return['regularHours'] = formatNumber($row['regularHours'] + 0) . ' hours'; $return['overtimeHours'] = formatNumber($row['overtimeHours'] + 0) . ' hours'; $return['holidayHours'] = formatNumber($row['holidayHours'] + 0) . ' hours'; $return['vacationHours'] = formatNumber($row['vacationHours'] + 0) . ' hours'; } elseif ($data['subType'] == 'timesheet') { $sth = $dbh->prepare('SELECT firstDate, lastDate, status FROM timesheets WHERE timesheetID = :timesheetID'); $sth->execute([':timesheetID' => $data['subID']]); $row = $sth->fetch(); $firstDate = $row['firstDate']; $lastDate = $row['lastDate']; $return['timesheetStatus'] = $row['status']; //this will fill in days with no hours automatically, no row in timesheetHours is needed $sth = $dbh->prepare('SELECT date, regularHours, overtimeHours, holidayHours, vacationHours FROM timesheetHours WHERE timesheetID = :timesheetID'); $sth->execute([':timesheetID' => $data['subID']]); while ($row = $sth->fetch()) { $hours[$row['date']] = [$row['regularHours'], $row['overtimeHours'], $row['holidayHours'], $row['vacationHours']]; } while ($firstDate <= $lastDate) { $table[$firstDate] = isset($hours[$firstDate]) ? $hours[$firstDate] : [0, 0, 0, 0]; $firstDate += 86400; } $typeArr = ['r', 'o', 'h', 'v']; $return['html'] = ''; foreach ($table as $day => $dayArr) { if ($return['timesheetStatus'] == 'E' || $return['timesheetStatus'] == 'P') { $return['html'] .= '<tr><td>' . formatDate($day) . ' ' . date('l', $day) . '</td>'; for ($i = 0; $i < 4; $i++) { $temp = empty($dayArr[$i] + 0) ? '' : formatNumber($dayArr[$i] + 0); $return['html'] .= '<td><input type="text" name="' . $typeArr[$i] . $day . '" autocomplete="off" value="' . $temp . '"></td>'; } $return['html'] .= '</tr>'; } else { $return['html'] .= '<tr><td>' . formatDate($day) . ' ' . date('l', $day) . '</td>'; for ($i = 0; $i < 4; $i++) { $temp = empty($dayArr[$i] + 0) ? '' : formatNumber($dayArr[$i] + 0); $return['html'] .= '<td>' . $temp . '</td>'; } $return['html'] .= '</tr>'; } } } } elseif ($data['subAction'] == 'edit') { if ($data['subType'] == 'timesheet') { $subID = $data['subID']; unset($data['subID']); unset($data['subAction']); unset($data['subType']); //make sure this timesheet has the correct status, get dates for later $sth = $dbh->prepare('SELECT employeeID, firstDate, lastDate, status FROM timesheets WHERE timesheetID = :timesheetID'); $sth->execute([':timesheetID' => $subID]); $row = $sth->fetch(); $employeeID = $row['employeeID']; $firstDate = $row['firstDate']; $lastDate = $row['lastDate']; $timesheetStatus = $row['status']; if ($timesheetStatus == 'E' || $timesheetStatus == 'P') { foreach ($data as $key => $value) { $hourType = substr($key, 0, 1); $ts = substr($key, 1); $value = $value == '' ? 0 : $value; //timesheet is not (and as far as I can think, cannot due to the many variable fields) be a subtype, so we need to manually clean and verify the data $value = str_replace($SETTINGS['thousandsSeparator'], '', $value); $value = str_replace($SETTINGS['decimalFormat'], '.', $value); if (filter_var($value, FILTER_VALIDATE_FLOAT) === false) { $return['status'] = 'fail'; $return[$key] = 'Must be a decimal'; } else { $temp = strrpos($value, '.'); if ($temp === false) { $value .= '.'; $temp = strrpos($value, '.'); } $length = strlen(substr($value, $temp + 1)); if ($length < 2) { $value .= str_repeat('0', 2 - $length); $length = strlen(substr($value, $temp + 1)); } if ($length > 2) { $return['status'] = 'fail'; $return[$key] = 'Must have 2 or fewer digits after the decimal'; } else { if ($value < 0 || $value > 24) { $return['status'] = 'fail'; $return[$key] = 'Must be between 0 and 24'; } } } $typeArr = ['r', 'o', 'h', 'v']; $i = array_search($hourType, $typeArr); if ($i === false) { //if we don't get the right hour type, fail with no error because this would never happen normally $return['status'] = 'fail'; } else { $newHours[$ts][$i] = $value; } } } else { $return['status'] = 'fail'; } //get old hours and then do the update if ($return['status'] != 'fail') { $sth = $dbh->prepare('SELECT date, regularHours, overtimeHours, holidayHours, vacationHours FROM timesheetHours WHERE timesheetID = :timesheetID'); $sth->execute([':timesheetID' => $subID]); while ($row = $sth->fetch()) { $oldHours[$row['date']] = [$row['regularHours'], $row['overtimeHours'], $row['holidayHours'], $row['vacationHours']]; } while ($firstDate <= $lastDate) { $oldHours[$firstDate] = isset($oldHours[$firstDate]) ? $oldHours[$firstDate] : [0, 0, 0, 0]; $firstDate += 86400; } //TODO: check to see if employee has enough vacation time to make the change //need to do it in a foreach loop right here because we need the oldHours to detect the change in vacation time and also do it before we start changing the db //loop through old hours because we know the ts will be right, whereas the ts in new hours could be malicious foreach ($oldHours as $key => $value) { if ($oldHours[$key][0] != $newHours[$key][0] || $oldHours[$key][1] != $newHours[$key][1] || $oldHours[$key][2] != $newHours[$key][2] || $oldHours[$key][3] != $newHours[$key][3]) { if ($oldHours[$key][0] == 0 && $oldHours[$key][1] == 0 && $oldHours[$key][2] == 0 && $oldHours[$key][3] == 0) { //no hours -> some hours $sth = $dbh->prepare('INSERT INTO timesheetHours (timesheetID, date, regularHours, overtimeHours, holidayHours, vacationHours) VALUES(:timesheetID, :date, :regular, :overtime, :holiday, :vacation)'); $sth->execute([':timesheetID' => $subID, ':date' => $key, ':regular' => $newHours[$key][0], ':overtime' => $newHours[$key][1], ':holiday' => $newHours[$key][2], ':vacation' => $newHours[$key][3]]); } elseif ($newHours[$key][0] == 0 && $newHours[$key][1] == 0 && $newHours[$key][2] == 0 && $newHours[$key][3] == 0) { //some hours -> no hours $sth = $dbh->prepare('DELETE FROM timesheetHours WHERE timesheetID = :timesheetID AND date = :date'); $sth->execute([':timesheetID' => $subID, ':date' => $key]); } else { //some hours -> different hours $sth = $dbh->prepare('UPDATE timesheetHours SET regularHours = :regular, overtimeHours = :overtime, holidayHours = :holiday, vacationHours = :vacation WHERE timesheetID = :timesheetID AND date = :date'); $sth->execute([':regular' => $newHours[$key][0], ':overtime' => $newHours[$key][1], ':holiday' => $newHours[$key][2], ':vacation' => $newHours[$key][3], ':timesheetID' => $subID, ':date' => $key]); } } } } } } elseif ($data['subAction'] == 'approve') { if ($data['subType'] == 'timesheet') { $sth = $dbh->prepare('UPDATE timesheets SET status = "A" WHERE timesheetID = :timesheetID'); $sth->execute([':timesheetID' => $data['subID']]); } } elseif ($data['subAction'] == 'changesMadeHistory') { $return['html'] = ''; $limit = (int) $_POST['limit'] == -1 ? 100000 : (int) $_POST['limit']; //cast as int because we can't use a placeholder for LIMIT $sth = $dbh->prepare('SELECT * FROM changes WHERE employeeID = :employeeID ORDER BY changeTime DESC LIMIT ' . $limit); $sth->execute([':employeeID' => $id]); while ($row = $sth->fetch()) { $parsed = parseHistory($row['type'], [$row]); $return['html'] .= '<tr><td data-sort="' . $row['changeTime'] . '">' . formatDateTime($row['changeTime']) . '</td>'; $return['html'] .= '<td>' . getLinkedName($row['type'], $row['id']) . '</td>'; $return['html'] .= '<td>' . $TYPES[$row['type']]['formalName'] . '</td>'; $return['html'] .= '<td>' . $parsed[0]['data'] . '</td></tr>'; } } return $return; }
public function customAjax($id, $data) { global $dbh; global $TYPES; $return = ['status' => 'success']; if ($data['subAction'] == 'add') { //add subAction //TODO: this could possibly be a subType, right now it looks like the dateTime verify type is stopping it, but I'll wait to see when I do more here if ($data['date'] == '') { $return['status'] = 'fail'; $return['date'] = 'Required'; } if ($data['startTime'] == '') { $return['status'] = 'fail'; $return['startTime'] = 'Required'; } if ($data['endTime'] == '') { $return['status'] = 'fail'; $return['endTime'] = 'Required'; } $startDate = DateTime::createFromFormat($SETTINGS['dateTimeFormat'] . '|', $data['date'] . ' ' . $data['startTime']); $startTS = $startDate->getTimestamp(); $endDate = DateTime::createFromFormat($SETTINGS['dateTimeFormat'] . '|', $data['date'] . ' ' . $data['endTime']); $endTS = $endDate->getTimestamp(); if ($return['status'] != 'fail') { if ($startDate === false || $endDate === false) { $return['status'] = 'fail'; $return['date'] = 'Unrecognized date/time format.'; } else { if ($endTS < $startTS) { $return['status'] = 'fail'; $return['endTime'] = 'End Time must be after Start Time.'; } if ($return['status'] != 'fail') { $sth = $dbh->prepare('INSERT INTO vacationRequests (employeeID, submitTime, startTime, endTime, status) VALUES(:employeeID, UNIX_TIMESTAMP(), :startTime, :endTime, "P")'); $sth->execute([':employeeID' => $id, ':startTime' => $startTS, ':endTime' => $endTS]); //TODO: should a call to addChange be here? or is it already logged enough? } } } } elseif ($data['subAction'] == 'changesMadeHistory') { $return['html'] = ''; $limit = (int) $_POST['limit'] == -1 ? 100000 : (int) $_POST['limit']; //cast as int because we can't use a placeholder for LIMIT $sth = $dbh->prepare('SELECT * FROM changes WHERE employeeID = :employeeID ORDER BY changeTime DESC LIMIT ' . $limit); $sth->execute([':employeeID' => $id]); while ($row = $sth->fetch()) { $parsed = parseHistory($row['type'], [$row]); $return['html'] .= '<tr><td data-sort="' . $row['changeTime'] . '">' . formatDateTime($row['changeTime']) . '</td>'; $return['html'] .= '<td>' . getLinkedName($row['type'], $row['id']) . '</td>'; $return['html'] .= '<td>' . $TYPES[$row['type']]['formalName'] . '</td>'; $return['html'] .= '<td>' . $parsed[0]['data'] . '</td></tr>'; } } return $return; }