pay invoices features

This commit is contained in:
Tiavina 2025-01-31 12:51:33 +03:00
parent 5108043679
commit 0f75240b2f
32 changed files with 279 additions and 46 deletions

View File

@ -165,5 +165,7 @@ return [
['name' => 'page#uploadFileToBijoux','url' => '/defunt/uploadFileToBijoux', 'verb' => 'POST'],
//upload pacemaker photo to defunt
['name' => 'page#uploadPacemakerPhotoToDefunts','url' => '/defunt/uploadPacemakerPhotoToDefunts', 'verb' => 'POST'],
//pay invoices
['name' => 'page#payInvoices','url' => '/facture/payInvoices', 'verb' => 'POST'],
]
];

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace OCA\Gestion\Constants;
abstract class FactureStatusConstant
{
const PENDING_KEY = "PENDING";
const PAID_KEY = "PAID";
const CANCELED = "CANCELED";
}

View File

@ -1,6 +1,7 @@
<?php
namespace OCA\Gestion\Controller;
use Exception;
use OCA\Gestion\Service\InvoicePdfHandler;
defined("TAB1") or define("TAB1", "\t");
@ -194,7 +195,13 @@ class PageController extends Controller {
*/
public function facture() {
$this->denyIfNotAdmin();
return new TemplateResponse('gestion', 'facture', array('groups' => $this->groups, 'user' => $this->user, 'path' => $this->idNextcloud, 'url' => $this->getNavigationLink())); // templates/facture.php
$facturePaymentTypeList = $this->myDb->getFacturePaymentList();
return new TemplateResponse('gestion', 'facture', array(
'groups' => $this->groups,
'user' => $this->user,
'path' => $this->idNextcloud,
'paymentTypes' => json_decode($facturePaymentTypeList),
'url' => $this->getNavigationLink())); // templates/facture.php
}
/**
@ -2818,4 +2825,19 @@ class PageController extends Controller {
return null;
}
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*
*/
public function payInvoices($factureIds,$facturePaymentTypeId,$paymentDate){
try{
$result = $this->myDb->payInvoices($factureIds,$facturePaymentTypeId,$paymentDate);
return $result;
}
catch(Exception) {
return false;
}
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace OCA\Gestion\Db;
use OCA\Gestion\Constants\FactureStatusConstant;
use OCA\Gestion\Helpers\DateHelpers;
use OCP\IDBConnection;
use OCP\IL10N;
@ -356,6 +357,9 @@ class Bdd {
public function getFactures($idNextcloud){
$sql = "SELECT ".$this->tableprefix."facture.id, ".$this->tableprefix."facture.user_id, ".$this->tableprefix."facture.num, ".$this->tableprefix."facture.date, "
.$this->tableprefix."facture.fk_facture_status_key, ".$this->tableprefix."facture.fk_facture_payment_type_id, ".$this->tableprefix."facture.payment_date, "
.$this->tableprefix."facture_payment_type.facture_payment_type_label, "
.$this->tableprefix."facture_status.facture_status_label, "
.$this->tableprefix."devis.num as dnum, ".$this->tableprefix."devis.comment as dcomment, date_paiement, type_paiement, id_devis, entreprise, "
.$this->tableprefix."facture.version, status_paiement,"
.$this->tableprefix."client.nom, ".$this->tableprefix."client.prenom, "
@ -369,6 +373,8 @@ class Bdd {
LEFT JOIN ".$this->tableprefix."lieu on ".$this->tableprefix."devis.id_lieu = ".$this->tableprefix."lieu.id
LEFT JOIN ".$this->tableprefix."client on ".$this->tableprefix."devis.id_client = ".$this->tableprefix."client.id
LEFT JOIN ".$this->tableprefix."defunt on id_defunt = ".$this->tableprefix."defunt.id
LEFT JOIN ".$this->tableprefix."facture_payment_type on fk_facture_payment_type_id = ".$this->tableprefix."facture_payment_type.id
LEFT JOIN ".$this->tableprefix."facture_status on fk_facture_status_key = ".$this->tableprefix."facture_status.facture_status_key
ORDER BY ".$this->tableprefix."facture.id DESC, ".$this->tableprefix."facture.date_paiement DESC";
$result = $this->execSQL($sql, array());
return $result;
@ -1286,7 +1292,7 @@ class Bdd {
return $result;
}
public function insertFactureForeEachDevisId($idNextCloud,$devisIdArray,$paymentDate = null){
public function insertFactureForeEachDevisId($idNextCloud,$devisIdArray,$facturationDate = null){
$mentionsFilter = [
DevisMentionConstant::NEW,
DevisMentionConstant::MENTION
@ -1294,7 +1300,7 @@ class Bdd {
$devisIdListFiltered = $this->getDevisIdListFilteredByMentionAndDevisListId($mentionsFilter,$devisIdArray);
$factureIdsGenerated = [];
foreach($devisIdListFiltered as $devis){
$factureId = $this->insertFactureByDevisId($idNextCloud,$devis['id'],$devis['devis_date'],$paymentDate);
$factureId = $this->insertFactureByDevisId($idNextCloud,$devis['id'],$devis['devis_date'],$facturationDate);
$factureIdsGenerated[] = $factureId;
}
return $factureIdsGenerated;
@ -1303,15 +1309,15 @@ class Bdd {
/**
* Insert invoice with a devis
*/
public function insertFactureByDevisId($idNextcloud,$devisId,$devisDate = null,$paymentDate = null){
if($paymentDate == null || $paymentDate == ""){
public function insertFactureByDevisId($idNextcloud,$devisId,$devisDate = null,$facturationDate = null){
if($facturationDate == null || $facturationDate == ""){
$datetimeNow = new Datetime();
$paymentDate = DateHelpers::GetLastDayOfTheMonthOfADate($datetimeNow);
$paymentDate = $paymentDate->format('Y-m-d');
$facturationDate = DateHelpers::GetLastDayOfTheMonthOfADate($datetimeNow);
$facturationDate = $facturationDate->format('Y-m-d');
}
else{
$paymentDate = Datetime::createFromFormat('Y-m-d',$paymentDate);
$paymentDate = $paymentDate->format('Y-m-d');
$facturationDate = Datetime::createFromFormat('Y-m-d',$facturationDate);
$facturationDate = $facturationDate->format('Y-m-d');
}
$devisDatetime = new Datetime();
if($devisDate != null){
@ -1327,7 +1333,7 @@ class Bdd {
$factureDate ,
$idNextcloud,
$fullFactureNumber,
$paymentDate,
$facturationDate,
"Comptant",
$devisId,
$last+1,
@ -3714,4 +3720,49 @@ class Bdd {
return true;
}
private function getFacturePaymentTypeById($facturePaymentTypeId){
$sql = "SELECT * FROM ".$this->tableprefix."facture_payment_type as facture_payment_type
WHERE facture_payment_type.id = ? LIMIT 1
";
$facturePaymentType = $this->execSQLNoJsonReturn($sql,[$facturePaymentTypeId]);
if(!empty($facturePaymentType)){
return $facturePaymentType[0];
}
return null;
}
public function getFacturePaymentList(){
$sql = "SELECT * FROM ".$this->tableprefix."facture_payment_type";
return $this->execSQL($sql,[]);
}
public function payInvoices($factureIds,$facturePaymentTypeId,$paymentDate){
$facturePaymentType = $this->getFacturePaymentTypeById($facturePaymentTypeId);
if($facturePaymentType == null){
return null;
}
$paymentDate = Datetime::createFromFormat('Y-m-d',$paymentDate);
$paymentDate = $paymentDate->format('Y-m-d');
foreach($factureIds as $factureId){
$this->payAnInvoice($factureId,$facturePaymentTypeId,$paymentDate);
}
return true;
}
private function payAnInvoice($factureId,$facturePaymentTypeId,$paymentDate){
$sql = "UPDATE ".$this->tableprefix."facture as facture
SET facture.fk_facture_status_key = ?,
facture.payment_date = ?,
facture.fk_facture_payment_type_id = ?
WHERE facture.id = ?
";
$this->execSQLNoData($sql,[
FactureStatusConstant::PAID_KEY,
$paymentDate,
$facturePaymentTypeId,
$factureId
]);
return true;
}
}

View File

@ -0,0 +1,26 @@
create table if not exists oc_gestion_facture_status (
facture_status_key VARCHAR(255) PRIMARY KEY NOT NULL,
facture_status_label VARCHAR(255) DEFAULT ''
);
INSERT INTO oc_gestion_facture_status (facture_status_key, facture_status_label)
VALUES
('PENDING', 'En attente'),
('PAID', 'Payée'),
('CANCELED', 'Annulée');
create table if not exists oc_gestion_facture_payment_type (
id INT PRIMARY KEY AUTO_INCREMENT,
facture_payment_type_label VARCHAR(255) DEFAULT ''
);
INSERT INTO oc_gestion_facture_payment_type (facture_payment_type_label)
VALUES
('Comptant'),
('Chèque'),
('Virement');
alter table oc_gestion_facture
add column fk_facture_status_key VARCHAR(255) DEFAULT 'PENDING',
add column fk_facture_payment_type_id INT DEFAULT NULL,
add column payment_date DATE DEFAULT NULL;

View File

@ -2,4 +2,8 @@ export const FacturedDevisMentionConstant = "factur&eacute;";
export const FacturedDevisMentionConstantFormatted = "facturé";
export const DefaultDevisMentionConstant = "Mention";
export const NewDevisMentionConstant = "Nouveau";
export const CanceledDevisMentionConstant = "CANCELED";
export const CanceledDevisMentionConstant = "CANCELED";
export const FactureStatusPaid = "PAID";
export const FactureStatusPending = "PENDING";
export const FactureStatusCanceled = "CANCELED";

View File

@ -1,7 +1,7 @@
import "@nextcloud/dialogs/dist/index.css";
import "datatables.net-dt/css/jquery.dataTables.css";
import "../css/mycss.css";
import "./listener/invoiceListener";
import DataTable from "datatables.net";
import { globalConfiguration, optionDatatable } from "./modules/mainFunction.mjs";

View File

@ -1,5 +1,78 @@
import {showError, showSuccess } from "@nextcloud/dialogs";
import {baseUrl} from "../modules/mainFunction.mjs";
import { Facture } from "../objects/facture.mjs";
import DataTable from "datatables.net";
window.addEventListener("DOMContentLoaded", function () {
const today = new Date();
const formattedDate = today.toISOString().split('T')[0];
const dateInput = document.getElementById('facturePaymentDate');
dateInput.value = formattedDate;
});
$('body').on('click', '#showFacturePaymentModal', function () {
var oTable = $('.tabledt').dataTable();
var rowcollection = oTable.$(".factureToPay:checked", {"page": "all"});
let factureToPay = [];
rowcollection.each(function(index,elem){
var checkbox_value = $(elem).val();
factureToPay.push(checkbox_value);
});
if(factureToPay.length == 0){
showError(t('gestion', "Veuillez choisir une ligne de facture à payer"));
return;
}
$('#facturePaymentModal').show();
});
$('body').on('click', '#closeFacturePaymentModal', function () {
$('#facturePaymentModal').hide();
});
$('body').on('click', '#payInvoice', function () {
var paymentDate = document.getElementById("facturePaymentDate").value;
var oTable = $('.tabledt').dataTable();
var rowcollection = oTable.$(".factureToPay:checked", {"page": "all"});
let factureToPay = [];
rowcollection.each(function(index,elem){
var checkbox_value = $(elem).val();
factureToPay.push(checkbox_value);
});
if(factureToPay.length == 0){
$('#facturePaymentModal').hide();
showError(t('gestion', "Veuillez choisir une ligne de facture à payer"));
return;
}
var paymentTypeId = document.getElementById("selectPaymentType").value;
let payFacturesPaylaod = {
factureIds: factureToPay,
facturePaymentTypeId: paymentTypeId,
paymentDate: paymentDate
}
$.ajax({
url: baseUrl + '/facture/payInvoices',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(payFacturesPaylaod)
}).done(function (response) {
$('#facturePaymentModal').hide();
if(response){
let datatable = new DataTable('.tabledt');
Facture.loadFactureDT(datatable);
showSuccess(t('gestion', "Factures payés avec succès"));
return;
}
showError(t('gestion', "Erreur dans le paiement des factures"));
}).fail(function (response, code) {
$('#facturePaymentModal').hide();
showError(t('gestion', "Erreur dans le paiement des factures"));
});
});
$('body').on('click', '#exportMultipleFactureToPdf', function () {
// Access specific parameter values
@ -33,8 +106,15 @@ $('body').on('click', '#exportMultipleFactureToPdf', function () {
});
document.getElementById('clientselector').addEventListener('change', function() {
let selectedOption = this.options[this.selectedIndex];
let filterType = selectedOption.getAttribute('data-type');
document.getElementById('filterType').value = filterType;
});
let clientSelector = document.getElementById('clientselector');
if (clientSelector) {
clientSelector.addEventListener('change', function() {
let selectedOption = this.options[this.selectedIndex];
let filterType = selectedOption.getAttribute('data-type');
let filterTypeInput = document.getElementById('filterType');
if (filterTypeInput) {
filterTypeInput.value = filterType;
}
});
}

View File

@ -16,16 +16,22 @@ export class Facture {
this.num = ((myresp.num == null || myresp.num.length === 0) ? '-' : myresp.num);
this.version = ((myresp.version == null || myresp.version.length === 0) ? '-' : myresp.version);
this.date_paiement = ((myresp.date_paiement == null || myresp.date_paiement.length === 0) ? '-' : myresp.date_paiement);
this.type_paiement = ((myresp.type_paiement == null || myresp.type_paiement.length === 0) ? '-' : myresp.type_paiement);
this.type_paiement = ((myresp.facture_payment_type_label != null && myresp.facture_payment_type_label.length > 0)) ? myresp.facture_payment_type_label : '-';
this.dnum = ((myresp.dnum == null || myresp.dnum.length === 0) ? '-' : myresp.dnum);
this.nom_defunt = ((myresp.nom_defunt == null || myresp.nom_defunt.length == 0) ? '-' : myresp.nom_defunt);
this.nom = ((myresp.nom == null || myresp.nom.length === 0) ? '-' : myresp.nom);
this.lieu = ((myresp.lieu == null || myresp.lieu.length === 0) ? '-' : myresp.lieu);
this.prenom = ((myresp.prenom == null || myresp.prenom.length === 0) ? '-' : myresp.prenom);
this.status_paiement = ((myresp.status_paiement == null || myresp.status_paiement.length === 0) ? '-' : myresp.status_paiement);
this.status_paiement = ((myresp.facture_status_label == null || myresp.facture_status_label.length === 0) ? '-' : myresp.facture_status_label);
this.id_devis = ((myresp.id_devis == null || myresp.id_devis.length === 0) ? '-' : myresp.id_devis);
this.baseUrl = generateUrl(`/apps/gestion/facture/${this.id}/show`);
this.factureProduits = Devis.getDevisProduitsString(myresp);
let paymentDate = "-";
if(myresp.payment_date != null && myresp.payment_date.length > 0){
paymentDate = new Date(myresp.payment_date);
paymentDate = paymentDate.toLocaleDateString("fr-FR");
}
this.payment_date = paymentDate;
}
/**
@ -33,15 +39,17 @@ export class Facture {
*/
getDTRow() {
let myrow = [
'<input class="factureToPay" data-id= '+ this.id + ' type="checkbox" name="factureToPay" value="' + this.id + '"/>',
'<div>' + this.user_id + '</div>',
'<div class="factureNum" data-table="facture" data-column="num" data-id="' + this.id + '">' + this.num + '</div>',
'<input style="margin:0;padding:0;" class="inputDate devisOrFactureInputDate" type="date" value=' + this.date + ' data-table="facture" data-column="date" data-id="' + this.id + '"/>',
'<input style="margin:0;padding:0;" class="inputDate devisOrFactureInputDate" type="date" value=' + this.date_paiement + ' data-table="facture" data-column="date_paiement" data-id="' + this.id + '"/>',
'<div class="editable" data-table="facture" data-column="type_paiement" data-id="' + this.id + '">' + this.type_paiement + '</div>',
'<div>' + this.type_paiement + '</div>',
'<div class="selectAvailableDevis" data-table="facture" data-column="id_devis" data-id="' + this.id + '" data-current="' + this.id_devis + '">' + this.nom_defunt + ' | <span style="font-size: 0.7rem">' + this.prenom + ' ' + this.nom + '</span></div>',
'<div class="" data-table="facture" data-column="" data-id="' + this.id + '" style="display:inline">' + this.lieu + '</div>',
'<div>' + this.factureProduits + '</div>',
'<div class="editable" data-table="facture" data-column="status_paiement" data-id="' + this.id + '" style="display:inline">' + this.status_paiement + '</div>',
'<div>' + this.status_paiement + '</div>',
'<div>' + this.payment_date + '</div>',
'<div style="display:inline-block;margin-right:0px;width:80%;"><a href="' + this.baseUrl +'"><button>' + t('gestion', 'Open') + '</button></a></div><div data-modifier="facture" data-id=' + this.id + ' data-table="facture" style="display:inline-block;margin-right:0px;" class="deleteItem icon-delete"></div>',
];
return myrow;

View File

@ -17,14 +17,16 @@
</div>-->
</div>
<div class="d-flex justify-content-end">
<div>
<button class="btn btn-secondary" id="apercusFactures">Voir les aperçus</button>
</div>
<button id="showFacturePaymentModal" class="btn btn-secondary" data-toggle="modal" data-target="#facturePaymentModal">
Payer
</button>
<button class="btn btn-secondary" id="apercusFactures">Voir les aperçus</button>
</div>
<hr>
<table id="facture" class="display tabledt">
<thead>
<tr>
<th></th>
<th><?php p($l->t('ID'));?></th>
<th><?php p($l->t('Invoice number'));?></th>
<th><?php p($l->t('Date of service'));?></th>
@ -34,10 +36,38 @@
<th>Lieu</th>
<th><?php p($l->t('Articles'));?></th>
<th><?php p($l->t('Status'));?></th>
<th><?php p($l->t('Date de paiement'));?></th>
<th><?php p($l->t('Actions'));?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="modal" id="facturePaymentModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Choisir le mode de paiement et la date de paiement</h5>
</div>
<div class="modal-body">
<div class="d-flex align-items-center gap-2">
<select class="form-select w-auto" name="payment_type" id="selectPaymentType">
<?php
$paymentTypes = $_['paymentTypes'];
foreach($paymentTypes as $paymentType){
?>
<option value="<?= $paymentType->id; ?>"><?= $paymentType->facture_payment_type_label; ?></option>
<?php
}
?>
<input type="date" id="facturePaymentDate">
</div>
</div>
<div class="modal-footer">
<button id="closeFacturePaymentModal" type="button" class="btn btn-secondary">Annuler</button>
<button id="payInvoice" type="button" class="btn btn-primary">Payer</button>
</div>
</div>
</div>
</div>
</div>