+
+ CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.5'");
}
- // if (CURRENT_DATABASE_VERSION == '1.7.5') {
- // // Insert queries here required to update to DB version 1.7.6
+ if (CURRENT_DATABASE_VERSION == '1.7.5') {
+ mysqli_query($mysqli, "CREATE TABLE `client_stripe` (`client_id` INT(11) NOT NULL, `stripe_id` VARCHAR(255) NOT NULL, `stripe_pm` varchar(255) NULL) ENGINE = InnoDB CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci; ");
+
+ mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.6'");
+ }
+
+ // if (CURRENT_DATABASE_VERSION == '1.7.6') {
+ // // Insert queries here required to update to DB version 1.7.7
// // Then, update the database to the next sequential version
- // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.6'");
+ // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.7.7'");
// }
} else {
diff --git a/database_version.php b/database_version.php
index 589a6c56..61ca815b 100644
--- a/database_version.php
+++ b/database_version.php
@@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php
*/
-DEFINE("LATEST_DATABASE_VERSION", "1.7.5");
+DEFINE("LATEST_DATABASE_VERSION", "1.7.6");
diff --git a/db.sql b/db.sql
index 664915d8..6001fb86 100644
--- a/db.sql
+++ b/db.sql
@@ -342,6 +342,17 @@ CREATE TABLE `client_notes` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `client_stripe`
+--
+
+DROP TABLE IF EXISTS `client_stripe`;
+CREATE TABLE IF NOT EXISTS `client_stripe` (
+ `client_id` int(11) NOT NULL,
+ `stripe_id` varchar(255) NOT NULL,
+ `stripe_pm` varchar(255) NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
--
-- Table structure for table `client_tags`
--
diff --git a/guest/guest_pay_invoice_stripe.php b/guest/guest_pay_invoice_stripe.php
index c9ca5478..2b3065bb 100644
--- a/guest/guest_pay_invoice_stripe.php
+++ b/guest/guest_pay_invoice_stripe.php
@@ -279,7 +279,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent
// Add Payment to History
mysqli_query($mysqli, "INSERT INTO payments SET payment_date = '$pi_date', payment_amount = $pi_amount_paid, payment_currency_code = '$pi_currency', payment_account_id = $config_stripe_account, payment_method = 'Stripe', payment_reference = 'Stripe - $pi_id', payment_invoice_id = $invoice_id");
- mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Paid', history_description = 'Payment added - $ip - $os - $browser', history_invoice_id = $invoice_id");
+ mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Paid', history_description = 'Online Payment added (client) - $ip - $os - $browser', history_invoice_id = $invoice_id");
// Notify
appNotify("Invoice Paid", "Invoice $invoice_prefix$invoice_number has been paid by $client_name - $ip - $os - $browser", "invoice.php?invoice_id=$invoice_id", $pi_client_id);
@@ -313,7 +313,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent
if (!empty($config_smtp_host)) {
$subject = "Payment Received - Invoice $invoice_prefix$invoice_number";
- $body = "Hello $contact_name,
We have received your payment in the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
We have received online payment for the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
~ $company_name - Billing $config_invoice_from_email $company_phone";
$data = [
[
@@ -330,7 +330,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent
// Email the internal notification address too
if (!empty($config_invoice_paid_notification_email)) {
$subject = "Payment Received - $client_name - Invoice $invoice_prefix$invoice_number";
- $body = "Hello,
This is a notification that an invoice has been paid in ITFlow. Below is a copy of the receipt sent to the client:-
--------
Hello $contact_name,
We have received your payment in the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
This is a notification that an invoice has been paid in ITFlow. Below is a copy of the receipt sent to the client:-
--------
Hello $contact_name,
We have received online payment for the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
+
+
+
+
+ Save card details
+ In order to set up automatic payments, you must create a customer record in Stripe.
+ First, you must authorize Stripe to store your card details for the purpose of automatic payment.
+
+
+
+
+
+
+
+ elseif (empty($stripe_pm)) { ?>
+
+ Save card details
+ Please add the payment details you would like to save.
+ By adding payment details here, you grant consent for future automatic payments of invoices.
@@ -100,7 +106,6 @@ header("X-Frame-Options: DENY"); // Legacy
" alt="..." height="50" width="50" class="img-circle img-responsive">
-
diff --git a/portal/portal_post.php b/portal/portal_post.php
index d576bbad..eab9c817 100644
--- a/portal/portal_post.php
+++ b/portal/portal_post.php
@@ -4,8 +4,11 @@
* Process GET/POST requests
*/
-require_once "inc_portal.php";
-
+require_once '../config.php';
+require_once '../get_settings.php';
+require_once '../functions.php';
+require_once 'check_login.php';
+require_once 'portal_functions.php';
if (isset($_POST['add_ticket'])) {
@@ -327,6 +330,12 @@ if (isset($_POST['edit_profile'])) {
}
if (isset($_POST['add_contact'])) {
+
+ if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
$contact_name = sanitizeInput($_POST['contact_name']);
$contact_email = sanitizeInput($_POST['contact_email']);
$contact_technical = intval($_POST['contact_technical']);
@@ -368,6 +377,12 @@ if (isset($_POST['add_contact'])) {
}
if (isset($_POST['edit_contact'])) {
+
+ if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
$contact_id = intval($_POST['contact_id']);
$contact_name = sanitizeInput($_POST['contact_name']);
$contact_email = sanitizeInput($_POST['contact_email']);
@@ -413,3 +428,258 @@ if (isset($_POST['edit_contact'])) {
customAction('contact_update', $contact_id);
}
+
+if (isset($_POST['create_stripe_customer'])) {
+
+ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
+ // Get Stripe vars
+ $stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret FROM settings WHERE company_id = 1"));
+ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']);
+ $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']);
+
+ if (!$config_stripe_enable) {
+ header("Location: autopay.php");
+ exit();
+ }
+
+ // Include stripe SDK
+ require_once '../vendor/stripe-php-10.5.0/init.php';
+
+ // Get client's StripeID from database (should be none)
+ $stripe_client_details = mysqli_fetch_array(mysqli_query($mysqli, "SELECT stripe_id FROM client_stripe WHERE client_id = $session_client_id LIMIT 1"));
+ if (!$stripe_client_details) {
+
+ try {
+ // Initiate Stripe
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ // Create customer
+ $customer = $stripe->customers->create([
+ 'name' => $session_client_name,
+ 'email' => $session_contact_email,
+ 'metadata' => [
+ 'itflow_client_id' => $session_client_id,
+ 'consent' => $session_contact_name
+ ]
+ ]);
+
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception when creating customer record for $session_client_name: $error");
+ logApp("Stripe", "error", "Exception creating customer $session_client_name: $error");
+ }
+
+ // Get & Store customer ID
+ $stripe_id = sanitizeInput($customer->id);
+
+ mysqli_query($mysqli, "INSERT INTO client_stripe SET client_id = $session_client_id, stripe_id = '$stripe_id'");
+
+ // Logging
+ logAction("Stripe", "Create", "$session_contact_name created Stripe customer for $session_client_name as $stripe_id and authorised future automatic payments", $session_client_id, $session_client_id);
+
+ $_SESSION['alert_message'] = "Stripe customer created, thank you for your consent";
+
+ } else {
+ $_SESSION['alert_type'] = "danger";
+ $_SESSION['alert_message'] = "Stripe customer already exists";
+ }
+
+ header('Location: autopay.php');
+}
+
+if (isset($_GET['create_stripe_checkout'])) {
+
+ // This page is called by the autopay_setup_stripe.js, it returns a checkout session client secret
+
+ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
+ // Get Stripe vars
+ $stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret FROM settings WHERE company_id = 1"));
+ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']);
+ $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']);
+
+ if (!$config_stripe_enable) {
+ header("Location: autopay.php");
+ exit();
+ }
+
+ // Client Currency
+ $client_currency_details = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT client_currency_code FROM clients WHERE client_id = $session_client_id LIMIT 1"));
+ $client_currency = $client_currency_details['client_currency_code'];
+
+ // Define return URL that user is redirected to once payment method is verified by Stripe
+ $return_url = "https://$config_base_url/portal/portal_post.php?stripe_save_card&session_id={CHECKOUT_SESSION_ID}";
+
+ try {
+ // Initialize stripe
+ require_once '../vendor/stripe-php-10.5.0/init.php';
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ // Create checkout session (server side)
+ $checkout_session = $stripe->checkout->sessions->create([
+ 'currency' => $client_currency,
+ 'mode' => 'setup',
+ 'ui_mode' => 'embedded',
+ 'return_url' => $return_url,
+ ]);
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception when creating checkout session: $error");
+ logApp("Stripe", "error", "Exception creating checkout: $error");
+ }
+
+ // Return the client secret to the js script
+ echo json_encode(array('clientSecret' => $checkout_session->client_secret));
+
+ // No redirect & no point logging this
+}
+
+if (isset($_GET['stripe_save_card'])) {
+
+ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
+ // Get Stripe vars
+ $stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret FROM settings WHERE company_id = 1"));
+ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']);
+ $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']);
+
+ if (!$config_stripe_enable) {
+ header("Location: autopay.php");
+ exit();
+ }
+
+ // Get session ID from URL
+ $checkout_session_id = sanitizeInput($_GET['session_id']);
+
+ // Get client's StripeID from database
+ $stripe_client_details = mysqli_fetch_array(mysqli_query($mysqli, "SELECT stripe_id FROM client_stripe WHERE client_id = $session_client_id LIMIT 1"));
+ $client_stripe_id = sanitizeInput($stripe_client_details['stripe_id']);
+
+ try {
+ // Initialize stripe
+ require_once '../vendor/stripe-php-10.5.0/init.php';
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ // Retrieve checkout session
+ $checkout_session = $stripe->checkout->sessions->retrieve($checkout_session_id,[]);
+
+ // Get setup intent
+ $setup_intent_id = $checkout_session->setup_intent;
+
+ // Retrieve the setup intent details
+ $setup_intent = $stripe->setupIntents->retrieve($setup_intent_id, []);
+
+ // Get the payment method token
+ $payment_method = sanitizeInput($setup_intent->payment_method);
+
+ // Attach the payment method to the client in Stripe
+ $stripe->paymentMethods->attach($payment_method, ['customer' => $client_stripe_id]);
+
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception when adding payment method info: $error");
+ logApp("Stripe", "error", "Exception adding payment method: $error");
+ }
+
+ // Update ITFlow
+ mysqli_query($mysqli, "UPDATE client_stripe SET stripe_pm = '$payment_method' WHERE client_id = $session_client_id LIMIT 1");
+
+ // Get some card/payment method details for the email/logging
+ $payment_method_details = $stripe->paymentMethods->retrieve($payment_method);
+ $card_info = sanitizeInput($payment_method_details->card->display_brand) . " " . sanitizeInput($payment_method_details->card->last4);
+
+ // Send email confirmation
+
+ // Company Details & Settings
+ $sql_settings = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1");
+ $row = mysqli_fetch_array($sql_settings);
+ $company_name = sanitizeInput($row['company_name']);
+ $config_smtp_host = $row['config_smtp_host'];
+ $config_smtp_port = intval($row['config_smtp_port']);
+ $config_smtp_encryption = $row['config_smtp_encryption'];
+ $config_smtp_username = $row['config_smtp_username'];
+ $config_smtp_password = $row['config_smtp_password'];
+ $config_invoice_from_name = sanitizeInput($row['config_invoice_from_name']);
+ $config_invoice_from_email = sanitizeInput($row['config_invoice_from_email']);
+ $config_base_url = sanitizeInput($config_base_url);
+
+ if (!empty($config_smtp_host)) {
+ $subject = "Payment method saved";
+ $body = "Hello $session_contact_name,
We’re writing to confirm that your payment details have been securely stored with Stripe, our trusted payment processor.
By agreeing to save your payment information, you have authorized us to automatically bill your card ($card_info) for any future invoices. The payment details you’ve provided are securely stored with Stripe and will be used solely for invoices. We do not have access to your full card details.
You may update or remove your payment information at any time using the portal.
Thank you for your business!
-- $company_name - Billing Department $config_invoice_from_email $company_phone";
+
+ $data = [
+ [
+ 'from' => $config_invoice_from_email,
+ 'from_name' => $config_invoice_from_name,
+ 'recipient' => $session_contact_email,
+ 'recipient_name' => $session_contact_name,
+ 'subject' => $subject,
+ 'body' => $body,
+ ]
+ ];
+
+ $mail = addToMailQueue($mysqli, $data);
+
+ }
+
+ // Logging
+ logAction("Stripe", "Update", "$session_contact_name added saved card ($card_info) for future automatic payments (PM: $payment_method)", $session_client_id, $session_client_id);
+
+ // Redirect
+ $_SESSION['alert_message'] = "Card saved - thank you";
+ header('Location: autopay.php');
+
+}
+
+if (isset($_GET['stripe_remove_card'])) {
+
+ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
+ header("Location: portal_post.php?logout");
+ exit();
+ }
+
+ // Get Stripe vars
+ $stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret FROM settings WHERE company_id = 1"));
+ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']);
+ $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']);
+
+ if (!$config_stripe_enable) {
+ header("Location: autopay.php");
+ exit();
+ }
+
+ $payment_method = sanitizeInput($_GET['pm']);
+
+ try {
+ // Initialize stripe
+ require_once '../vendor/stripe-php-10.5.0/init.php';
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ // Detach PM
+ $stripe->paymentMethods->detach($payment_method, []);
+
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception when removing payment method info for $payment_method: $error");
+ logApp("Stripe", "error", "Exception removing payment method for $payment_method: $error");
+ }
+
+ // Remove payment method from ITFlow
+ mysqli_query($mysqli, "UPDATE client_stripe SET stripe_pm = NULL WHERE client_id = $session_client_id LIMIT 1");
+
+ // Logging & Redirect
+ logAction("Stripe", "Update", "$session_contact_name deleted saved card (PM: $payment_method)", $session_client_id, $session_client_id);
+
+ $_SESSION['alert_message'] = "Card removed";
+ header('Location: autopay.php');
+}
\ No newline at end of file
diff --git a/post/user/invoice.php b/post/user/invoice.php
index 847a096b..343e5907 100644
--- a/post/user/invoice.php
+++ b/post/user/invoice.php
@@ -815,14 +815,17 @@ if (isset($_POST['add_payment'])) {
$email_data[] = $email;
+ // Add email to queue
+ if (!empty($email)) {
+ addToMailQueue($mysqli, $email_data);
+ }
+
// Get Email ID for reference
$email_id = mysqli_insert_id($mysqli);
// Email Logging
-
- $_SESSION['alert_message'] = "Email queued successfully! Check Admin > Mail queue";
-
- mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Email Receipt Queued', history_invoice_id = $invoice_id");
+ mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Payment Receipt sent to mail queue ID: $email_id!', history_invoice_id = $invoice_id");
+ logAction("Invoice", "Payment", "Payment receipt for invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id", $client_id, $invoice_id);
}
@@ -847,26 +850,22 @@ if (isset($_POST['add_payment'])) {
$email_data[] = $email;
+ // Add email to queue
+ if (!empty($email)) {
+ addToMailQueue($mysqli, $email_data);
+ }
+
// Get Email ID for reference
$email_id = mysqli_insert_id($mysqli);
// Email Logging
-
- $_SESSION['alert_message'] = "Test email queued successfully! Check Admin > Mail queue";
-
mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Payment Receipt sent to mail queue ID: $email_id!', history_invoice_id = $invoice_id");
-
logAction("Invoice", "Payment", "Payment receipt for invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id", $client_id, $invoice_id);
}
}
- // Add emails to queue
- if (!empty($email)) {
- addToMailQueue($mysqli, $email_data);
- }
-
//Update Invoice Status
mysqli_query($mysqli,"UPDATE invoices SET invoice_status = '$invoice_status' WHERE invoice_id = $invoice_id");
@@ -884,6 +883,193 @@ if (isset($_POST['add_payment'])) {
}
}
+if (isset($_GET['add_payment_stripe'])) {
+
+ enforceUserPermission('module_sales', 2);
+ validateCSRFToken($_GET['csrf_token']);
+
+ $invoice_id = intval($_GET['invoice_id']);
+
+ // Get invoice details
+ $sql = mysqli_query($mysqli,"SELECT * FROM invoices
+ LEFT JOIN clients ON invoice_client_id = client_id
+ LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1
+ WHERE invoice_id = $invoice_id"
+ );
+ $row = mysqli_fetch_array($sql);
+ $invoice_number = intval($row['invoice_number']);
+ $invoice_status = sanitizeInput($row['invoice_status']);
+ $invoice_amount = floatval($row['invoice_amount']);
+ $invoice_prefix = sanitizeInput($row['invoice_prefix']);
+ $invoice_number = intval($row['invoice_number']);
+ $invoice_url_key = sanitizeInput($row['invoice_url_key']);
+ $invoice_currency_code = sanitizeInput($row['invoice_currency_code']);
+ $client_id = intval($row['client_id']);
+ $client_name = sanitizeInput($row['client_name']);
+ $contact_name = sanitizeInput($row['contact_name']);
+ $contact_email = sanitizeInput($row['contact_email']);
+ $contact_phone = sanitizeInput(formatPhoneNumber($row['contact_phone']));
+ $contact_extension = preg_replace("/[^0-9]/", '',$row['contact_extension']);
+ $contact_mobile = sanitizeInput(formatPhoneNumber($row['contact_mobile']));
+
+ // Get ITFlow company details
+ $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
+ $row = mysqli_fetch_array($sql);
+ $company_name = sanitizeInput($row['company_name']);
+ $company_country = sanitizeInput($row['company_country']);
+ $company_address = sanitizeInput($row['company_address']);
+ $company_city = sanitizeInput($row['company_city']);
+ $company_state = sanitizeInput($row['company_state']);
+ $company_zip = sanitizeInput($row['company_zip']);
+ $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone']));
+ $company_email = sanitizeInput($row['company_email']);
+ $company_website = sanitizeInput($row['company_website']);
+
+ // Sanitize Config vars from get_settings.php
+ $config_invoice_from_name = sanitizeInput($config_invoice_from_name);
+ $config_invoice_from_email = sanitizeInput($config_invoice_from_email);
+
+ // Get Client Stripe details
+ $stripe_client_details = mysqli_fetch_array(mysqli_query($mysqli, "SELECT * FROM client_stripe WHERE client_id = $client_id LIMIT 1"));
+ $stripe_id = sanitizeInput($stripe_client_details['stripe_id']);
+ $stripe_pm = sanitizeInput($stripe_client_details['stripe_pm']);
+
+ // Sanity checks
+ if (!$config_stripe_enable || !$stripe_id || !$stripe_pm) {
+ $_SESSION['alert_type'] = "error";
+ $_SESSION['alert_message'] = "Stripe not enabled or no client card saved";
+ header("Location: " . $_SERVER["HTTP_REFERER"]);
+ exit();
+ } elseif ($invoice_status !== 'Sent' && $invoice_status !== 'Viewed') {
+ $_SESSION['alert_type'] = "error";
+ $_SESSION['alert_message'] = "Invalid invoice state (draft/partial/paid/not billable)";
+ header("Location: " . $_SERVER["HTTP_REFERER"]);
+ exit();
+ } elseif ($invoice_amount == 0) {
+ $_SESSION['alert_type'] = "error";
+ $_SESSION['alert_message'] = "Invalid invoice amount";
+ header("Location: " . $_SERVER["HTTP_REFERER"]);
+ exit();
+ }
+
+ // Initialize Stripe
+ require_once __DIR__ . '/../../vendor/stripe-php-10.5.0/init.php';
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ $balance_to_pay = round($invoice_amount, 2);
+ $pi_description = "ITFlow: $client_name payment of $invoice_currency_code $balance_to_pay for $invoice_prefix$invoice_number";
+
+ // Create a payment intent
+ try {
+ $payment_intent = $stripe->paymentIntents->create([
+ 'amount' => intval($balance_to_pay * 100), // Times by 100 as Stripe expects values in cents
+ 'currency' => $invoice_currency_code,
+ 'customer' => $stripe_id,
+ 'payment_method' => $stripe_pm,
+ 'off_session' => true,
+ 'confirm' => true,
+ 'description' => $pi_description,
+ 'metadata' => [
+ 'itflow_client_id' => $client_id,
+ 'itflow_client_name' => $client_name,
+ 'itflow_invoice_number' => $invoice_prefix . $invoice_number,
+ 'itflow_invoice_id' => $invoice_id,
+ ]
+ ]);
+
+ // Get details from PI
+ $pi_id = sanitizeInput($payment_intent->id);
+ $pi_date = date('Y-m-d', $payment_intent->created);
+ $pi_amount_paid = floatval(($payment_intent->amount_received / 100));
+ $pi_currency = strtoupper(sanitizeInput($payment_intent->currency));
+ $pi_livemode = $payment_intent->livemode;
+
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception during payment intent for invoice ID $invoice_id / $invoice_prefix$invoice_number: $error");
+ logApp("Stripe", "error", "Exception during PI for invoice ID $invoice_id: $error");
+ }
+
+ if ($payment_intent->status == "succeeded" && intval($balance_to_pay) == intval($pi_amount_paid)) {
+
+ // Update Invoice Status
+ mysqli_query($mysqli, "UPDATE invoices SET invoice_status = 'Paid' WHERE invoice_id = $invoice_id");
+
+ // Add Payment to History
+ mysqli_query($mysqli, "INSERT INTO payments SET payment_date = '$pi_date', payment_amount = $pi_amount_paid, payment_currency_code = '$pi_currency', payment_account_id = $config_stripe_account, payment_method = 'Stripe', payment_reference = 'Stripe - $pi_id', payment_invoice_id = $invoice_id");
+ mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Paid', history_description = 'Online Payment added (agent)', history_invoice_id = $invoice_id");
+
+ // Email receipt
+ if (!empty($config_smtp_host)) {
+ $subject = "Payment Received - Invoice $invoice_prefix$invoice_number";
+ $body = "Hello $contact_name,
We have received online payment for the amount of " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
This is a notification that an invoice has been paid in ITFlow. Below is a copy of the receipt sent to the client:-
--------
Hello $contact_name,
We have received online payment for the amount of " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_email or $company_phone.
- Kindly review the invoice details mentioned below.
Invoice: $invoice_prefix$invoice_number Issue Date: $invoice_date Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . " Due Date: $invoice_due Over Due By: $day Days
-- $company_name - Billing $config_invoice_from_email $company_phone";
$mail = addToMailQueue($mysqli, [
[
@@ -674,19 +684,150 @@ while ($row = mysqli_fetch_array($sql_recurring)) {
// Create Payment from Auto Payment
if ($recurring_payment_recurring_invoice_id) {
- mysqli_query($mysqli,"INSERT INTO payments SET payment_date = CURDATE(), payment_amount = $recurring_amount, payment_currency_code = '$recurring_payment_currency_code', payment_account_id = $recurring_payment_account_id, payment_method = '$recurring_payment_method', payment_reference = 'Paid via AutoPay', payment_invoice_id = $new_invoice_id");
- // Get Payment ID for reference
- $payment_id = mysqli_insert_id($mysqli);
+ if ($recurring_payment_method == "Stripe") {
+ // Stripe payment
- // Update Invoice Status
- mysqli_query($mysqli,"UPDATE invoices SET invoice_status = 'Paid' WHERE invoice_id = $new_invoice_id");
+ // Get Stripe info for client
+ $stripe_client_details = mysqli_fetch_array(mysqli_query($mysqli, "SELECT * FROM client_stripe WHERE client_id = $client_id LIMIT 1"));
+ $stripe_id = sanitizeInput($stripe_client_details['stripe_id']);
+ $stripe_pm = sanitizeInput($stripe_client_details['stripe_pm']);
- //Add Payment to History
- mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Paid', history_description = 'Payment added via Auto Pay', history_invoice_id = $new_invoice_id");
+ if ($config_stripe_enable && $stripe_id && $stripe_pm) {
- // Logging
- logAction("Invoice", "Payment", "Auto Payment amount of " . numfmt_format_currency($currency_format, $recurring_amount, $recurring_payment_currency_code) . " added to invoice $invoice_prefix$invoice_number", $client_id, $new_invoice_id);
+ // Initialize
+ require_once __DIR__ . '/../vendor/stripe-php-10.5.0/init.php';
+ $stripe = new \Stripe\StripeClient($config_stripe_secret);
+
+ $balance_to_pay = round($invoice_amount, 2);
+ $pi_description = "ITFlow: $client_name payment of $recurring_payment_currency_code $balance_to_pay for $invoice_prefix$invoice_number";
+
+ // Create a payment intent
+ try {
+ $payment_intent = $stripe->paymentIntents->create([
+ 'amount' => intval($balance_to_pay * 100), // Times by 100 as Stripe expects values in cents
+ 'currency' => $recurring_payment_currency_code,
+ 'customer' => $stripe_id,
+ 'payment_method' => $stripe_pm,
+ 'off_session' => true,
+ 'confirm' => true,
+ 'description' => $pi_description,
+ 'metadata' => [
+ 'itflow_client_id' => $client_id,
+ 'itflow_client_name' => $client_name,
+ 'itflow_invoice_number' => $invoice_prefix . $invoice_number,
+ 'itflow_invoice_id' => $new_invoice_id,
+ ]
+ ]);
+
+ // Get details from PI
+ $pi_id = sanitizeInput($payment_intent->id);
+ $pi_date = date('Y-m-d', $payment_intent->created);
+ $pi_amount_paid = floatval(($payment_intent->amount_received / 100));
+ $pi_currency = strtoupper(sanitizeInput($payment_intent->currency));
+ $pi_livemode = $payment_intent->livemode;
+
+ } catch (Exception $e) {
+ $error = $e->getMessage();
+ error_log("Stripe payment error - encountered exception during payment intent for invoice ID $new_invoice_id / $invoice_prefix$invoice_number: $error");
+ logApp("Stripe", "error", "Exception during PI for invoice ID $new_invoice_id: $error");
+ echo $error;
+ }
+
+ if ($payment_intent->status == "succeeded" && intval($balance_to_pay) == intval($pi_amount_paid)) {
+
+ // Update Invoice Status
+ mysqli_query($mysqli, "UPDATE invoices SET invoice_status = 'Paid' WHERE invoice_id = $new_invoice_id");
+
+ // Add Payment to History
+ mysqli_query($mysqli, "INSERT INTO payments SET payment_date = '$pi_date', payment_amount = $pi_amount_paid, payment_currency_code = '$pi_currency', payment_account_id = $recurring_payment_account_id, payment_method = 'Stripe', payment_reference = 'Stripe - $pi_id', payment_invoice_id = $new_invoice_id");
+ mysqli_query($mysqli, "INSERT INTO history SET history_status = 'Paid', history_description = 'Online Payment added (autopay)', history_invoice_id = $new_invoice_id");
+
+ // Email receipt
+ if (!empty($config_smtp_host)) {
+ $subject = "Payment Received - Invoice $invoice_prefix$invoice_number";
+ $body = "Hello $contact_name,
We have received online payment for the amount of " . numfmt_format_currency($currency_format, $invoice_amount, $recurring_payment_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.
This is a notification that an invoice has been paid in ITFlow. Below is a copy of the receipt sent to the client:-
--------
Hello $contact_name,
We have received online payment for the amount of " . numfmt_format_currency($currency_format, $invoice_amount, $recurring_payment_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.