Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW: Save invoice payment with a AJAX request so the user don't send many request at the same time #537

Open
wants to merge 3 commits into
base: 2024_rc
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 277 additions & 0 deletions htdocs/compta/ajax/addpayment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
<?php
/* Copyright (C) 2022-2023 Easya Solutions <[email protected]>
* Copyright (C) 2023 Sylvain Legrand <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/**
* \file htdocs/compta/ajax/addpayment.php
* \brief File to return Ajax response on payment process
*/

//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1');
//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1');
if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1');
if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no menu to show
if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php

require '../../main.inc.php';
require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';

$langs->loadLangs(array('banks', 'bills', 'companies', 'multicurrency'));
$error = 0;
$invoice_id = 0;
$errors_msg = array();

/*
* View
*/
top_httphead('application/json');

$facid = GETPOST('facid', 'int');
$accountid = GETPOST('accountid', 'int');
$paymentnum = GETPOST('num_paiement', 'alpha');
$socid = GETPOST('socid', 'int');

$amounts = array();
$amountsresttopay = array();

$multicurrency_amounts = array();
$multicurrency_amountsresttopay = array();

// Security check
if ($user->societe_id > 0) {
$socid = $user->societe_id;
}

$object = new Facture($db);

// Load object
if ($facid > 0) {
$ret = $object->fetch($facid);
}

$usercanissuepayment = !empty($user->rights->facture->paiement);

$fieldid = 'rowid';
$isdraft = (($object->status == Facture::STATUS_DRAFT) ? 1 : 0);
$result = restrictedArea($user, 'facture', $object->id, '', '', 'fk_soc', $fieldid, $isdraft, 1);
if ($result <= 0 || !$usercanissuepayment) {
$langs->load("errors");
$errors_msg[] = $langs->trans('ErrorForbidden');
$error++;
}

if (!$error) {
$datepaye = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
$payment_id = 0;
$totalpayment = 0;
$multicurrency_totalpayment = 0;
$atleastonepaymentnotnull = 0;
$formquestion = array();
$i = 0;

// Generate payment array and check if there is payment higher than invoice and payment date before invoice date
$tmpinvoice = new Facture($db);
foreach ($_POST as $key => $value) {
if (substr($key, 0, 7) == 'amount_' && GETPOST($key) != '') {
$cursorfacid = substr($key, 7);
$amounts[$cursorfacid] = price2num(GETPOST($key));
$totalpayment = $totalpayment + $amounts[$cursorfacid];
if (!empty($amounts[$cursorfacid])) {
$atleastonepaymentnotnull++;
}
$result = $tmpinvoice->fetch($cursorfacid);
if ($result <= 0) {
$errors_msg[] = $db->lasterror();
$error++;
break;
} else {
$amountsresttopay[$cursorfacid] = price2num($tmpinvoice->total_ttc - $tmpinvoice->getSommePaiement());
if ($amounts[$cursorfacid]) {
// Check date
if ($datepaye && ($datepaye < $tmpinvoice->date)) {
$langs->load("errors");
//$error++;
setEventMessages($langs->transnoentities("WarningPaymentDateLowerThanInvoiceDate", dol_print_date($datepaye, 'day'), dol_print_date($tmpinvoice->date, 'day'), $tmpinvoice->ref), null, 'warnings');
}
}
}
} elseif (substr($key, 0, 21) == 'multicurrency_amount_') {
$cursorfacid = substr($key, 21);
$multicurrency_amounts[$cursorfacid] = price2num(GETPOST($key));
$multicurrency_totalpayment += floatval($multicurrency_amounts[$cursorfacid]);
if (!empty($multicurrency_amounts[$cursorfacid])) {
$atleastonepaymentnotnull++;
}
$result = $tmpinvoice->fetch($cursorfacid);
if ($result <= 0) {
$errors_msg[] = $db->lasterror();
$error++;
break;
} else {
$multicurrency_amountsresttopay[$cursorfacid] = price2num($tmpinvoice->multicurrency_total_ttc - $tmpinvoice->getSommePaiement(1));
if ($multicurrency_amounts[$cursorfacid]) {
// Check date
if ($datepaye && ($datepaye < $tmpinvoice->date)) {
$langs->load("errors");
//$error++;
setEventMessages($langs->transnoentities("WarningPaymentDateLowerThanInvoiceDate", dol_print_date($datepaye, 'day'), dol_print_date($tmpinvoice->date, 'day'), $tmpinvoice->ref), null, 'warnings');
}
}
}
}
}
}

// Check parameters
if (!GETPOST('paiementcode')) {
$errors_msg[] = $langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('PaymentMode'));
$error++;
}

if (!empty($conf->banque->enabled)) {
// If bank module is on, account is required to enter a payment
if ($accountid <= 0) {
$errors_msg[] = $langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('AccountToCredit'));
$error++;
}
}

if (empty($totalpayment) && empty($multicurrency_totalpayment) && empty($atleastonepaymentnotnull)) {
$errors_msg[] = $langs->transnoentities('ErrorFieldRequired', $langs->trans('PaymentAmount'));
$error++;
}

if (empty($datepaye)) {
$errors_msg[] = $langs->transnoentities('ErrorFieldRequired', $langs->transnoentities('Date'));
$error++;
}

// Check if payments in both currency
if ($totalpayment > 0 && $multicurrency_totalpayment > 0) {
$errors_msg[] = $langs->transnoentities('ErrorPaymentInBothCurrency');
$error++;
}

if (!$error) {
$db->begin();

$thirdparty = new Societe($db);
if ($socid > 0) {
$thirdparty->fetch($socid);
}
$multicurrency_code = array();
$multicurrency_tx = array();

// Clean parameters amount if payment is for a credit note
foreach ($amounts as $key => $value) { // How payment is dispatched
$tmpinvoice = new Facture($db);
$tmpinvoice->fetch($key);
if ($tmpinvoice->type == Facture::TYPE_CREDIT_NOTE) {
$newvalue = price2num($value, 'MT');
$amounts[$key] = -abs($newvalue);
}
$multicurrency_code[$key] = $tmpinvoice->multicurrency_code;
$multicurrency_tx[$key] = $tmpinvoice->multicurrency_tx;
}

foreach ($multicurrency_amounts as $key => $value) { // How payment is dispatched
$tmpinvoice = new Facture($db);
$tmpinvoice->fetch($key);
$paiement = new Paiement($db);
$paiement->multicurrency_code = $tmpinvoice->multicurrency_code;
$paiement->multicurrency_tx = $tmpinvoice->multicurrency_tx; // TODO the exchange rate may differ from the invoice rate => enter or confirm on the payment entry page
if ($tmpinvoice->type == Facture::TYPE_CREDIT_NOTE) {
$newvalue = price2num($value, 'MT');
$multicurrency_amounts[$key] = -abs($newvalue);
}
$multicurrency_code[$key] = $tmpinvoice->multicurrency_code;
$multicurrency_tx[$key] = $tmpinvoice->multicurrency_tx;
}

// Creation of payment line
$paiement = new Paiement($db);
$paiement->datepaye = $datepaye;
$paiement->amounts = $amounts; // Array with all payments dispatching with invoice id
$paiement->multicurrency_amounts = $multicurrency_amounts; // Array with all payments dispatching
$paiement->multicurrency_code = $multicurrency_code; // Array with all currency of payments dispatching
$paiement->multicurrency_tx = $multicurrency_tx; // Array with all currency tx of payments dispatching
$paiement->paiementid = dol_getIdFromCode($db, GETPOST('paiementcode'), 'c_paiement', 'code', 'id', 1);
$paiement->num_payment = $paymentnum;
$paiement->note_private = GETPOST('comment', 'alpha');
$paiement->fk_account = GETPOST('accountid', 'int');

if (!$error) {
// Create payment and update this->multicurrency_amounts if this->amounts filled or
// this->amounts if this->multicurrency_amounts filled.
// This also set ->amount and ->multicurrency_amount
$payment_id = $paiement->create($user, (GETPOST('closepaidinvoices') == 'on' ? 1 : 0), $thirdparty); // This include closing invoices and regenerating documents
if ($payment_id < 0) {
$errors_msg[] = $paiement->errorsToString();
$error++;
}
}

if (!$error) {
$label = '(CustomerInvoicePayment)';
if (GETPOST('type') == Facture::TYPE_CREDIT_NOTE) {
$label = '(CustomerInvoicePaymentBack)'; // Refund of a credit note
}
$result = $paiement->addPaymentToBank($user, 'payment', $label, $accountid, GETPOST('chqemetteur'), GETPOST('chqbank'));
if ($result < 0) {
$errors_msg[] = $paiement->errorsToString();
$error++;
}
}

if (!$error) {
$db->commit();

// If payment dispatching on more than one invoice, we stay on summary page, otherwise jump on invoice card
foreach ($paiement->amounts as $key => $amount) {
$facid = $key;
if (is_numeric($amount) && $amount <> 0) {
if ($invoice_id != 0) {
$invoice_id = -1; // There is more than one invoice payed by this payment
} else {
$invoice_id = $facid;
}
}
}
} else {
$db->rollback();
}
}

if ($error) {
$toJsonArray = array(
'error' => implode('<br>', $errors_msg),
);
} elseif ($invoice_id > 0) {
$toJsonArray = array(
'invoice_id' => $invoice_id,
);
} else {
$toJsonArray = array(
'payment_id' => $payment_id,
);
}

// Encode to JSON to return
echo json_encode($toJsonArray); // Printing the call's result
56 changes: 51 additions & 5 deletions htdocs/compta/paiement.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
* Copyright (C) 2014 Teddy Andreotti <[email protected]>
* Copyright (C) 2015 Juanjo Menent <[email protected]>
* Copyright (C) 2018-2021 Frédéric France <[email protected]>
* Copyright (C) 2023 Lenin Rivas <[email protected]>
* Copyright (C) 2023 Lenin Rivas <[email protected]>
* Copyright (C) 2023 Sylvain Legrand <[email protected]>
* Copyright (C) 2022-2023 Easya Solutions <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -81,7 +82,7 @@
$usercanissuepayment = $user->hasRight('facture', 'paiement');

$fieldid = 'rowid';
$isdraft = (($object->statut == Facture::STATUS_DRAFT) ? 1 : 0);
$isdraft = (($object->status == Facture::STATUS_DRAFT) ? 1 : 0);
$result = restrictedArea($user, 'facture', $object->id, '', '', 'fk_soc', $fieldid, $isdraft);


Expand Down Expand Up @@ -459,13 +460,55 @@ function callForResult(imgId)

print ' });'."\n";

//Add js for AutoFill
// Add js for AutoFill
print ' $(document).ready(function () {';
print ' $(".AutoFillAmout").on(\'click touchstart\', function(){
$("input[name="+$(this).data(\'rowname\')+"]").val($(this).data("value")).trigger("change");
});';
print ' });'."\n";

if ($action == 'add_paiement' && !empty($conf->use_javascript_ajax)) {
print ' $(document).ready(function () {
var payment_form = $("#payment_form");
var submit_button = $("#submit_button");
var please_wait = $("#please_wait");

payment_form.submit(function (e) {
e.preventDefault();
submit_button.hide();
please_wait.show();
var redirection = false;
$(\'input[name="token"]\').val("' . currentToken(). '");

$.ajax({
type: "POST",
url: "' . DOL_URL_ROOT . '/compta/ajax/addpayment.php",
data: payment_form.serialize(),
dataType: "json"
}).done(function(data, textStatus, jqXHR) {
if (typeof data.error !== "undefined") {
$.jnotify(data.error, "error", true, { remove: function(){} });
} else if (typeof data.invoice_id !== "undefined") {
window.location = "' . DOL_URL_ROOT . '/compta/facture/card.php?facid=" + data.invoice_id;
redirection = true;
} else if (typeof data.payment_id !== "undefined") {
window.location = "' . DOL_URL_ROOT . '/compta/paiement/card.php?id=" + data.payment_id;
redirection = true;
}
//console.log("done", data);
}).fail(function(jqXHR, textStatus, errorThrown) {
$.jnotify(textStatus + " - " + error, "error", true, { remove: function(){} });
//console.log("fail", jqXHR);
}).always(function(data, textStatus, jqXHR) { // function(data|jqXHR, textStatus, jqXHR|errorThrown)
if (!redirection) {
submit_button.show();
please_wait.hide();
}
});
});
});' . "\n";
}

print ' </script>'."\n";
}

Expand Down Expand Up @@ -848,7 +891,7 @@ function callForResult(imgId)
print '</b></td>';
print '<td class="right"><b>'.price($sign * price2num($total_ttc - $totalrecu - $totalrecucreditnote - $totalrecudeposits, 'MT')).'</b></td>';
print '<td class="right" id="result" style="font-weight: bold;"></td>'; // Autofilled
print '<td align="center">&nbsp;</td>';
print '<td class="center">&nbsp;</td>';
print "</tr>\n";
}
print "</table>";
Expand Down Expand Up @@ -897,7 +940,10 @@ function callForResult(imgId)
$text .= '<br>'.$langs->trans("AllCompletelyPayedInvoiceWillBeClosed");
print '<input type="hidden" name="closepaidinvoices" value="'.GETPOST('closepaidinvoices').'">';
}
$formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$facture->id.'&socid='.$facture->socid.'&type='.$facture->type, $langs->trans('ReceivedCustomersPayments'), $text, 'confirm_paiement', $formquestion, $preselectedchoice);
$formconfirm = '<div id="submit_button">';
$formconfirm .= $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$facture->id.'&socid='.$facture->socid.'&type='.$facture->type, $langs->trans('ReceivedCustomersPayments'), $text, 'confirm_paiement', $formquestion, $preselectedchoice);
$formconfirm .= '</div>';
$formconfirm .= '<div id="please_wait" style="display: none;">'. info_admin('<span class="fa fa-spinner fa-spin"></span> ' . $langs->trans('PleaseBePatient'), 0, 0, 'warning') . '</div>';
}

// Call Hook formConfirm
Expand Down