Merge branch 'itflow-org:master' into 0.1.8.2

This commit is contained in:
Andrew Malsbury 2024-02-05 09:18:52 -06:00 committed by GitHub
commit 50b2c3ad6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 271 additions and 29 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
node_modules
config.php
uploads/favicon.ico
uploads/clients/*
!uploads/clients/index.php
uploads/expenses/*

View File

@ -0,0 +1,83 @@
<?php
// Variable assignment from POST (or: blank/from DB is updating)
if (isset($_POST['client_name'])) {
$name = sanitizeInput($_POST['client_name']);
} elseif ($client_row) {
$name = $client_row['client_name'];
} else {
$name = '';
}
if (isset($_POST['client_type'])) {
$type = sanitizeInput($_POST['client_type']);
} elseif ($client_row) {
$type = $client_row['client_type'];
} else {
$type = '';
}
if (isset($_POST['client_website'])) {
$website = preg_replace("(^https?://)", "", sanitizeInput($_POST['client_website']));
} elseif ($client_row) {
$website = $client_row['client_website'];
} else {
$website = '';
}
if (isset($_POST['client_referral'])) {
$referral = sanitizeInput($_POST['client_referral']);
} elseif ($client_row) {
$referral = $client_row['client_referral'];
} else {
$referral = '';
}
if (isset($_POST['client_rate'])) {
$rate = floatval($_POST['client_rate']);
} elseif ($client_row) {
$rate = $client_row['client_rate'];
} else {
$rate = '';
}
if (isset($_POST['client_currency_code'])) {
$currency_code = sanitizeInput($_POST['client_currency_code']);
} elseif ($client_row) {
$currency_code = $client_row['client_currency_code'];
} else {
$currency_code = '';
}
if (isset($_POST['client_net_terms'])) {
$net_terms = intval($_POST['client_net_terms']);
} elseif ($client_row) {
$net_terms = $client_row['client_net_terms'];
} else {
$net_terms = '';
}
if (isset($_POST['client_tax_id_number'])) {
$tax_id_number = sanitizeInput($_POST['client_tax_id_number']);
} elseif ($client_row) {
$tax_id_number = $client_row['client_tax_id_number'];
} else {
$tax_id_number = '';
}
if (isset($_POST['client_is_lead'])) {
$lead = intval($_POST['client_is_lead']);
} elseif ($client_row) {
$lead = $client_row['client_is_lead'];
} else {
$lead = 0; // Default: Not a lead
}
if (isset($_POST['client_notes'])) {
$notes = sanitizeInput($_POST['client_notes']);
} elseif ($client_row) {
$notes = $client_row['client_notes'];
} else {
$notes = '';
}

31
api/v1/clients/create.php Normal file
View File

@ -0,0 +1,31 @@
<?php
require_once '../validate_api_key.php';
require_once '../require_post_method.php';
// Parse Info
require_once 'client_model.php';
// Default
$insert_id = false;
// To add a client, we just need a name and an "ANY CLIENT" API key
if (!empty($name) && $client_id == 0) {
// Insert client
$insert_sql = mysqli_query($mysqli, "INSERT INTO clients SET client_name = '$name', client_type = '$type', client_website = '$website', client_referral = '$referral', client_rate = $rate, client_currency_code = '$currency_code', client_net_terms = $net_terms, client_tax_id_number = '$tax_id_number', client_lead = $lead, client_notes = '$notes', client_accessed_at = NOW()");
// Check insert & get insert ID
if ($insert_sql) {
$insert_id = mysqli_insert_id($mysqli);
//Logging
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Client', log_action = 'Created', log_description = '$name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $insert_id");
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'API', log_action = 'Success', log_description = 'Created client $name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $insert_id");
}
}
// Output
require_once '../create_output.php';

View File

@ -9,6 +9,6 @@ if ($_SERVER['REQUEST_METHOD'] !== "POST") {
// Client ID must be specific for INSERT/UPDATE/DELETE queries
// If this API key allows any client, set $client_id to the one specified, else leave it
if ($client_id == 0) {
if ($client_id == 0 && isset($_POST['client_id'])) {
$client_id = intval($_POST['client_id']);
}
}

View File

@ -1,5 +1,5 @@
<div class="modal" id="addServiceModal" tabindex="-1">
<div class="modal-dialog modal-md">
<div class="modal-dialog">
<div class="modal-content bg-dark">
<div class="modal-header">
<h5 class="modal-title text-white"><i class="fa fa-fw fa-stream mr-2"></i>New Service</h5>
@ -141,10 +141,8 @@
</div>
<div class="tab-pane fade" id="pills-assets">
<div class="form-group">
<label for="assets">Select related assets</label>
<select class="form-control select2" id="assets" name="assets[]" multiple>
@ -157,7 +155,7 @@
}
?>
</select>
</div>
<div class="form-group">
<label for="logins">Select related logins</label>

View File

@ -30,8 +30,6 @@
<div class="tab-content">
<!-- //TODO: The multiple selects won't play nicely with the icons or just general formatting. I've just added blank <p> tags to format it better for now -->
<div class="tab-pane fade show active" id="pills-overview<?php echo $service_id ?>">
<div class="form-group">

View File

@ -446,7 +446,7 @@ if ($config_send_invoice_reminders == 1) {
// PAST DUE INVOICE Notifications
//$invoiceAlertArray = [$config_invoice_overdue_reminders];
$invoiceAlertArray = [30,60,90,120,150,180,210,240,270,300,330,360,390,420,450,480,510,540,570,590,620];
$invoiceAlertArray = [30,60,90,120,150,180,210,240,270,300,330,360,390,420,450,480,510,540,570,590,620,650,680,710,740];
foreach ($invoiceAlertArray as $day) {
@ -488,9 +488,9 @@ if ($config_send_invoice_reminders == 1) {
mysqli_query($mysqli, "UPDATE invoices SET invoice_amount = $new_invoice_amount WHERE invoice_id = $invoice_id");
//Insert Items into New Invoice
mysqli_query($mysqli, "INSERT INTO invoice_items SET item_name = 'Late Fee', item_description = '$config_invoice_late_fee_percent% late fee applied on $todays_date', item_quantity = 1, item_price = $late_fee_amount, item_total = $late_fee_amount, item_invoice_id = $invoice_id");
mysqli_query($mysqli, "INSERT INTO invoice_items SET item_name = 'Late Fee', item_description = '$config_invoice_late_fee_percent% late fee applied on $todays_date', item_quantity = 1, item_price = $late_fee_amount, item_total = $late_fee_amount, item_order = 998, item_invoice_id = $invoice_id");
mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Sent', history_description = 'Cron applied a late charge', history_invoice_id = $invoice_id");
mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Sent', history_description = 'Cron applied a late fee of $late_fee_amount', history_invoice_id = $invoice_id");
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Invoice Late Charge', notification = 'Invoice $invoice_prefix$invoice_number for $client_name in the amount of $invoice_amount was charged a late fee of $late_fee_amount', notification_action = 'invoice.php?invoice_id=$invoice_id', notification_client_id = $client_id, notification_entity_id = $invoice_id");

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -201,7 +201,7 @@ function truncate($text, $chars) {
}
function formatPhoneNumber($phoneNumber) {
$phoneNumber = preg_replace('/[^0-9]/', '', $phoneNumber);
$phoneNumber = $phoneNumber ? preg_replace('/[^0-9]/', '', $phoneNumber): "";
if (strlen($phoneNumber) > 10) {
$countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10);
@ -853,7 +853,7 @@ function calculateAccountBalance($mysqli, $account_id) {
$row = mysqli_fetch_array($sql_account);
$opening_balance = floatval($row['opening_balance']);
$account_id = intval($row['account_id']);
$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS total_payments FROM payments WHERE payment_account_id = $account_id");
$row = mysqli_fetch_array($sql_payments);
$total_payments = floatval($row['total_payments']);
@ -928,7 +928,7 @@ function generateReadablePassword($security_level) {
}
function addToMailQueue($mysqli, $data) {
foreach ($data as $email) {
$from = strval($email['from']);
$from_name = strval($email['from_name']);
@ -963,7 +963,7 @@ function calculateInvoiceBalance($mysqli, $invoice_id) {
"SELECT SUM(payment_amount) AS total_payments FROM payments
WHERE payment_invoice_id = $invoice_id
");
$row = mysqli_fetch_array($sql_payments);
$total_payments = floatval($row['total_payments']);
@ -976,4 +976,4 @@ function calculateInvoiceBalance($mysqli, $invoice_id) {
return $balance;
}
}

View File

@ -24,6 +24,14 @@ $browser = sanitizeInput(getWebBrowser($user_agent));
<title><?php echo nullable_htmlentities($config_app_name); ?></title>
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="/uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css">
<!-- Theme style -->

View File

@ -86,9 +86,12 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent
if ($config_stripe_client_pays_fees == 1) {
$balance_before_fees = $balance_to_pay;
// Calculate the Gateway fee
$gateway_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2);
$balance_to_pay = $balance_to_pay + $gateway_fee;
// See here for passing costs on to client https://support.stripe.com/questions/passing-the-stripe-fee-on-to-customers
// Calculate the amount to charge the client
$balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee);
// Calculate the fee amount
$gateway_fee = round($balance_to_pay - $balance_before_fees, 2);
}
//Round balance to pay to 2 decimal places
@ -276,10 +279,18 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent
// Check config to see if client pays fees is enabled or if should expense it
if ($config_stripe_client_pays_fees == 1) {
// Calculate gateway expense fee
$gateway_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2);
$balance_before_fees = $balance_to_pay;
// See here for passing costs on to client https://support.stripe.com/questions/passing-the-stripe-fee-on-to-customers
// Calculate the amount to charge the client
$balance_to_pay = $balance_to_pay + $gateway_fee;
$balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee);
// Calculate the fee amount
$gateway_fee = round($balance_to_pay - $balance_before_fees, 2);
// Add as line item to client Invoice
mysqli_query($mysqli,"INSERT INTO invoice_items SET item_name = 'Gateway Fees', item_description = 'Payment Gateway Fees', item_quantity = 1, item_price = $gateway_fee, item_subtotal = $gateway_fee, item_total = $gateway_fee, item_order = 999, item_invoice_id = $invoice_id");
// Update the Amount on the invoice to include the gateway fee
$new_invoice_amount = $invoice_amount + $gateway_fee;
mysqli_query($mysqli,"UPDATE invoices SET invoice_amount = $new_invoice_amount WHERE invoice_id = $invoice_id");
}
// Check to see if Expense Fields are configured and client pays fee is off then create expense

View File

@ -114,7 +114,14 @@ $amount_paid = floatval($row['amount_paid']);
$balance = $invoice_amount - $amount_paid;
// Calculate Gateway Fee
$gateway_fee = round($balance * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2);
if ($config_stripe_client_pays_fees == 1) {
$balance_before_fees = $balance;
// See here for passing costs on to client https://support.stripe.com/questions/passing-the-stripe-fee-on-to-customers
// Calculate the amount to charge the client
$balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee);
// Calculate the fee amount
$gateway_fee = round($balance_to_pay - $balance_before_fees, 2);
}
//check to see if overdue
$invoice_color = $invoice_badge_color; // Default

View File

@ -18,6 +18,14 @@ header("X-Frame-Options: DENY");
<title><?php echo nullable_htmlentities($session_company_name); ?> | <?php echo nullable_htmlentities($config_app_name); ?></title>
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="/uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css">

View File

@ -1,10 +1,10 @@
<div class="modal fade" id="confirmationModal" tabindex="-1" role="dialog" aria-labelledby="confirmationModalLabel" aria-hidden="true">
<div class="modal fade" id="confirmationModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmationModalLabel">Confirm</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">

View File

@ -272,6 +272,15 @@ if (isset($_POST['login'])) {
<!-- Font Awesome -->
<link rel="stylesheet" href="plugins/fontawesome-free/css/all.min.css">
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="/uploads/favicon.ico">
<?php } ?>
<!-- Theme style -->
<link rel="stylesheet" href="dist/css/adminlte.min.css">
<!-- Google Font: Source Sans Pro -->

View File

@ -88,6 +88,14 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['login'])) {
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('../uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="../uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome -->
<link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">

View File

@ -186,6 +186,14 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") {
<!-- Font Awesome -->
<link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('../uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="../uploads/favicon.ico">
<?php } ?>
<!-- Theme style -->
<link rel="stylesheet" href="../dist/css/adminlte.min.css">

View File

@ -18,6 +18,14 @@ header("X-Frame-Options: DENY"); // Legacy
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<!--
Favicon
If Fav Icon exists else use the default one
-->
<?php if(file_exists('../uploads/favicon.ico')) { ?>
<link rel="icon" type="image/x-icon" href="../uploads/favicon.ico">
<?php } ?>
<!-- Font Awesome -->
<link rel="stylesheet" href="../plugins/fontawesome-free/css/all.min.css">

View File

@ -325,6 +325,46 @@ if (isset($_POST['edit_theme_settings'])) {
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_POST['edit_favicon_settings'])) {
validateCSRFToken($_POST['csrf_token']);
validateAdminRole();
// Check to see if a file is attached
if ($_FILES['file']['tmp_name'] != '') {
if ($new_file_name = checkFileUpload($_FILES['file'], array('ico'))) {
$file_tmp_path = $_FILES['file']['tmp_name'];
// Delete old file
if(file_exists("uploads/favicon.ico")) {
unlink("uploads/favicon.ico");
}
// directory in which the uploaded file will be moved
$upload_file_dir = "uploads/";
//Force File Name
$new_file_name = "favicon.ico";
$dest_path = $upload_file_dir . $new_file_name;
move_uploaded_file($file_tmp_path, $dest_path);
$_SESSION['alert_message'] = 'File successfully uploaded.';
}else{
$_SESSION['alert_message'] = 'There was an error moving the file to upload directory. Please make sure the upload directory is writable by web server.';
}
}
//Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name updated the favicon', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id");
$_SESSION['alert_message'] = "You updated the favicon";
header("Location: " . $_SERVER["HTTP_REFERER"]);
}
if (isset($_POST['edit_notification_settings'])) {
validateCSRFToken($_POST['csrf_token']);

View File

@ -74,6 +74,7 @@ require_once "inc_all_settings.php";
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="config_stripe_percentage_fee" placeholder="Enter Percentage" value="<?php echo $config_stripe_percentage_fee * 100; ?>">
</div>
<small class="form-text text-muted">Please click <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
@ -84,13 +85,14 @@ require_once "inc_all_settings.php";
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="config_stripe_flat_fee" placeholder="0.030" value="<?php echo number_format($config_stripe_flat_fee, 2, '.', ''); ?>">
</div>
<small class="form-text text-muted">Please click <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
<div class="form-group">
<label>Client Pays Fees <small class="muted">(if disabled you may choose to expense the selected account)</small></label>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="config_stripe_client_pays_fees" <?php if ($config_stripe_client_pays_fees == 1) { echo "checked"; } ?> value="1" id="clientPaysFeesSwitch">
<label class="custom-control-label" for="clientPaysFeesSwitch">Enable</label>
<label class="custom-control-label" for="clientPaysFeesSwitch">Enable Client Pays Fees</label>
<small class="form-text text-muted">Note: It is illegal to pass payment gateway fees in certain countries, states and provinces. Please check with your local laws before enabling. Click <a href="https://support.stripe.com/questions/passing-the-stripe-fee-on-to-customers" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for more details.</small>
</div>
</div>

View File

@ -44,6 +44,28 @@ require_once "inc_all_settings.php";
</div>
</div>
<div class="card card-dark">
<div class="card-header py-3">
<h3 class="card-title"><i class="fas fa-fw fa-image mr-2"></i>Favicon</h3>
</div>
<div class="card-body">
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<img class="mb-3" src="<?php if(file_exists("uploads/favicon.ico")) { echo "uploads/favicon.ico"; } else { echo "favicon.ico"; } ?>">
<div class="form-group">
<input type="file" class="form-control-file" name="file" accept=".ico">
</div>
<hr>
<button type="submit" name="edit_favicon_settings" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Upload Icon</button>
</form>
</div>
</div>
<?php
require_once "footer.php";