From: Kilian Saffran Date: Thu, 11 Jul 2024 11:09:32 +0000 (+0200) Subject: v240711 3 X-Git-Tag: 0.27.2~2 X-Git-Url: http://cloud.dks.lu/git/?a=commitdiff_plain;h=7dc9c2c9340fd73b2c5ed2ecedd32c348e929a6b;p=ngl-snep.git v240711 3 --- diff --git a/public_html/lib/App/Cotisations.php b/public_html/lib/App/Cotisations.php index ab1e27c..435179e 100644 --- a/public_html/lib/App/Cotisations.php +++ b/public_html/lib/App/Cotisations.php @@ -55,7 +55,7 @@ and (mc.status != 'payed' or mc.status is null) and mc.id_member=".$this->dbh->v } public function saveExportSepaRow($id,$data){ - $updsql = $this->dbh->createUpdateDDL("saveExportSepaRow",array("id" => $id),$data); + $updsql = $this->dbh->createUpdateDDL("nextsepaexport",array("id" => $id),$data); $ret = $this->dbh->exec($updsql); return $ret; } @@ -164,6 +164,13 @@ unaccent(UPPER(m.firstname)) as firstname,unaccent(UPPER(m.lastname)) as lastnam join banks b on (m.ID_bank=b.ID_bank) where mc.id In (".implode(",",$ids).") and m.sepasigned = 1 group by mc.id;"; $this->dbh->exec($sql); + return 1; + } + + public function setStatus($status,$ids){ + $sql = "UPDATE members_cotisation SET status=".$this->dbh->value($status)." WHERE id in (".implode(",",$ids).")"; + $this->dbh->exec($sql); + return 1; } } diff --git a/public_html/scripts/exportsepaxml.php b/public_html/scripts/exportsepaxml.php index 2f7b4ac..d627ab9 100644 --- a/public_html/scripts/exportsepaxml.php +++ b/public_html/scripts/exportsepaxml.php @@ -57,7 +57,7 @@ echo "recherche des membres à exporter!\n"; $sql = "select * from nextsepaexport;"; // $sql = "select mc.id,m.id_member,m.quota as amount, m.datesepasigned as sepasig_date , b.biccode as bic,unaccent(UPPER(CONCAT(m.lastname,' ',m.firstname))) as fullname, - // replace(m.bankaccount,' ','') as iban,CONCAT('NGL-SNEP ','".str_pad($p["month"], 2, "0", STR_PAD_LEFT )."','/','".$p["year"]."') as message,case when sum(case when mx.cntstatus > 0 then 1 else 0 end) > 0 then 'RCUR' else 'FRST' end as seqtype + // replace(m.bankaccount,' ','') as iban,CONCAT('NGL-SNEP ','".str_pad($p["month"], 2, "0", STR_PAD_LEFT )."','/','".$p["year"]."') as message,case when sum(case when mx.cntstatus > 0 then 1 else 0 end) > 0 then 'RCUR' else 'FRST' end as sepa_type // from members m // join members_cotisation mc on (m.id_member=mc.id_member) // left join (select id_member,count(status) as cntstatus from members_cotisation where status is not null and status != 'error' group by id_member) mx on (mx.id_member=m.id_member) @@ -88,7 +88,7 @@ // //file_put_contents("log/debug.log","parse unpaiddata:".print_r($p["ids"],true)."\n",FILE_APPEND); // $sql = "select mc.id,m.id_member,m.quota as amount, m.datesepasigned as sepasig_date , b.biccode as bic,CONCAT(m.lastname,' ',m.firstname) as fullname, - // m.bankaccount as iban,CONCAT('NGL-SNEP ', DATE_FORMAT(mc.date_month,'%m/%Y')) as message,case when sum(case when mx.cntstatus > 0 then 1 else 0 end) > 0 then 'RCUR' else 'FRST' end as seqtype + // m.bankaccount as iban,CONCAT('NGL-SNEP ', DATE_FORMAT(mc.date_month,'%m/%Y')) as message,case when sum(case when mx.cntstatus > 0 then 1 else 0 end) > 0 then 'RCUR' else 'FRST' end as sepa_type // from members m // join members_cotisation mc on (m.id_member=mc.id_member) // left join (select id_member,count(status) as cntstatus from members_cotisation where status is not null and status != 'error' group by id_member) mx on (mx.id_member=m.id_member) @@ -143,11 +143,11 @@ $DrctDbtTxInf .= " ".$CrLf; $DrctDbtTxInf .= " ".$CrLf; //file_put_contents($cfg["datapath"]."tmp/debug.log","Pmt_inf:\n".print_r($py,true),FILE_APPEND); - if (!isset($sepa_pmtinf[$py["seqtype"]])){ - $sepa_pmtinf[$py["seqtype"]] = array("DrctDbtTxInf" => array(),"CommonPmtInf" => "","sumDrctDbtTxInf" => 0.0); + if (!isset($sepa_pmtinf[$py["sepa_type"]])){ + $sepa_pmtinf[$py["sepa_type"]] = array("DrctDbtTxInf" => array(),"CommonPmtInf" => "","sumDrctDbtTxInf" => 0.0); } - array_push($sepa_pmtinf[$py["seqtype"]]["DrctDbtTxInf"],$DrctDbtTxInf); - $sepa_pmtinf[$py["seqtype"]]["sumDrctDbtTxInf"] += $py["amount"]; + array_push($sepa_pmtinf[$py["sepa_type"]]["DrctDbtTxInf"],$DrctDbtTxInf); + $sepa_pmtinf[$py["sepa_type"]]["sumDrctDbtTxInf"] += $py["amount"]; $countall++; #echo "Transaction ".$countall."/".$totaltx." ajoutée\n"; $sumall+=$py["amount"]; diff --git a/public_html/tmpl/dialogs/dlg_changestatus.php b/public_html/tmpl/dialogs/dlg_changestatus.php new file mode 100644 index 0000000..4907d44 --- /dev/null +++ b/public_html/tmpl/dialogs/dlg_changestatus.php @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/public_html/tmpl/js/app/invoicing.min.js b/public_html/tmpl/js/app/invoicing.min.js index 821ee9d..a768777 100644 --- a/public_html/tmpl/js/app/invoicing.min.js +++ b/public_html/tmpl/js/app/invoicing.min.js @@ -1 +1 @@ -let invoicing={tbl:null,tbldates:null,selects:{},init:function(){let tomorrow=new Date;tomorrow.setDate(tomorrow.getDate()+1),flatpickr("#debitdate",{altInput:!0,allowInput:!0,altFormat:"d/m/Y",dateFormat:"Y-m-d",defaultDate:tomorrow,minDate:tomorrow}),this.selects=dataform.initSelects(document.getElementsByClassName("select")),invoicing.tbldates=new Tabulator("#tbl_dates",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 65px)",layout:"fitDataStretch",selectableRows:1,columns:[{title:"Mois",field:"id",width:120,hozAlign:"center",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Count",field:"cnt",width:50,headerFilter:!1,headerSort:!1,hozAlign:"right"}]}),invoicing.tbldates.on("rowClick",(function(e,row){invoicing.gettblCotisationsData(),invoicing.gettblTransactionsData()})),invoicing.tbl_cotisations=new Tabulator("#tbl_cotisations",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 120px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editCotisation(),!1}},{label:'voir fiche membre',action:function(e,row){return invoicing.viewMember(),!1}},{separator:!0},{label:'Selectionner tous les visibles',action:function(e,row){return invoicing.selectVisibleCotisationRows(),!1}},{label:'Ajouter la selection à la table d\'export SEPA',action:function(e,row){return invoicing.copySelectedToExportView(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0,headerMenu:tablehelper.headerMenu},columns:[{title:"ID",field:"id_member"},{title:"Nom",field:"lastname",width:200},{title:"Prénom",field:"firstname",width:200},{title:"Mois",field:"date_month",visible:!1,formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Date Traitement",field:"date_transaction",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"dd/MM/yyyy",invalidPlaceholder:""}},{title:"status",field:"status",headerFilter:"list",formatter:tablehelper.statusFormatter,headerFilterParams:{valuesLookup:!0,clearable:!0}},{title:"Montant",field:"amount",formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2},bottomCalc:tablehelper.totalAmount},{title:"Type Payement",field:"paymenttype",headerFilter:"list",headerFilterParams:{valuesLookup:!0,clearable:!0}},{title:"Fichier Export",field:"sepa_file_out",visible:!1},{title:"Fichier Import",field:"transaction_file_in",visible:!1},{title:"ID Transaction",field:"transaction_id",visible:!1},{title:"Code SEPA",field:"last_sepa_code",visible:!1},{title:"IBAN",field:"bank_account"},{title:"BIC",field:"bank_bic"},{title:"Type Sepa",field:"sepa_type"}]}),invoicing.tbl_cotisations.on("rowDblClick",(function(e,row){invoicing.editCotisation()})),invoicing.tbl_transactions=new Tabulator("#tbl_transactions",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 120px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editTransaction(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0},columns:[{title:"Date Transaction",field:"datemovement"},{title:"nom",field:"lastname"},{title:"Prénom",field:"firstname"},{title:"succès",field:"success"},{title:"Cotisation Type",field:"quotatype"},{title:"Montant",field:"quota",formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2}},{title:"Fichier XML Retour",field:"filexml"},{title:"Ficher XML Envoi",field:"refxml"},{title:"Sepa signé",field:"sepasigned"},{title:"Groupe Sepa",field:"sepagroup"},{title:"Compte Débiteur",field:"accountout"},{title:"Compter Crediteur",field:"accountin"},{title:"Note",field:"quotaobs"},{title:"Message Erreur",field:"errormsg"},{title:"Code Erreur",field:"errorcode"}]}),invoicing.tblexportsepa=new Tabulator("#tbl_exportsepa",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 125px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editExportSepa(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0},columns:[{title:"ID Membre",field:"id_member"},{title:"Nom",field:"fullname",width:250},{title:"Mois",field:"date_month",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Montant",field:"amount",headerFilter:!1,headerSort:!1,width:100,formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2},bottomCalc:tablehelper.totalAmount},{title:"Message",field:"message",width:250},{title:"Signature Date",field:"sepasig_date",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"dd/MM/yyyy",invalidPlaceholder:""}},{title:"Type SEPA",field:"sepa_type"},{title:"IBAN",field:"iban",width:200},{title:"BIC",field:"bic",width:80}]})},load:function(){invoicing.gettbldates(),invoicing.gettblTransactionsData(),invoicing.gettblCotisationsData(),myapp.viewpanel("invoicing")},gettbldates:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),postData({cl:"Cotisations",fn:"getDatesList"}).then(data=>{invoicing.tbldates.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},gettblTransactionsData:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),sel&&sel[0]&&postData({cl:"Payments",fn:"getList",month:sel[0].month,year:sel[0].year}).then(data=>{invoicing.tbl_transactions.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},gettblCotisationsData:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),sel&&sel[0]&&postData({cl:"Cotisations",fn:"getList",monthdate:sel[0].id}).then(data=>{invoicing.tbl_cotisations.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},editCotisation:function(){let sel=null;invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData()),document.getElementById("dlg_cotisation_btnok").setAttribute("onclick","invoicing.saveCotisation();"),sel[0]&&postData({cl:"Cotisations",fn:"getRowData",id:sel[0].id}).then(data=>{dataform.fillform("cotisation",this.selects,data.result.data),myapp.viewdialog("cotisation")})},saveCotisation(){let datatosave=dataform.getContent("cotisation",invoicing.selects),transferdata={amount:datatosave.amount,paymenttype:datatosave.paymenttype,date_transaction:datatosave.date_transaction,status:datatosave.status,bank_account:datatosave.bank_account,bank_bic:datatosave.bank_bic,sepa_type:datatosave.sepa_type};postData({cl:"Cotisations",fn:"saveRow",id:datatosave.id,data:transferdata}).then(data=>{invoicing.gettblCotisationsData(),document.getElementById("dlg_cotisation").style.display="none"}).catch(e=>{document.getElementById("dlg_cotisation").style.display="none"})},editExportSepa:function(){let sel=null;invoicing.tblexportsepa&&(sel=invoicing.tblexportsepa.getSelectedData()),document.getElementById("dlg_nextsepaexport_btnok").setAttribute("onclick","invoicing.saveExportSepa();"),sel[0]&&postData({cl:"Cotisations",fn:"getExportSepaRowData",id:sel[0].id}).then(data=>{dataform.fillform("nextsepaexport",this.selects,data.result.data,"nse"),myapp.viewdialog("nextsepaexport")})},saveExportSepa(){let datatosave=dataform.getContent("nextsepaexport",invoicing.selects),transferdata={amount:datatosave.amount,sepasig_date:datatosave.sepasig_date,fullname:datatosave.fullname,amount:datatosave.amount,message:datatosave.message,iban:datatosave.iban,bic:datatosave.bic,sepa_type:datatosave.sepa_type};postData({cl:"Cotisations",fn:"saveExportSepaRow",id:datatosave.nextsepaexport_id,data:transferdata}).then(data=>{invoicing.viewTabExport(),document.getElementById("dlg_nextsepaexport").style.display="none"}).catch(e=>{document.getElementById("dlg_nextsepaexport").style.display="none"})},editTransaction:function(){let sel=null;invoicing.tbl&&(sel=invoicing.tbl.getSelectedData()),sel[0]&&postData({cl:"Cotisations",fn:"getRowData",id:sel[0].id}).then(data=>{dataform.fillform("cotisation",this.selects,data.result.data),myapp.viewdialog("cotisation")})},saveTransaction(){},viewMember:function(){var windowReference;(invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData()),sel[0])&&(window.open().location=api+"index?id="+sel[0].id_member)},getCountries:function(){postData({cl:"Countries",fn:"getCountries"}).then(data=>{data.result.data.unshift({iso2:null,country:null}),dataform.fillselectlist(this.selects.birthcountry,data.result.data,"iso2","country"),dataform.fillselectlist(this.selects.addresscountry,data.result.data,"iso2","country")})},loadFileDlg(){},importSepa(){myapp.upload("Import fichier XML SEPA","","importer","annuler","invoicing.importSepaFile();","text/xml")},getProcessInfo(logfile){postData({cl:"WorkerProcess",fn:"getLastWorkerInfo",logfile:logfile}).then(data=>{var windowReference;data.result.data.info&&"error"!=data.result.data.status?(myapp.setDataloadText(data.result.data.info),data.result.data.info.startsWith("End: ")&&(progressinfo.stopGetInfo(),logfile.endsWith("exportsepa.log")&&!data.result.data.info.startsWith("End: Erreur:")&&(window.open().location=api+"file.php?open="+encodeURIComponent(invoicing.exportfile)))):"error"==data.result.data.status&&(myapp.setDataloadText(data.result.data.error),progressinfo.stopGetInfo())}).catch(e=>{myapp.setDataloadText("ne peux pas avoir d'info sur le progrès!")})},importSepaFile(){myapp.openDataload("Import données","Attendez svp! Import XML encours!"),postFile(document.getElementById("dlg_uploadfile_files"),{folder:"importsepa"}).then(data=>{data.file?postData({cl:"Sepa",fn:"startSepaImport",xmlfile:data.file}).then(data=>{progressinfo.startGetInfo("invoicing.getProcessInfo('"+data.result.data.log+"')",1)}):(myapp.closeDataload(),myapp.message("Erreur","Échec de l'importation du fichier XML!"))}).catch(e=>{myapp.closeDataload(),myapp.message("Erreur","Échec de l'importation du fichier XML!",e.msg)})},viewTabExport:function(){myapp.viewtab("tab_invoicing","inv_export"),myapp.openDataload("Recherche données","Attendez svp!"),postData({cl:"Cotisations",fn:"getExportTable"}).then(data=>{invoicing.tblexportsepa.setData(data.result.data).then(data=>{}),myapp.closeDataload()}).catch(e=>{console.log(e),myapp.closeDataload()})},viewTabTransactions:function(){myapp.viewtab("tab_invoicing","inv_transactions")},viewTabCotisations:function(){myapp.viewtab("tab_invoicing","inv_cotisations")},addCotisationMonth:function(){myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"addCotisationMonth",monthdate:"latest"}).then(data=>{invoicing.gettbldates(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})},syncSepaTransactions:function(){let selmonyear=invoicing.tbldates.getSelectedData();selmonyear[0]?(myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"syncSepaTransactions",monthdate:selmonyear[0].id}).then(data=>{invoicing.gettblCotisationsData(),invoicing.gettblTransactionsData(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})):myapp.message("Info","Pas de mois sélectionné!")},syncMembers:function(){let selmonyear=invoicing.tbldates.getSelectedData();selmonyear[0]?(myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"addCotisationMonth",monthdate:selmonyear[0].id}).then(data=>{invoicing.gettbldates(),invoicing.gettblCotisationsData(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})):myapp.message("Info","Pas de mois sélectionné!")},selectVisibleCotisationRows:function(){invoicing.tbl_cotisations.selectRow("active")},copySelectedToExportView:function(){let selexp=invoicing.tbl_cotisations.getSelectedData();if(selexp[0]){myapp.openDataload("Copy des données en cours","Attendez svp!");let addsel=[];for(i=0;i{myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})}},cleanExportTable:function(){postData({cl:"Cotisations",fn:"cleanExportTable"}).then(data=>{invoicing.viewTabExport()}).catch(e=>{})},removefromExportTable:function(){let selexp=invoicing.tblexportsepa.getSelectedData();if(selexp[0]){let rmsel=[];for(i=0;i{invoicing.viewTabExport()}).catch(e=>{})}},exportSepa:function(){let debitdate=document.getElementById("debitdate").value;myapp.openDataload("Export des données","Attendez svp! Export XML encours!"),postData({cl:"Sepa",fn:"createSepa",debitdate:debitdate}).then(data=>{progressinfo.startGetInfo("invoicing.getProcessInfo('"+data.result.data.log+"')",1),invoicing.exportfile=data.result.data.file}).catch(e=>{myapp.closeDataload(),myapp.message("Erreur","Échec de l'export du fichier XML!",e.msg)})}}; \ No newline at end of file +let invoicing={tbl:null,tbldates:null,selects:{},init:function(){let tomorrow=new Date;tomorrow.setDate(tomorrow.getDate()+1),flatpickr("#debitdate",{altInput:!0,allowInput:!0,altFormat:"d/m/Y",dateFormat:"Y-m-d",defaultDate:tomorrow,minDate:tomorrow}),this.selects=dataform.initSelects(document.getElementsByClassName("select")),invoicing.tbldates=new Tabulator("#tbl_dates",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 65px)",layout:"fitDataStretch",selectableRows:1,columns:[{title:"Mois",field:"id",width:120,hozAlign:"center",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Count",field:"cnt",width:50,headerFilter:!1,headerSort:!1,hozAlign:"right"}]}),invoicing.tbldates.on("rowClick",(function(e,row){invoicing.gettblCotisationsData(),invoicing.gettblTransactionsData()})),invoicing.tbl_cotisations=new Tabulator("#tbl_cotisations",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 120px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editCotisation(),!1}},{label:'voir fiche membre',action:function(e,row){return invoicing.viewMember(),!1}},{separator:!0},{label:'Selectionner tous les visibles',action:function(e,row){return invoicing.selectVisibleCotisationRows(),!1}},{label:'Ajouter la selection à la table d\'export SEPA',action:function(e,row){return invoicing.copySelectedToExportView(),!1}},{label:'Changer status (sélection)',action:function(e,row){return invoicing.viewChangeStatus(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0,headerMenu:tablehelper.headerMenu},columns:[{title:"ID",field:"id_member"},{title:"Nom",field:"lastname",width:200},{title:"Prénom",field:"firstname",width:200},{title:"Mois",field:"date_month",visible:!1,formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Date Traitement",field:"date_transaction",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"dd/MM/yyyy",invalidPlaceholder:""}},{title:"status",field:"status",headerFilter:"list",formatter:tablehelper.statusFormatter,headerFilterParams:{valuesLookup:!0,clearable:!0}},{title:"Montant",field:"amount",formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2},bottomCalc:tablehelper.totalAmount},{title:"Type Payement",field:"paymenttype",headerFilter:"list",headerFilterParams:{valuesLookup:!0,clearable:!0}},{title:"Fichier Export",field:"sepa_file_out",visible:!1},{title:"Fichier Import",field:"transaction_file_in",visible:!1},{title:"ID Transaction",field:"transaction_id",visible:!1},{title:"Code SEPA",field:"last_sepa_code",visible:!1},{title:"IBAN",field:"bank_account"},{title:"BIC",field:"bank_bic"},{title:"Type Sepa",field:"sepa_type"}]}),invoicing.tbl_cotisations.on("rowDblClick",(function(e,row){invoicing.editCotisation()})),invoicing.tbl_transactions=new Tabulator("#tbl_transactions",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 120px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editTransaction(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0},columns:[{title:"Date Transaction",field:"datemovement"},{title:"nom",field:"lastname"},{title:"Prénom",field:"firstname"},{title:"succès",field:"success"},{title:"Cotisation Type",field:"quotatype"},{title:"Montant",field:"quota",formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2}},{title:"Fichier XML Retour",field:"filexml"},{title:"Ficher XML Envoi",field:"refxml"},{title:"Sepa signé",field:"sepasigned"},{title:"Groupe Sepa",field:"sepagroup"},{title:"Compte Débiteur",field:"accountout"},{title:"Compter Crediteur",field:"accountin"},{title:"Note",field:"quotaobs"},{title:"Message Erreur",field:"errormsg"},{title:"Code Erreur",field:"errorcode"}]}),invoicing.tblexportsepa=new Tabulator("#tbl_exportsepa",{columnDefaults:{resizable:!1,headerFilterPlaceholder:"",headerSort:!0,headerFilter:"input",formatter:"html"},height:"calc(100vh - 125px)",layout:"fitDataStretch",selectableRows:!0,selectableRowsRangeMode:"click",rowContextMenu:[{label:'éditer',action:function(e,row){return invoicing.editExportSepa(),!1}}],rowHeader:{formatter:"rownum",headerSort:!1,hozAlign:"center",resizable:!1,frozen:!0},columns:[{title:"ID Membre",field:"id_member"},{title:"Nom",field:"fullname",width:250},{title:"Mois",field:"date_month",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"MM/yyyy",invalidPlaceholder:""}},{title:"Montant",field:"amount",headerFilter:!1,headerSort:!1,width:100,formatter:"money",hozAlign:"right",formatterParams:{decimal:",",thousand:"",symbol:"€",symbolAfter:"p",negativeSign:!0,precision:2},bottomCalc:tablehelper.totalAmount},{title:"Message",field:"message",width:250},{title:"Signature Date",field:"sepasig_date",formatter:"datetime",formatterParams:{inputFormat:"yyyy-MM-dd",outputFormat:"dd/MM/yyyy",invalidPlaceholder:""}},{title:"Type SEPA",field:"sepa_type"},{title:"IBAN",field:"iban",width:200},{title:"BIC",field:"bic",width:80}]}),invoicing.tblexportsepa.on("rowDblClick",(function(e,row){invoicing.editExportSepa()}))},load:function(){invoicing.gettbldates(),invoicing.gettblTransactionsData(),invoicing.gettblCotisationsData(),myapp.viewpanel("invoicing")},gettbldates:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),postData({cl:"Cotisations",fn:"getDatesList"}).then(data=>{invoicing.tbldates.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},gettblTransactionsData:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),sel&&sel[0]&&postData({cl:"Payments",fn:"getList",month:sel[0].month,year:sel[0].year}).then(data=>{invoicing.tbl_transactions.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},gettblCotisationsData:function(){let sel=null;invoicing.tbldates.initialized&&(sel=invoicing.tbldates.getSelectedData()),sel&&sel[0]&&postData({cl:"Cotisations",fn:"getList",monthdate:sel[0].id}).then(data=>{invoicing.tbl_cotisations.setData(data.result.data).then(data=>{})}).catch(e=>{console.log(e)})},editCotisation:function(){let sel=null;invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData()),document.getElementById("dlg_cotisation_btnok").setAttribute("onclick","invoicing.saveCotisation();"),sel[0]&&postData({cl:"Cotisations",fn:"getRowData",id:sel[0].id}).then(data=>{dataform.fillform("cotisation",this.selects,data.result.data),myapp.viewdialog("cotisation")})},saveCotisation(){let datatosave=dataform.getContent("cotisation",invoicing.selects),transferdata={amount:datatosave.amount,paymenttype:datatosave.paymenttype,date_transaction:datatosave.date_transaction,status:datatosave.status,bank_account:datatosave.bank_account,bank_bic:datatosave.bank_bic,sepa_type:datatosave.sepa_type};postData({cl:"Cotisations",fn:"saveRow",id:datatosave.id,data:transferdata}).then(data=>{invoicing.gettblCotisationsData(),document.getElementById("dlg_cotisation").style.display="none"}).catch(e=>{document.getElementById("dlg_cotisation").style.display="none"})},editExportSepa:function(){let sel=null;invoicing.tblexportsepa&&(sel=invoicing.tblexportsepa.getSelectedData()),document.getElementById("dlg_nextsepaexport_btnok").setAttribute("onclick","invoicing.saveExportSepa();"),sel[0]&&postData({cl:"Cotisations",fn:"getExportSepaRowData",id:sel[0].id}).then(data=>{dataform.fillform("nextsepaexport",this.selects,data.result.data,"nse"),myapp.viewdialog("nextsepaexport")})},saveExportSepa(){let datatosave=dataform.getContent("nextsepaexport",invoicing.selects),transferdata={amount:datatosave.nextsepaexport_amount,fullname:datatosave.nextsepaexport_fullname,amount:datatosave.nextsepaexport_amount,message:datatosave.nextsepaexport_message,iban:datatosave.nextsepaexport_iban,bic:datatosave.nextsepaexport_bic,sepa_type:datatosave.nextsepaexport_sepa_type};console.log("Export row to save",transferdata,datatosave.nextsepaexport_id),postData({cl:"Cotisations",fn:"saveExportSepaRow",id:datatosave.nextsepaexport_id,data:transferdata}).then(data=>{invoicing.viewTabExport(),document.getElementById("dlg_nextsepaexport").style.display="none"}).catch(e=>{document.getElementById("dlg_nextsepaexport").style.display="none"})},editTransaction:function(){let sel=null;invoicing.tbl&&(sel=invoicing.tbl.getSelectedData()),sel[0]&&postData({cl:"Cotisations",fn:"getRowData",id:sel[0].id}).then(data=>{dataform.fillform("cotisation",this.selects,data.result.data),myapp.viewdialog("cotisation")})},saveTransaction(){},viewChangeStatus:function(){let sel=null;invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData()),sel[0]&&(document.getElementById("dlg_changestatus_btnok").setAttribute("onclick","invoicing.changeStatus();"),myapp.viewdialog("changestatus"))},changeStatus:function(){let sel=null;invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData());let chsel=[];for(i=0;i{invoicing.gettblCotisationsData(),myapp.closeDialog("changestatus")}).catch(e=>{myapp.closeDialog("changestatus")})},viewMember:function(){var windowReference;(invoicing.tbl_cotisations&&(sel=invoicing.tbl_cotisations.getSelectedData()),sel[0])&&(window.open().location=api+"index?id="+sel[0].id_member)},getCountries:function(){postData({cl:"Countries",fn:"getCountries"}).then(data=>{data.result.data.unshift({iso2:null,country:null}),dataform.fillselectlist(this.selects.birthcountry,data.result.data,"iso2","country"),dataform.fillselectlist(this.selects.addresscountry,data.result.data,"iso2","country")})},loadFileDlg(){},importSepa(){myapp.upload("Import fichier XML SEPA","","importer","annuler","invoicing.importSepaFile();","text/xml")},getProcessInfo(logfile){postData({cl:"WorkerProcess",fn:"getLastWorkerInfo",logfile:logfile}).then(data=>{var windowReference;data.result.data.info&&"error"!=data.result.data.status?(myapp.setDataloadText(data.result.data.info),data.result.data.info.startsWith("End: ")&&(progressinfo.stopGetInfo(),logfile.endsWith("exportsepa.log")&&!data.result.data.info.startsWith("End: Erreur:")&&(window.open().location=api+"file.php?open="+encodeURIComponent(invoicing.exportfile)))):"error"==data.result.data.status&&(myapp.setDataloadText(data.result.data.error),progressinfo.stopGetInfo())}).catch(e=>{myapp.setDataloadText("ne peux pas avoir d'info sur le progrès!")})},importSepaFile(){myapp.openDataload("Import données","Attendez svp! Import XML encours!"),postFile(document.getElementById("dlg_uploadfile_files"),{folder:"importsepa"}).then(data=>{data.file?postData({cl:"Sepa",fn:"startSepaImport",xmlfile:data.file}).then(data=>{progressinfo.startGetInfo("invoicing.getProcessInfo('"+data.result.data.log+"')",1)}):(myapp.closeDataload(),myapp.message("Erreur","Échec de l'importation du fichier XML!"))}).catch(e=>{myapp.closeDataload(),myapp.message("Erreur","Échec de l'importation du fichier XML!",e.msg)})},viewTabExport:function(){myapp.viewtab("tab_invoicing","inv_export"),myapp.openDataload("Recherche données","Attendez svp!"),postData({cl:"Cotisations",fn:"getExportTable"}).then(data=>{invoicing.tblexportsepa.setData(data.result.data).then(data=>{}),myapp.closeDataload()}).catch(e=>{console.log(e),myapp.closeDataload()})},viewTabTransactions:function(){myapp.viewtab("tab_invoicing","inv_transactions")},viewTabCotisations:function(){myapp.viewtab("tab_invoicing","inv_cotisations")},addCotisationMonth:function(){myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"addCotisationMonth",monthdate:"latest"}).then(data=>{invoicing.gettbldates(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})},syncSepaTransactions:function(){let selmonyear=invoicing.tbldates.getSelectedData();selmonyear[0]?(myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"syncSepaTransactions",monthdate:selmonyear[0].id}).then(data=>{invoicing.gettblCotisationsData(),invoicing.gettblTransactionsData(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})):myapp.message("Info","Pas de mois sélectionné!")},syncMembers:function(){let selmonyear=invoicing.tbldates.getSelectedData();selmonyear[0]?(myapp.openDataload("Synchronisation des données en cours","Attendez svp!"),postData({cl:"Cotisations",fn:"addCotisationMonth",monthdate:selmonyear[0].id}).then(data=>{invoicing.gettbldates(),invoicing.gettblCotisationsData(),myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})):myapp.message("Info","Pas de mois sélectionné!")},selectVisibleCotisationRows:function(){invoicing.tbl_cotisations.selectRow("active")},copySelectedToExportView:function(){let selexp=invoicing.tbl_cotisations.getSelectedData();if(selexp[0]){myapp.openDataload("Copy des données en cours","Attendez svp!");let addsel=[];for(i=0;i{myapp.closeDataload()}).catch(e=>{myapp.closeDataload()})}},cleanExportTable:function(){postData({cl:"Cotisations",fn:"cleanExportTable"}).then(data=>{invoicing.viewTabExport()}).catch(e=>{})},removefromExportTable:function(){let selexp=invoicing.tblexportsepa.getSelectedData();if(selexp[0]){let rmsel=[];for(i=0;i{invoicing.viewTabExport()}).catch(e=>{})}},exportSepa:function(){let debitdate=document.getElementById("debitdate").value;myapp.openDataload("Export des données","Attendez svp! Export XML encours!"),postData({cl:"Sepa",fn:"createSepa",debitdate:debitdate}).then(data=>{progressinfo.startGetInfo("invoicing.getProcessInfo('"+data.result.data.log+"')",1),invoicing.exportfile=data.result.data.file}).catch(e=>{myapp.closeDataload(),myapp.message("Erreur","Échec de l'export du fichier XML!",e.msg)})}}; \ No newline at end of file diff --git a/public_html/tmpl/js/app/tablehelper.min.js b/public_html/tmpl/js/app/tablehelper.min.js index dcb32f6..942054e 100644 --- a/public_html/tmpl/js/app/tablehelper.min.js +++ b/public_html/tmpl/js/app/tablehelper.min.js @@ -1 +1 @@ -let tablehelper={headerMenu:function(){var menu=[],columns=this.getColumns();let first=!0;for(let column of columns){if(first){first=!1;continue}let icon=document.createElement("span");icon.classList.add("icon-inline"),icon.classList.add(column.isVisible()?"icon-rndcheck-ok":"icon-rndcheck-not");let label=document.createElement("span"),title=document.createElement("span");title.innerHTML=" "+column.getDefinition().title.replace(/\/g," "),label.appendChild(icon),label.appendChild(title),menu.push({label:label,action:function(e){e.stopPropagation(),column.toggle(),column.isVisible()?(icon.classList.remove("icon-rndcheck-not"),icon.classList.add("icon-rndcheck-ok")):(icon.classList.remove("icon-rndcheck-ok"),icon.classList.add("icon-rndcheck-not"))}})}return menu},setColDef:function(data){let coldef={title:data.COLUMN_NAME,field:data.COLUMN_NAME};return"PRI"==data.COLUMN_KEY&&(coldef.field="id"),(data.COLUMN_NAME.startsWith("ID_")||data.COLUMN_NAME.startsWith("new_")||data.COLUMN_NAME.startsWith("update_"))&&(coldef.visible=!1),data.COLUMN_NAME.startsWith("int")&&(coldef.formatter="plaintext",coldef.hozAlign="right"),coldef},dateFormatter:function(cell,formatterParams){return null!=cell.getValue()?DateTime.fromISO(cell.getValue()).toFormat("dd.MM.yyyy"):""},monthFormatter:function(cell,formatterParams){return DateTime.fromISO(cell._cell.row.data.myear+"-"+cell.getValue()+"-01").toFormat("MMM yy")},boldFormatter:function(cell,formatterParams){return cell.getElement().style.fontWeight="bold",cell.getValue()},imgFormatter(cell,formatterParams){var vstyle="",ret="";return null!=cell.getValue()&&(formatterParams&&Object.entries(formatterParams).forEach(entry=>{const[key,value]=entry;vstyle+=key+":"+value+";"}),ret=''),ret},ArrayToString:function(cell,formatterParams){let xval="";if(null!=cell.getValue())try{xval=JSON.parse(cell.getValue()).join(",")}catch(e){xval=""}return xval},colorFormatter:function(cell,formatterParams){return null!=cell._cell.row.data.bgcolor&&(cell.getElement().style.backgroundColor=colors.hexToRgbA(cell._cell.row.data.bgcolor,1)),cell.getValue()},dldDataAccessor:function(value,data,type,params,column){return null==value&&(value=""),value},nullFormatter:function(cell,formatterParams){return cell.getElement().style.backgroundColor="grey",""},totalAmount:function(values,data,calcParams){let amnt=0;for(let m in values)amnt+=parseFloat(values[m]);return amnt.toFixed(2)+"€"},statusFormatter:function(cell,formatterParams){var value=cell.getValue();return value&&(dataformatter.status[value].color&&(cell.getElement().style.color=dataformatter.status[value].color),dataformatter.status[value].text)?dataformatter.status[value].text:value}},dataformatter={status:{"":{color:"",text:""},open:{color:"orange",text:"ouvert"},exported:{color:"grey",text:"exporté"},sended:{color:"orange",text:"envoyé"},payed:{color:"green",text:"payé"},error:{color:"red",text:"erreur"}}}; \ No newline at end of file +let tablehelper={headerMenu:function(){var menu=[],columns=this.getColumns();let first=!0;for(let column of columns){if(first){first=!1;continue}let icon=document.createElement("span");icon.classList.add("icon-inline"),icon.classList.add(column.isVisible()?"icon-rndcheck-ok":"icon-rndcheck-not");let label=document.createElement("span"),title=document.createElement("span");title.innerHTML=" "+column.getDefinition().title.replace(/\/g," "),label.appendChild(icon),label.appendChild(title),menu.push({label:label,action:function(e){e.stopPropagation(),column.toggle(),column.isVisible()?(icon.classList.remove("icon-rndcheck-not"),icon.classList.add("icon-rndcheck-ok")):(icon.classList.remove("icon-rndcheck-ok"),icon.classList.add("icon-rndcheck-not"))}})}return menu},setColDef:function(data){let coldef={title:data.COLUMN_NAME,field:data.COLUMN_NAME};return"PRI"==data.COLUMN_KEY&&(coldef.field="id"),(data.COLUMN_NAME.startsWith("ID_")||data.COLUMN_NAME.startsWith("new_")||data.COLUMN_NAME.startsWith("update_"))&&(coldef.visible=!1),data.COLUMN_NAME.startsWith("int")&&(coldef.formatter="plaintext",coldef.hozAlign="right"),coldef},dateFormatter:function(cell,formatterParams){return null!=cell.getValue()?DateTime.fromISO(cell.getValue()).toFormat("dd.MM.yyyy"):""},monthFormatter:function(cell,formatterParams){return DateTime.fromISO(cell._cell.row.data.myear+"-"+cell.getValue()+"-01").toFormat("MMM yy")},boldFormatter:function(cell,formatterParams){return cell.getElement().style.fontWeight="bold",cell.getValue()},imgFormatter(cell,formatterParams){var vstyle="",ret="";return null!=cell.getValue()&&(formatterParams&&Object.entries(formatterParams).forEach(entry=>{const[key,value]=entry;vstyle+=key+":"+value+";"}),ret=''),ret},ArrayToString:function(cell,formatterParams){let xval="";if(null!=cell.getValue())try{xval=JSON.parse(cell.getValue()).join(",")}catch(e){xval=""}return xval},colorFormatter:function(cell,formatterParams){return null!=cell._cell.row.data.bgcolor&&(cell.getElement().style.backgroundColor=colors.hexToRgbA(cell._cell.row.data.bgcolor,1)),cell.getValue()},dldDataAccessor:function(value,data,type,params,column){return null==value&&(value=""),value},nullFormatter:function(cell,formatterParams){return cell.getElement().style.backgroundColor="grey",""},totalAmount:function(values,data,calcParams){let amnt=0;for(let m in values)amnt+=parseFloat(values[m]);return amnt.toFixed(2)+"€"},statusFormatter:function(cell,formatterParams){var value=cell.getValue();return value&&(dataformatter.status[value].color&&(cell.getElement().style.color=dataformatter.status[value].color),dataformatter.status[value].text)?dataformatter.status[value].text:value}},dataformatter={status:{"":{color:"",text:""},open:{color:"orange",text:"ouvert"},exported:{color:"grey",text:"exporté"},sended:{color:"orange",bisque:"envoyé"},payed:{color:"green",text:"payé"},error:{color:"red",text:"erreur"},canceled:{color:"silver",text:"annulé"}}}; \ No newline at end of file diff --git a/public_html/tmpl/js/common/tablehelper.js b/public_html/tmpl/js/common/tablehelper.js index a2d9a00..c9e0564 100644 --- a/public_html/tmpl/js/common/tablehelper.js +++ b/public_html/tmpl/js/common/tablehelper.js @@ -153,8 +153,9 @@ let dataformatter ={ "":{"color":"","text":""}, "open":{"color":"orange","text":"ouvert"}, "exported":{"color":"grey","text":"exporté"}, - "sended":{"color":"orange","text":"envoyé"}, + "sended":{"color":"orange","bisque":"envoyé"}, "payed":{"color":"green","text":"payé"}, "error":{"color":"red","text":"erreur"}, + "canceled":{"color":"silver","text":"annulé"}, } }; diff --git a/public_html/tmpl/js/pages/invoicing.js b/public_html/tmpl/js/pages/invoicing.js index 228a780..8a72f81 100644 --- a/public_html/tmpl/js/pages/invoicing.js +++ b/public_html/tmpl/js/pages/invoicing.js @@ -69,6 +69,7 @@ let invoicing = { { separator:true}, {label:'Selectionner tous les visibles', action:function(e, row){invoicing.selectVisibleCotisationRows(); return false;}}, {label:'Ajouter la selection à la table d\'export SEPA', action:function(e, row){invoicing.copySelectedToExportView(); return false;}}, + {label:'Changer status (sélection)', action:function(e, row){invoicing.viewChangeStatus(); return false;}}, ], rowHeader:{formatter:"rownum", headerSort:false, hozAlign:"center", resizable:false, frozen:true,headerMenu:tablehelper.headerMenu}, columns: [ @@ -171,6 +172,9 @@ let invoicing = { {title:"BIC",field:"bic",width: 80}, ] }); + invoicing.tblexportsepa.on("rowDblClick",function(e, row){ + invoicing.editExportSepa(); + }); }, load: function(){ //document.getElementById("moduletitle").innerHTML = "Membres"; @@ -291,16 +295,16 @@ let invoicing = { }, saveExportSepa(){ let datatosave = dataform.getContent("nextsepaexport",invoicing.selects); - let transferdata = {"amount":datatosave["amount"], - "sepasig_date":datatosave["sepasig_date"], - "fullname":datatosave["fullname"], - "amount":datatosave["amount"], - "message":datatosave["message"], - "iban":datatosave["iban"], - "bic":datatosave["bic"], - "sepa_type":datatosave["sepa_type"] + let transferdata = {"amount":datatosave["nextsepaexport_amount"], + //"sepasig_date":datatosave["nextsepaexport_sepasig_date"], + "fullname":datatosave["nextsepaexport_fullname"], + "amount":datatosave["nextsepaexport_amount"], + "message":datatosave["nextsepaexport_message"], + "iban":datatosave["nextsepaexport_iban"], + "bic":datatosave["nextsepaexport_bic"], + "sepa_type":datatosave["nextsepaexport_sepa_type"] } - //console.log("data to save",datatosave); + console.log("Export row to save",transferdata,datatosave["nextsepaexport_id"]); postData({"cl":"Cotisations","fn":"saveExportSepaRow","id":datatosave["nextsepaexport_id"],"data":transferdata}).then( data =>{ invoicing.viewTabExport(); document.getElementById('dlg_nextsepaexport').style.display='none'; @@ -339,6 +343,36 @@ let invoicing = { // document.getElementById('dlg_cotisation').style.display='none'; // }); }, + viewChangeStatus: function(){ + let sel = null; + if (invoicing.tbl_cotisations){ + sel = invoicing.tbl_cotisations.getSelectedData(); + } + if (sel[0]){ + document.getElementById("dlg_changestatus_btnok").setAttribute('onclick',"invoicing.changeStatus();"); + myapp.viewdialog("changestatus"); + } + }, + changeStatus: function(){ + let sel = null; + if (invoicing.tbl_cotisations){ + sel = invoicing.tbl_cotisations.getSelectedData(); + } + let chsel = []; + for(i=0;i { + invoicing.gettblCotisationsData(); + myapp.closeDialog("changestatus"); + }).catch(e => { + myapp.closeDialog("changestatus"); + }); + } + }, viewMember: function(){ if (invoicing.tbl_cotisations){ sel = invoicing.tbl_cotisations.getSelectedData(); diff --git a/public_html/tmpl/pages/invoicing.php b/public_html/tmpl/pages/invoicing.php index 3b1112e..f4071ed 100644 --- a/public_html/tmpl/pages/invoicing.php +++ b/public_html/tmpl/pages/invoicing.php @@ -13,7 +13,9 @@ + + @@ -65,4 +67,5 @@