From ae3d7865939fc8145b12704b0b18eed50d7054ca Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 3 Jun 2020 11:20:59 +0200 Subject: [PATCH 1/5] Fix crop on media file manager Conflicts: htdocs/core/ajax/ajaxdirpreview.php htdocs/core/photos_resize.php htdocs/theme/eldy/global.inc.php --- htdocs/core/ajax/ajaxdirpreview.php | 19 +++++++------ htdocs/core/class/html.formfile.class.php | 16 +++++++---- htdocs/core/photos_resize.php | 34 ++++++++++++++--------- htdocs/theme/eldy/global.inc.php | 6 ++-- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/htdocs/core/ajax/ajaxdirpreview.php b/htdocs/core/ajax/ajaxdirpreview.php index 83227b00e51..32d4f8d3bfa 100644 --- a/htdocs/core/ajax/ajaxdirpreview.php +++ b/htdocs/core/ajax/ajaxdirpreview.php @@ -61,15 +61,16 @@ if (!isset($mode) || $mode != 'noajax') // For ajax call $upload_dir = dirname(str_replace("../", "/", $rootdirfordoc.'/'.$file)); - $ecmdir = new EcmDirectory($db); - $result = $ecmdir->fetch($section); - if (!$result > 0) - { - //dol_print_error($db,$ecmdir->error); - //exit; - } -} -else // For no ajax call + $ecmdir = new EcmDirectory($db); + if ($section > 0) { + $result = $ecmdir->fetch($section); + if (!$result > 0) + { + //dol_print_error($db,$ecmdir->error); + //exit; + } + } +} else // For no ajax call { $rootdirfordoc = $conf->ecm->dir_output; diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 0da4b2ca390..651280369a1 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1107,7 +1107,7 @@ class FormFile if ($disablecrop == -1) { $disablecrop = 1; - if (in_array($modulepart, array('bank', 'bom', 'expensereport', 'holiday', 'member', 'mrp', 'project', 'product', 'produit', 'propal', 'service', 'societe', 'tax', 'tax-vat', 'ticket', 'user'))) $disablecrop = 0; + if (in_array($modulepart, array('bank', 'bom', 'expensereport', 'holiday', 'medias', 'member', 'mrp', 'project', 'product', 'produit', 'propal', 'service', 'societe', 'tax', 'tax-vat', 'ticket', 'user'))) $disablecrop = 0; } // Define relative path used to store the file @@ -1375,11 +1375,11 @@ class FormFile // Delete or view link // ($param must start with &) print ''; - if ($useinecm == 1 || $useinecm == 5) + if ($useinecm == 1 || $useinecm == 5) // ECM manual tree { - print ''.img_edit('default', 0, 'class="paddingrightonly"').''; + print ''.img_edit('default', 0, 'class="paddingrightonly"').''; } - if (empty($useinecm) || $useinecm == 2 || $useinecm == 6) + if (empty($useinecm) || $useinecm == 2 || $useinecm == 6) // 6=Media file manager { $newmodulepart = $modulepart; if (in_array($modulepart, array('product', 'produit', 'service'))) $newmodulepart = 'produit|service'; @@ -1389,7 +1389,13 @@ class FormFile if ($permtoeditline) { // Link to resize - print ''.img_picto($langs->trans("ResizeOrCrop"), 'resize', 'class="paddingrightonly"').''; + $moreparaminurl = ''; + if ($object->id > 0) { + $moreparaminurl = '&id='.$object->id; + } elseif (GETPOST('website', 'alpha')) { + $moreparaminurl = '&website='.GETPOST('website', 'alpha'); + } + print ''.img_picto($langs->trans("ResizeOrCrop"), 'resize', 'class="paddingrightonly"').''; } } diff --git a/htdocs/core/photos_resize.php b/htdocs/core/photos_resize.php index 2686efa6419..bd480dc865e 100644 --- a/htdocs/core/photos_resize.php +++ b/htdocs/core/photos_resize.php @@ -40,7 +40,7 @@ $cancel = GETPOST('cancel', 'alpha'); $file = GETPOST('file', 'alpha'); $num = GETPOST('num', 'alpha'); // Used for document on bank statement - +$website = GETPOST('website', 'alpha'); // Security check if (empty($modulepart)) accessforbidden('Bad value for modulepart'); @@ -86,8 +86,12 @@ elseif ($modulepart == 'bank') $result = restrictedArea($user, 'banque', $id, 'bank_account'); if (!$user->rights->banque->lire) accessforbidden(); $accessallowed = 1; -} -else // ticket, holiday, expensereport, societe... +} elseif ($modulepart == 'medias') +{ + $permtoadd = ($user->rights->mailing->creer || $user->rights->website->write); + if (!$permtoadd) accessforbidden(); + $accessallowed = 1; +} else // ticket, holiday, expensereport, societe... { $result = restrictedArea($user, $modulepart, $id, $modulepart); if (empty($user->rights->$modulepart->read) && empty($user->rights->$modulepart->lire)) accessforbidden(); @@ -224,9 +228,7 @@ elseif ($modulepart == 'bom') if ($result <= 0) dol_print_error($db, 'Failed to load object'); $dir = $conf->$modulepart->dir_output; // By default } -} -elseif ($modulepart == 'mrp') -{ +} elseif ($modulepart == 'mrp') { require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php'; $object = new MO($db); if ($id > 0) @@ -235,9 +237,7 @@ elseif ($modulepart == 'mrp') if ($result <= 0) dol_print_error($db, 'Failed to load object'); $dir = $conf->$modulepart->dir_output; // By default } -} -elseif ($modulepart == 'bank') -{ +} elseif ($modulepart == 'bank') { require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; $object = new Account($db); if ($id > 0) @@ -246,8 +246,9 @@ elseif ($modulepart == 'bank') if ($result <= 0) dol_print_error($db, 'Failed to load object'); $dir = $conf->bank->dir_output; // By default } -} -else { +} elseif ($modulepart == 'medias') { + $dir = $dolibarr_main_data_root.'/'.$modulepart; +} else { print 'Action crop for modulepart = '.$modulepart.' is not supported yet by photos_resize.php.'; } @@ -271,6 +272,8 @@ if (empty($backtourl)) } elseif (in_array($modulepart, array('bank'))) $backtourl = DOL_URL_ROOT."/compta/bank/document.php?id=".$id.'&file='.urldecode($file); elseif (in_array($modulepart, array('mrp'))) $backtourl = DOL_URL_ROOT."/mrp/mo_document.php?id=".$id.'&file='.urldecode($file); + elseif (in_array($modulepart, array('medias'))) $backtourl = DOL_URL_ROOT."/website/index.php?action=file_manager&website=".$website."&file=".urldecode($file).'&preopend=image'; + // Generic case that should work for everybody else else $backtourl = DOL_URL_ROOT."/".$modulepart."/".$modulepart."_document.php?id=".$id.'&file='.urldecode($file); } @@ -301,7 +304,10 @@ if ($action == 'confirm_resize' && GETPOSTISSET("file") && GETPOSTISSET("sizex") if ($result == $fullpath) { - $object->addThumbs($fullpath); + // If image is related to a given object, we create also thumbs. + if (is_object($object)) { + $object->addThumbs($fullpath); + } // Update/create database for file $fullpath $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $fullpath); @@ -371,7 +377,9 @@ if ($action == 'confirm_crop') if ($result == $fullpath) { - $object->addThumbs($fullpath); + if (is_object($object)) { + $object->addThumbs($fullpath); + } // Update/create database for file $fullpath $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $fullpath); diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 15a58295949..0ec69d4934a 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -667,10 +667,12 @@ body[class*="colorblind-"] .text-success{ color : } -.editfielda span.fa-pencil-alt, .editfielda span.fa-trash, .editfieldlang { +.editfielda span.fa-pencil-alt, .editfielda span.fa-pencil-ruler, .editfielda span.fa-trash, .editfielda span.fa-crop, +.editfieldlang { color: #ccc !important; } -.editfielda span.fa-pencil-alt:hover, .editfielda span.fa-trash:hover, .editfieldlang:hover { +.editfielda span.fa-pencil-alt:hover, .editfielda span.fa-pencil-ruler:hover, .editfielda span.fa-trash:hover, .editfielda span.fa-crop:hover, +.editfieldlang:hover { color: var(--colortexttitle) !important; } .fawidth30 { From 51c578840c76a87e27b3103705c5b5bc98fa0555 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 3 Jun 2020 11:40:51 +0200 Subject: [PATCH 2/5] Fix cancel in media filemanager --- htdocs/website/index.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index b3d5ee7be49..aa24134a6f4 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -321,6 +321,13 @@ if (GETPOST('refreshsite', 'alpha') || GETPOST('refreshsite.x', 'alpha') || GETP } if (GETPOST('refreshpage', 'alpha') && !in_array($action, array('updatecss'))) $action = 'preview'; +if ($action == 'renamefile') { + $action = 'file_manager'; // After actions_linkedfiles, if action were renamefile, we set it to 'file_manager' +} +if ($cancel && $action == 'file_manager') { + $cancel = ''; +} + // Cancel if ($cancel) { @@ -339,8 +346,6 @@ if ($sortorder) $backtopage .= '&sortorder='.$sortorder; include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; $backtopage = $savbacktopage; -if ($action == 'renamefile') $action = 'file_manager'; // After actions_linkedfiles, if action were renamefile, we set it to 'file_manager' - if ($action == 'seteditinline') { dolibarr_set_const($db, 'WEBSITE_EDITINLINE', 1); From 8023bc2fbb808a28218efac8bf93931c5554d30d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 3 Jun 2020 12:34:09 +0200 Subject: [PATCH 3/5] Fix cancel in media filemanager --- htdocs/core/class/html.formfile.class.php | 1 + htdocs/core/photos_resize.php | 6 +++++- htdocs/website/index.php | 12 ++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 651280369a1..7251db1476e 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1270,6 +1270,7 @@ class FormFile { print ''; $section_dir = dirname(GETPOST('urlfile', 'alpha')); + if (! preg_match('/\/$/', $section_dir)) $section_dir.='/'; print ''; print ''; print ''; diff --git a/htdocs/core/photos_resize.php b/htdocs/core/photos_resize.php index bd480dc865e..fc4d7b9f24c 100644 --- a/htdocs/core/photos_resize.php +++ b/htdocs/core/photos_resize.php @@ -272,7 +272,11 @@ if (empty($backtourl)) } elseif (in_array($modulepart, array('bank'))) $backtourl = DOL_URL_ROOT."/compta/bank/document.php?id=".$id.'&file='.urldecode($file); elseif (in_array($modulepart, array('mrp'))) $backtourl = DOL_URL_ROOT."/mrp/mo_document.php?id=".$id.'&file='.urldecode($file); - elseif (in_array($modulepart, array('medias'))) $backtourl = DOL_URL_ROOT."/website/index.php?action=file_manager&website=".$website."&file=".urldecode($file).'&preopend=image'; + elseif (in_array($modulepart, array('medias'))) { + $section_dir = dirname($file); + if (! preg_match('/\/$/', $section_dir)) $section_dir.='/'; + $backtourl = DOL_URL_ROOT."/website/index.php?action=file_manager&website=".$website.'§ion_dir='.urlencode($section_dir); + } // Generic case that should work for everybody else else $backtourl = DOL_URL_ROOT."/".$modulepart."/".$modulepart."_document.php?id=".$id.'&file='.urldecode($file); } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index aa24134a6f4..7153a7bc3d0 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -321,10 +321,7 @@ if (GETPOST('refreshsite', 'alpha') || GETPOST('refreshsite.x', 'alpha') || GETP } if (GETPOST('refreshpage', 'alpha') && !in_array($action, array('updatecss'))) $action = 'preview'; -if ($action == 'renamefile') { - $action = 'file_manager'; // After actions_linkedfiles, if action were renamefile, we set it to 'file_manager' -} -if ($cancel && $action == 'file_manager') { +if ($cancel && $action == 'renamefile') { $cancel = ''; } @@ -346,6 +343,10 @@ if ($sortorder) $backtopage .= '&sortorder='.$sortorder; include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; $backtopage = $savbacktopage; +if ($action == 'renamefile') { // Must be after include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php'; If action were renamefile, we set it to 'file_manager' + $action = 'file_manager'; +} + if ($action == 'seteditinline') { dolibarr_set_const($db, 'WEBSITE_EDITINLINE', 1); @@ -2423,8 +2424,7 @@ if (!GETPOST('hide_websitemenu')) // Toolbar for pages - - if ($websitekey && $websitekey != '-1' && !in_array($action, array('editcss', 'editmenu', 'importsite', 'file_manager', 'replacesite', 'replacesiteconfirm'))) + if ($websitekey && $websitekey != '-1' && !in_array($action, array('editcss', 'editmenu', 'importsite', 'file_manager', 'replacesite', 'replacesiteconfirm')) && !$file_manager) { print ''; // Close current websitebar to open a new one From 7b84518e59d5ad7cc012f36329eabbc780240c42 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 3 Jun 2020 14:05:18 +0200 Subject: [PATCH 4/5] Fix webp support --- htdocs/core/js/lib_head.js.php | 6 +++++- htdocs/core/lib/functions.lib.php | 6 ++++-- htdocs/core/lib/images.lib.php | 25 +++++++++++++++++++++---- htdocs/product/class/product.class.php | 2 +- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/htdocs/core/js/lib_head.js.php b/htdocs/core/js/lib_head.js.php index 1efa4c88771..9de5ceba476 100644 --- a/htdocs/core/js/lib_head.js.php +++ b/htdocs/core/js/lib_head.js.php @@ -880,12 +880,13 @@ function newpopup(url, title) { */ function document_preview(file, type, title) { - var ValidImageTypes = ["image/gif", "image/jpeg", "image/png"]; + var ValidImageTypes = ["image/gif", "image/jpeg", "image/png", "image/webp"]; var showOriginalSizeButton = false; console.log("document_preview A click was done. file="+file+", type="+type+", title="+title); if ($.inArray(type, ValidImageTypes) < 0) { + /* Not an image */ var width='85%'; var object_width='100%'; var height = ($( window ).height() - 60) * 0.90; @@ -894,6 +895,7 @@ function document_preview(file, type, title) show_preview('notimage'); } else { + /* This is an image */ var object_width=0; var object_height=0; @@ -904,11 +906,13 @@ function document_preview(file, type, title) object_height = this.height; width = $( window ).width()*0.90; + console.log("object_width="+object_width+" window width="+width); if(object_width < width){ console.log("Object width is small, we set width of popup according to image width."); width = object_width + 30 } height = $( window ).height()*0.85; + console.log("object_height="+object_height+" window height="+height); if(object_height < height){ console.log("Object height is small, we set height of popup according to image height."); height = object_height + 80 diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index b30bc99f38a..dd107308fed 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -8055,7 +8055,7 @@ function getImageFileNameForSize($file, $extName, $extImgTarget = '') $dirName = dirname($file); if ($dirName == '.') $dirName = ''; - $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp)$/i', '', $file); // We remove extension, whatever is its case + $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case $fileName = basename($fileName); if (empty($extImgTarget)) $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : ''); @@ -8063,6 +8063,7 @@ function getImageFileNameForSize($file, $extName, $extImgTarget = '') if (empty($extImgTarget)) $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : ''); if (empty($extImgTarget)) $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : ''); if (empty($extImgTarget)) $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : ''); + if (empty($extImgTarget)) $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : ''); if (!$extImgTarget) return $file; @@ -8088,7 +8089,7 @@ function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param if (empty($conf->use_javascript_ajax)) return ''; - $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'svg+xml'); + $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'svg+xml', 'webp'); //$mime_preview[]='vnd.oasis.opendocument.presentation'; //$mime_preview[]='archive'; $num_mime = array_search(dol_mimetype($relativepath, '', 1), $mime_preview); @@ -8199,6 +8200,7 @@ function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0) if (preg_match('/\.bmp$/i', $tmpfile)) { $mime = 'image/bmp'; $imgmime = 'image.png'; $famime = 'file-image-o'; } if (preg_match('/\.(tif|tiff)$/i', $tmpfile)) { $mime = 'image/tiff'; $imgmime = 'image.png'; $famime = 'file-image-o'; } if (preg_match('/\.svg$/i', $tmpfile)) { $mime = 'image/svg+xml'; $imgmime = 'image.png'; $famime = 'file-image-o'; } + if (preg_match('/\.webp$/i', $tmpfile)) { $mime = 'image/webp'; $imgmime = 'image.png'; $famime = 'file-image-o'; } // Calendar if (preg_match('/\.vcs$/i', $tmpfile)) { $mime = 'text/calendar'; $imgmime = 'other.png'; $famime = 'file-text-o'; } if (preg_match('/\.ics$/i', $tmpfile)) { $mime = 'text/calendar'; $imgmime = 'other.png'; $famime = 'file-text-o'; } diff --git a/htdocs/core/lib/images.lib.php b/htdocs/core/lib/images.lib.php index 4f65ca3a2bf..b65ad51db86 100644 --- a/htdocs/core/lib/images.lib.php +++ b/htdocs/core/lib/images.lib.php @@ -37,7 +37,7 @@ $quality = 80; */ function image_format_supported($file) { - $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.xpm|\.xbm|\.svg'; // See also into product.class.php + $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm|\.svg'; // See also into product.class.php // Case filename is not a format image $reg = array(); @@ -46,10 +46,11 @@ function image_format_supported($file) // Case filename is a format image but not supported by this PHP $imgfonction = ''; if (strtolower($reg[1]) == '.gif') $imgfonction = 'imagecreatefromgif'; - if (strtolower($reg[1]) == '.png') $imgfonction = 'imagecreatefrompng'; if (strtolower($reg[1]) == '.jpg') $imgfonction = 'imagecreatefromjpeg'; if (strtolower($reg[1]) == '.jpeg') $imgfonction = 'imagecreatefromjpeg'; + if (strtolower($reg[1]) == '.png') $imgfonction = 'imagecreatefrompng'; if (strtolower($reg[1]) == '.bmp') $imgfonction = 'imagecreatefromwbmp'; + if (strtolower($reg[1]) == '.webp') $imgfonction = 'imagecreatefromwebp'; if (strtolower($reg[1]) == '.xpm') $imgfonction = 'imagecreatefromxpm'; if (strtolower($reg[1]) == '.xbm') $imgfonction = 'imagecreatefromxbm'; if (strtolower($reg[1]) == '.svg') $imgfonction = 'imagecreatefromsvg'; // Never available @@ -60,10 +61,12 @@ function image_format_supported($file) // Fonctions of conversion not available in this PHP return 0; } + + // Filename is a format image and supported for conversion by this PHP + return 1; } - // Filename is a format image and supported for conversion by this PHP - return 1; + return 0; } @@ -180,6 +183,9 @@ function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, case 4: // IMG_WBMP $imgfonction = 'imagecreatefromwbmp'; break; + case 17: // IMG_WBMP + $imgfonction = 'imagecreatefromwebp'; + break; } if ($imgfonction) { @@ -213,6 +219,11 @@ function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, $extImg = '.bmp'; $newquality = 'NU'; // Quality is not used for this format break; + case 18: // Webp + $img = imagecreatefromwebp($filetoread); + $extImg = '.webp'; + $newquality = '100'; // % quality maximum + break; } // Create empty image @@ -255,6 +266,9 @@ function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, case 4: // Bmp $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 0); break; + case 18: // Webp + $trans_colour = imagecolorallocatealpha($imgThumb, 255, 255, 255, 127); + break; } if (function_exists("imagefill")) imagefill($imgThumb, 0, 0, $trans_colour); @@ -283,6 +297,9 @@ function dol_imageResizeOrCrop($file, $mode, $newWidth, $newHeight, $src_x = 0, case 4: // Bmp imagewbmp($imgThumb, $imgThumbName); break; + case 18: // Webp + imagewebp($imgThumb, $imgThumbName, $newquality); + break; } // Set permissions on file diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 7b6892552d1..d557dd90392 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -79,7 +79,7 @@ class Product extends CommonObject */ protected $table_ref_field = 'ref'; - public $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.xpm|\.xbm'; // See also into images.lib.php + public $regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm'; // See also into images.lib.php /* * @deprecated From f1b791d5e0e92b364dfeaab7b0dba5300712d9a0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 3 Jun 2020 14:05:55 +0200 Subject: [PATCH 5/5] Doc --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 7e8ce042bf3..c4bc005a94d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ NEW: Accountancy - Add mode intra & export for product or service bought NEW: Accountancy - Add possibility to manage a short alternative label for account - Use to simplify accountancy NEW: Accountancy - General ledger - Add an option to search not reconciled lines NEW: Add accountancy code of thirdparty in contact and supplier export +NEW: support webp image format NEW: add a link to notes in members list NEW: add a parameter to group same products in TakePOS NEW: add a parameter to sort product by label in TakePOS