28require_once
'../main.inc.php';
36require_once DOL_DOCUMENT_ROOT.
'/core/class/html.form.class.php';
37require_once DOL_DOCUMENT_ROOT.
'/core/lib/files.lib.php';
38require_once DOL_DOCUMENT_ROOT.
'/ai/class/ai.class.php';
39require_once DOL_DOCUMENT_ROOT.
'/societe/class/societe.class.php';
40require_once DOL_DOCUMENT_ROOT.
'/product/class/product.class.php';
41require_once DOL_DOCUMENT_ROOT.
'/fourn/class/fournisseur.facture.class.php';
43$langs->loadLangs(array(
"main",
"exports",
"other"));
45$action =
GETPOST(
'action',
'aZ09');
46$modulepart =
GETPOST(
'modulepart',
'aZ09');
52$upload_dir =
$conf->user->dir_temp.
'/import';
57$originalfilename = $file;
58$uid = $thiid = $pid = $erid = $salid = 0;
60if (preg_match(
'/-uid([\d+])/', $file, $reg)) {
62 $originalfilename = preg_replace(
'/-uid\d+/',
'', $originalfilename);
64if (preg_match(
'/-thiid([\d+])/', $file, $reg)) {
66 $originalfilename = preg_replace(
'/-thiid\d+/',
'', $originalfilename);
68if (preg_match(
'/-pid([\d+])/', $file, $reg)) {
70 $originalfilename = preg_replace(
'/-pid\d+/',
'', $originalfilename);
72if (preg_match(
'/-erid([\d+])/', $file, $reg)) {
74 $originalfilename = preg_replace(
'/-erid\d+/',
'', $originalfilename);
76if (preg_match(
'/-salid([\d+])/', $file, $reg)) {
78 $originalfilename = preg_replace(
'/-salid\d+/',
'', $originalfilename);
80$originalfilename = preg_replace(
'/^upload_page-[a-z_]+-/',
'', $originalfilename);
96 header(
"Location: ".$urlforuploadpage);
100if ($action ==
'uploadfile') {
102 print
'Error, modulepart param is empty';
109 $module = $arrayobject[
'module'];
110 $element = $arrayobject[
'element'];
111 $dir_output = $arrayobject[
'dir_output'];
112 $dir_temp = $arrayobject[
'dir_temp'];
114 $permlevel1 =
'read';
116 $fileprefix =
'unknown';
117 if (in_array($modulepart, array(
'fournisseur',
'invoice_supplier'))) {
118 $permlevel1 =
'facture';
119 $permlevel2 =
'read';
121 } elseif ($modulepart ==
'expensereport') {
122 $fileprefix =
'upload_page-'.$modulepart.
'-uid'.$user->id.
'-erid'.(
GETPOSTINT(
'userexpensereportid') > 0 ?
GETPOSTINT(
'userexpensereportid') : 0).
'-pid'.(
GETPOSTINT(
'search_prodid') > 0 ?
GETPOSTINT(
'search_prodid') : 0);
123 } elseif ($modulepart ==
'salaries') {
124 $fileprefix =
'upload_page-'.$modulepart.
'-uid'.$user->id.
'-salid'.(
GETPOSTINT(
'usersalaryid') > 0 ?
GETPOSTINT(
'usersalaryid') : 0);
128 $permissiontoadd = $user->hasRight($module, $permlevel1, $permlevel2);
130 $permissiontoadd = $user->hasRight($module, $permlevel1);
132 $forceFullTextIndexation =
'0';
135 if (!empty($_FILES[
'userfile'][
'name'])) {
136 $fullnewname = $fileprefix.
'-'.$_FILES[
'userfile'][
'name'];
137 $_FILES[
'userfile'][
'name'] = $fullnewname;
142 include DOL_DOCUMENT_ROOT.
'/core/actions_linkedfiles.inc.php';
149 $ajaxFileUrl = DOL_URL_ROOT.
'/core/ajax/ajaxuploadpage.php?file='.urlencode($fullnewname);
178$title = $langs->trans(
"UploadFile");
182$arrayofcss = array();
184llxHeader(
'', $title, $help_url,
'', 0, 0, $arrayofjs, $arrayofcss,
'',
'mod-upload page-card');
190$hookmanager->initHooks(array(
'uploadform'));
198 $uploadform =
'<div class="display-flex">';
201 $prodtext = $langs->trans(
"RefOrLabel");
203 $langs->load(
"bills");
205 <div id="supplierinvoice" class="flex-item flex-item-uploadfile">'.img_picto(
'',
'bill',
'class="fa-2x"').
'<br>
206 <div>'.$langs->trans(
"SupplierInvoice").
'<br><br>';
212 $uploadform .=
img_picto(
'',
'company',
'class="pictofixedwidth"');
213 $uploadform .= $form->select_company($socid,
'socid',
'(statut:=:0)', $langs->transnoentitiesnoconv(
"Supplier"), 0, 0, array(), 0,
'maxwidth200 disableautoopen');
215 $uploadform .=
'<br>';
218 $uploadform .=
img_picto(
'',
'product',
'class="pictofixedwidth"');
219 $uploadform .= $form->select_produits_fournisseurs(0, $prodid,
'prodid',
'',
'', array(), 1, 1,
'maxwidth200 disableautoopen', $prodtext, 1);
221 $uploadform .=
'<br>';
224 <small class="opacitymedium">'.$langs->trans(
"OrClickToSelectAFile").
'...</small>
231 $langs->load(
"expensereport");
233 <div id="userexpensereport" class="flex-item flex-item-uploadfile">'.img_picto(
'',
'expensereport',
'class="fa-2x"').
'<br>
234 <div>'.$langs->trans(
"ExpenseReport").
'<br><br>';
236 $uploadform .=
img_picto(
'',
'user',
'class="pictofixedwidth"');
238 $uploadform .= $form->select_dolusers(
GETPOSTINT(
'userexpensereportid') > 0 ?
GETPOSTINT(
'userexpensereportid') : $user->id,
'userexpensereportid', $langs->transnoentitiesnoconv(
"User"), null, 0,
'hierarchyme',
'',
'', 0, 0,
'', 0,
'',
'maxwidth200 disableautoopen', 1);
241 $uploadform .=
'<br>';
244 <small class="opacitymedium">'.$langs->trans(
"OrClickToSelectAFile").
'...</small>
252 $langs->load(
"salaries");
254 <div id="userpayroll" class="flex-item flex-item-uploadfile">'.img_picto(
'',
'salary',
'class="fa-2x"').
'<br>
255 <div>'.$langs->trans(
"UserPaySlip").
'<br><br>';
258 $uploadform .=
img_picto(
'',
'user',
'class="pictofixedwidth"');
260 $uploadform .= $form->select_dolusers(
GETPOSTINT(
'usersalaryid') > 0 ?
GETPOSTINT(
'usersalaryid') : $user->id,
'usersalaryid', $langs->transnoentitiesnoconv(
"Employee"), null, 0,
'hierarchyme',
'',
'', 0, 0,
'', 0,
'',
'maxwidth200 disableautoopen', 1);
263 $uploadform .=
'<br>';
266 <small class="opacitymedium">'.$langs->trans(
"OrClickToSelectAFile").
'...</small>
271 $uploadform .=
'</div>';
277$parameters = array(
'uploadform' => $uploadform);
278$reshook = $hookmanager->executeHooks(
'printUploadForm', $parameters);
279if (empty($reshook)) {
280 $uploadform .= $hookmanager->resPrint;
282 $uploadform = $hookmanager->resPrint;
285$uploadform .=
'<br>';
288if ($action ==
'uploadfile' || $action ==
'showsummary') {
289 print
'<b>'.$langs->trans(
"ImportingFile", $originalfilename).
'</b><br>';
292 print
'<div class="'.($action ==
'showsummary' ?
'green' :
'neutral').
'" style="padding-left: 20px; padding-right: 20px;">';
294 print
'<div class="marginbottom">';
295 if ($action ==
'showsummary') {
296 print $langs->trans(
"AIProcessingDone", $ai->getApiService());
298 print $langs->trans(
"AIProcessingPleaseWait", $ai->getApiService()).
'...';
303 print
'<div class="progress" title="80%">
304 <div class="progress-bar" role="progressbar" style="width: '.($action ==
'showsummary' ?
'100' :
'0').
'%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
310 if (!empty($ajaxFileUrl)) {
312 $(document).ready(function() {
313 console.log("Call ajaxFileUrl: '.dol_escape_js($ajaxFileUrl).
'");
318 beforeSend:
function() {
319 $(
".progress-bar").css(
"width",
"25%");
321 success:
function(data, textStatus, jqXHR) {
322 if (jqXHR.status === 200) {
324 console.log(
"Fill the #ajax-result with json result");
326 $(
"#ajax-result").val(JSON.stringify(data,
null, 2));
327 $(
".progress-bar").css(
"width",
"100%");
330 $(
"#form-result-submit").show();
333 $(
"#ajax-result").html(
"<div class=\"error\">Error: HTTP status " + jqXHR.status +
"</div>");
336 error:
function(jqXHR, textStatus, errorThrown) {
338 $(
"#ajax-result").html(
"<div class=\"error\">Error: " + (jqXHR.responseText || errorThrown ||
"Unknown error") +
"</div>");
339 $(
".progress-bar").css(
"width",
"100%");
346 // Example of JSON result when importing a supplier PDF invoice
350 "invoice_number": "MSTRL-API-1234-001",
351 "invoice_reference": "Pro - Annual",
352 "issue_date": "2026-08-21",
353 "due_date": "2026-08-21",
356 "description": "0 jours"
358 "organization": "MyBigCompany"
361 "name": "Mistral AI SAS",
363 "street": "15, rue des Halles",
364 "postal_code": "75001",
368 "vat_number": "FR95952418325",
370 "siren": "952 418 325",
371 "capital": "19,189.04 €",
374 "email": "no-reply@mistral.ai",
375 "contact_url": "https://help.mistral.ai/en"
378 "name": "MyBigCompany",
380 "street": "1 rue de la paix",
381 "postal_code": "75000",
385 "vat_number": "FR012345678901",
386 "email": "contact@mybigcompany.com"
390 "description": "Fee for use- August",
391 "service": "Pro - Annual",
395 "total_excluding_tax": 143.9,
396 "total_including_tax": 172.68,
397 "period_start": "2026-08-21",
398 "period_end": "2027-08-20"
402 "subtotal_excluding_tax": 143.9,
406 "description": "EU FR Standard (20.0% sur 143,90 €)"
408 "total_including_tax": 172.68
411 "due_date": "2026-08-21",
412 "amount_due": 172.68,
419 "content": "Mistral AI - SAS au capital de 19,189.04€ - 952 418 325 R.C.S. Paris"
423 "content": "For any inquiry, please refer to https://help.mistral.ai/en"
430 print '<form
class=
"" id=
"form-result" method=
"POST">
';
431 print '<input
type=
"hidden" name=
"token" value=
"'.newToken().'">
';
432 print '<input
type=
"hidden" name=
"modulepart" value=
"'.$modulepart.'">
';
433 print '<input
type=
"hidden" name=
"action" value=
"showsummary">
';
434 print '<input
type=
"hidden" name=
"socid" value=
"'.$socid.'">
';
435 print '<input
type=
"hidden" name=
"prodid" value=
"'.$prodid.'">
';
436 print '<input
type=
"hidden" name=
"originalfilename" value=
"'.$fullnewname.'">
';
437 print '<input
type=
"hidden" name=
"jsonstring" id=
"ajax-result" value=
"jsonstringtoreplace">
';
438 if ($action == 'uploadfile
') {
439 print '<input
type=
"submit" name=
"form-result-submit" class=
"" value=
"'.$langs->trans("Next
").'">
'; // TODO Hide.
441 print '</form>
'."\n";
445if ($action == 'showsummary
') {
446 print '<form
class=
"" id=
"summary-result">
';
448 print '<div
class=
"neutral">
';
450 print '<input
type=
"hidden" name=
"token" value=
"'.newToken().'">
';
452 $json = json_decode(GETPOST('jsonstring
', 'restricthtml
'), true);
454 if ($modulepart == 'invoice_supplier
') {
456 <div
id=
"supplierinvoice" class=
"">
';
458 //print '<div
class=
"inline-block">
'.img_picto('', 'bill
', '').' '.$langs->trans("SupplierInvoice").'</div>
';
461 $nameindoc = $json['vendor
']['name'];
462 $addressindoc = $json['vendor
']['address'];
463 $idprof1indoc = $json['professional_id
']['siren
'];
464 $idprof2indoc = $json['supplier
']['siret
'];
465 $emailindoc = $json['email'];
466 $vatnumberindoc = $json['vat_number
'];
469 $tmpthirdparty = new Societe($db);
470 print img_picto('', 'company
', 'class=
"pictofixedwidth"').$langs->trans("ThirdParty").'<br>
';
471 if (GETPOSTINT('socid
')) {
472 $tmpthirdparty->fetch(GETPOSTINT('socid
'));
473 // TODO We can show a warning if we find a diff with autodetected value $nameindoc
475 // Try to find thirdparty
476 $result = $tmpthirdparty->findNearest(0, $nameindoc, '', '', $idprof1indoc, $idprof2indoc, '', '', '', '', $emailindoc, $vatnumberindoc, 0, 0, '1
');
479 $tmpthirdparty->id = $result;
483 print '<span
class=
"opacitymedium">
'.$langs->trans("FoundInDocument").' :</span>
';
484 print $nameindoc.',
'.implode(',
', $addressindoc);
486 if (empty($tmpthirdparty->id)) {
487 print '<span
class=
"opacitymedium">
'.$langs->trans("NotFoundInDatabase").'</span><br>
';
488 print $langs->trans("ChooseTheThirdPartyTouse").' ';
489 print $form->select_company($socid, 'socid
', '(statut:=:0)
', $langs->trans("Name"), 0, 0, array(), 0, 'maxwidth200 disableautoopen
');
490 //print '
'.$langs->trans("or").' <input
type=
"checkbox" name=
"createthirdparty" id=
"createthirdparty" value=
"1" checked><label
for=
"createthirdparty">
'.$langs->trans("CreateIt").'</label>
';
492 print $langs->trans("WillUse").' ';
493 print $tmpthirdparty->getNomUrl(1);
494 print '<input
type=
"hidden" name=
"socid" value=
"'.$tmpthirdparty->id.'">
';
505 $prodid = GETPOSTINT('prodid
');
506 $prodtext = $langs->trans("RefOrLabel");
508 $tmpproduct = new Product($db);
509 print img_picto('', 'product
', 'class=
"pictofixedwidth"').$langs->trans("Product").'<br>
';
512 $tmpproduct->fetch($prodid);
513 // TODO We can show a warning if we find a diff with autodetected value $json['items
']['service
']
515 //$tmpproduct->ref = $json['ref'];
518 print '<span
class=
"opacitymedium">
'.$langs->trans("FoundInDocument").' :</span>
';
519 print $nameprodindoc;
521 if (empty($tmpproduct->id)) {
522 print $langs->trans("ChooseTheProductTouse").' ';
523 print $form->select_produits_fournisseurs(0, $prodid, 'prodid
', '', '', array(), 1, 1, 'maxwidth200 disableautoopen
', $prodtext, 1);
525 print $langs->trans("WillUse").' ';
526 print $tmpproduct->getNomUrl(1);
527 print '<input
type=
"hidden" name=
"prodid" value=
"'.$tmpproduct->id.'">
';
533 $tmpinvoice = new FactureFournisseur($db);
535 $invoiceindoc = $ai->decodeJsonIntoArray($json, 'supplier_invoice
');
537 print img_picto('', 'supplier_invoice
', 'class=
"pictofixedwidth"').$langs->trans("SupplierInvoice").'<br>
';
539 print '<span
class=
"opacitymedium">
'.$langs->trans("FoundInDocument").' :</span>
';
540 print $invoiceindoc['supplierref
'].' -
'.$invoiceindoc['due_date
'].' -
'.$invoiceindoc['issue_date
'];
541 print ' -
'.$invoiceindoc['currency_code
'];
545 if (!empty($invoiceindoc['supplierref
'])) {
546 // Try to find supplier invoice
547 // TODO Search using ref (see code of einvoicing module)
548 //$tmpinvoice->find...
551 if (empty($tmpinvoice->id)) {
552 print $langs->trans("InvoiceWillBeCreated");
554 print $tmpinvoice->getNomUrl(1);
555 print '<input
type=
"hidden name="invoiceid
" value="'.$tmpinvoice->id.'">';
563 print '<center><input type="submit
" name="submit
" class="button" value="'.$langs->trans("Create").'"></center>';
566 print '<input type="hidden
" name="jsonstring
" value="'.$json.'">';
573 print "<!-- Begin UploadForm -->\n
";
574 print '<form id="uploadform
" enctype="multipart/form-data
" method="POST
" action="'.dolBuildUrl($_SERVER["PHP_SELF"]).'">';
575 print '<input type="hidden
" name="token
" value="'.newToken().'">';
576 print '<input type="hidden
" name="action
" value="uploadfile
">';
577 print '<input type="hidden
" name="sendit
" value="1
">';
578 print '<input type="hidden
" name="modulepart
" id="modulepart
" value="">';
579 print '<input type="hidden
" name="overwritefile
" value="1
">';
581 print '<div class="center
"><div class="center
" style="padding: 10px;
">';
582 print '<style>.menu_titre { padding-top: 7px; }</style>';
583 print '<div id="blockupload
" class="center
">'."\n
";
584 //print '<input name="filenamePDF
" id="filenamePDF
" type="hideobject
">';
588 $accept = '.pdf,image/*';
593 $maxfilesizearray = getMaxFileSizeArray();
594 $max = $maxfilesizearray['max'];
595 $maxmin = $maxfilesizearray['maxmin'];
596 $maxphptoshow = $maxfilesizearray['maxphptoshow'];
597 $maxphptoshowparam = $maxfilesizearray['maxphptoshowparam'];
600 $out .= '<input type="hidden
" name="MAX_FILE_SIZE
" value="'.($maxmin * 1024).'">'; // MAX_FILE_SIZE must precede the field type=file
602 $out .= '<input class="hideobject
" type="file
" id="fileInput
" value=""';
603 // @phpstan-ignore-next-line
604 $out .= ((getDolGlobalString('MAIN_DISABLE_MULTIPLE_FILEUPLOAD') || $disablemulti) ? ' name="userfile
"' : ' name="userfile[]
" multiple');
605 // @phpstan-ignore-next-line
606 $out .= (!getDolGlobalString('MAIN_UPLOAD_DOC') || empty($perm) ? ' disabled' : '');
607 // @phpstan-ignore-next-line
608 $out .= (!empty($accept) ? ' accept="'.$accept.'"' : ' accept=""');
609 // @phpstan-ignore-next-line
610 $out .= (!empty($capture) ? ' capture="capture
"' : '');
617 $(document).ready(
function() {
618 jQuery(
'#supplierinvoice:not(.disableautoopen)').on(
'click',
function(event) {
619 console.log(
'Click on link supplierinvoice to open input file');
621 if (!event.target.closest(
'.disableautoopen')) {
622 $(
'#modulepart').val(
'invoice_supplier');
623 $(
'#fileInput').click();
627 jQuery(
'#userexpensereport:not(.disableautoopen)').on(
'click',
function(event) {
628 console.log(
'Click on link userexpensereport to open input file');
630 if (!event.target.closest(
'.disableautoopen')) {
631 $(
'#modulepart').val(
'expensereport');
632 $(
'#fileInput').click();
636 jQuery(
'#userpayroll:not(.disableautoopen)').on(
'click',
function(event) {
637 console.log(
'Click on link userpayroll to open input file');
639 if (!event.target.closest(
'.disableautoopen')) {
640 $(
'#modulepart').val(
'salaries');
641 $(
'#fileInput').click();
645 jQuery(
'#fileInput').on(
'change',
function(event) {
647 console.log(
'A file was selected, we submit the form');
648 $(
'#uploadform').submit();
654 print '</div></div>';
657 print "\n<!-- End UploadForm -->\n
";
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as p label as s rowid as s nom as s email
Sender: Who sends the email ("Sender" has sent emails on behalf of "From").
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
getElementProperties($elementType)
Get an array with properties of an element.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
multi select button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
div refaddress div address
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
$conf db name
Only used if Module[ID]Name translation string is not found.