diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index 9dbdf1b5ee4..e7d330324dd 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -36,11 +36,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - - name: Setup MariaDB - uses: ankane/setup-mariadb@v1 - with: - # mariadb-version: ${{ matrix.mariadb-version }} - database: travis # Specify your database name - name: Setup PHP uses: shivammathur/setup-php@v2 with: @@ -70,6 +65,7 @@ jobs: path: | ./db_init.sql ./db_init.sql.md5 + ./.cache/mariadb key: ${{ env.KEY_ROOT }}-${{ env.HASH }}-${{ env.CACHE_KEY_PART }}-${{ github.run_id }} restore-keys: | ${{ env.KEY_ROOT }}-${{ env.HASH }}-${{ env.CACHE_KEY_PART }}- @@ -78,6 +74,12 @@ jobs: ${{ env.KEY_ROOT }}-${{ env.HASH }}- ${{ env.KEY_ROOT }}- + - name: Setup MariaDB + uses: frederic34/setup-mariadb@v1 + with: + # mariadb-version: ${{ matrix.mariadb-version }} + database: travis # Specify your database name + - name: Create local php.ini with open_basedir restrictions shell: cmd # Objective: separate step, and before database initialisation to verify open_basedir restrictions @@ -189,3 +191,4 @@ jobs: path: | ./db_init.sql ./db_init.sql.md5 + ./.cache/mariadb diff --git a/ChangeLog b/ChangeLog index 6f2c15dfe29..ee320d33ba3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,56 @@ English Dolibarr ChangeLog -------------------------------------------------------------- +***** ChangeLog for 20.0.1 compared to 20.0.0 ***** + +FIX: #30960 show and search extrafields (#31026) +FIX: #31076 Bad position of hooks +FIX: #31152 +FIX: #31237 (#31239) +FIX: #31241 (#31245) +FIX: accounting transfer when nb of lines is not zero but amount is zero +FIX: Add same security test when nuploading files from API than from GUI (#31114) +FIX: allow "class" into search string in website module +FIX: autoselect the fiscal period by default +FIX: avoid odt errors (#31126) +FIX: Backport fix fatal error on price with some truncating setup +FIX: better compatibility with some old extrafield syntax filter +FIX: box_actions.php still uses fk_user_done which no longer exists (#31190) +FIX: Browser Notification ko with firefox +FIX: custom CSS for WebPortal (#31022) +FIX: Debug calculation of the delay of purchase order +FIX: Debug option WORKFLOW_TICKET_LINK_CONTRACT. Bad id stored. Bad +FIX: dolFICalculatePaymentReference for Finland in functions_fi.lib.php (#31281) +FIX: Duplicate trigger printFieldPreListTitle +FIX: edit contract of intervention broken by CSRF protection +FIX: error return missing in mo creation when qty to consume is <= 0 (#31134) +FIX: Extrafields does not appear on form +FIX: FATAL ERROR abusively triggered due to incomplete regex (#31052) +FIX: if you call fetchLines several times, your $object->lines contains duplicates (#31167) +FIX: late order search option (v18+) (#30692) +FIX: late propal search option (v18+) (#30687) +FIX: Maxi debug edit/delete accounting transaction +FIX: member must be found to search the linked partnership (WebPortal) (#30977) +FIX: Missing picto on user link +FIX: mysql error during dump for enable sandbox M999999 (#31116) +FIX: OAuth generation of token for Microsoft, Stripe and Generic +FIX: param id in website account list from third-party card (#30975) +FIX: Position of box for shipping address in PDF +FIX: Protection to avoid an extrafield to be mandatory if computed +FIX: removed unreachable code (#31141) +FIX: Remove wrong button +FIX: retrieving user specific constant +FIX: Revert storing of ticket files into event dir, too many troubles. +FIX: Selection of country - state in resource +FIX: State dropdown is not working on User card #31198 (#31205) +FIX: Tool to convert into utf8 or utf8mb4 +FIX: use price() to display qty on a product's stats tab to avoid showing too many decimals when rounding errors are possible (#31165) +FIX: Warning visible when it should not +FIX: webhook must send POST in body. Add WEBHOOK_POST_SEND_DATA_IN_BODY +FIX: when qty is not an integer, apply price() (#31138) +FIX: Wrong price for BOM with workstation (#31142) +FIX: determine multi-currency price on object line create tpl (#28021) + ***** ChangeLog for 20.0.0 compared to 19.0 ***** diff --git a/htdocs/accountancy/admin/fiscalyear_card.php b/htdocs/accountancy/admin/fiscalyear_card.php index 3d7cd6b0185..1e5b91224d9 100644 --- a/htdocs/accountancy/admin/fiscalyear_card.php +++ b/htdocs/accountancy/admin/fiscalyear_card.php @@ -94,7 +94,7 @@ if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); } -if ($action == 'confirm_delete' && $confirm == "yes") { +if ($action == 'confirm_delete' && $confirm == "yes" && $permissiontoadd) { $result = $object->delete($user); if ($result >= 0) { header("Location: fiscalyear.php"); @@ -102,7 +102,7 @@ if ($action == 'confirm_delete' && $confirm == "yes") { } else { setEventMessages($object->error, $object->errors, 'errors'); } -} elseif ($action == 'add') { +} elseif ($action == 'add' && $permissiontoadd) { if (!GETPOST('cancel', 'alpha')) { $error = 0; @@ -144,7 +144,7 @@ if ($action == 'confirm_delete' && $confirm == "yes") { header("Location: ./fiscalyear.php"); exit(); } -} elseif ($action == 'update') { +} elseif ($action == 'update' && $permissiontoadd) { // Update record if (!GETPOST('cancel', 'alpha')) { $result = $object->fetch($id); @@ -166,8 +166,19 @@ if ($action == 'confirm_delete' && $confirm == "yes") { header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id); exit(); } -} +} elseif ($action == 'reopen' && $permissiontoadd && getDolGlobalString('ACCOUNTING_CAN_REOPEN_CLOSED_PERIOD')) { + $result = $object->fetch($id); + $object->status = GETPOSTINT('status'); + $result = $object->update($user); + + if ($result > 0) { + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id); + exit(); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } +} /* @@ -364,6 +375,10 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea if ($user->hasRight('accounting', 'fiscalyear', 'write')) { print '
'; + if (getDolGlobalString('ACCOUNTING_CAN_REOPEN_CLOSED_PERIOD') && $object->status == $object::STATUS_CLOSED) { + print dolGetButtonAction($langs->trans("ReOpen"), '', 'reopen', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=reopen&token='.newToken(), 'reopen', $permissiontoadd); + } + print ''.$langs->trans('Modify').''; //print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken(), 'delete', $permissiontodelete); diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 1e4afa2d45f..66bd62cce11 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -2533,7 +2533,7 @@ class BookKeeping extends CommonObject } /** - * Get list of fiscal period + * Get list of fiscal period ordered by start date. * * @param string $filter Filter * @return array|int Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...] diff --git a/htdocs/accountancy/closure/index.php b/htdocs/accountancy/closure/index.php index 43f9179c599..262282f033e 100644 --- a/htdocs/accountancy/closure/index.php +++ b/htdocs/accountancy/closure/index.php @@ -60,33 +60,57 @@ if (!is_array($fiscal_periods)) { setEventMessages($object->error, $object->errors, 'errors'); } +// Define the arrays of fiscal periods $active_fiscal_periods = array(); +$first_active_fiscal_period = null; $last_fiscal_period = null; $current_fiscal_period = null; $next_fiscal_period = null; $next_active_fiscal_period = null; if (is_array($fiscal_periods)) { - foreach ($fiscal_periods as $fiscal_period) { - if (empty($fiscal_period['status'])) { + foreach ($fiscal_periods as $fiscal_period) { // List of fiscal periods sorted by date start + if (empty($first_active_fiscal_period) && empty($fiscal_period['status'])) { + $first_active_fiscal_period = $fiscal_period; + } + if (empty($fiscal_period['status'])) { // if not closed $active_fiscal_periods[] = $fiscal_period; } - if (isset($current_fiscal_period)) { + if (isset($current_fiscal_period)) { // If we already reach then current fiscal period, then this one is the next one just after if (!isset($next_fiscal_period)) { $next_fiscal_period = $fiscal_period; } if (!isset($next_active_fiscal_period) && empty($fiscal_period['status'])) { $next_active_fiscal_period = $fiscal_period; } - } else { + } else { // If we did not found the current fiscal period if ($fiscal_period_id == $fiscal_period['id'] || (empty($fiscal_period_id) && $fiscal_period['date_start'] <= $now && $now <= $fiscal_period['date_end'])) { $current_fiscal_period = $fiscal_period; } else { - $last_fiscal_period = $fiscal_period; + $last_fiscal_period = $fiscal_period; // $last_fiscal_period is in fact $previous_fiscal_period } } } } +// If a current fiscal period open with an end and start date was not found, we autoselect the first one that is open and has a start and end date defined +if (empty($current_fiscal_period) && !empty($first_active_fiscal_period)) { + $current_fiscal_period = $first_active_fiscal_period; + $last_fiscal_period = null; + $foundcurrent = false; + foreach ($fiscal_periods as $fiscal_period) { // List of fiscal periods sorted by date start + if ($foundcurrent) { + $next_fiscal_period = $fiscal_period; + break; + } + if ($fiscal_period['id'] == $current_fiscal_period['id']) { + $foundcurrent = true; + } + if (!$foundcurrent) { + $last_fiscal_period = $fiscal_period; + } + } +} + $accounting_groups_used_for_balance_sheet_account = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT'))), 'strlen'); $accounting_groups_used_for_income_statement = array_filter(array_map('trim', explode(',', getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT'))), 'strlen'); @@ -127,11 +151,10 @@ if (empty($reshook)) { if ($generate_bookkeeping_records) { if (!getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_BALANCE_SHEET_ACCOUNT')) { $error++; - setEventMessages($langs->trans("ErrorModuleSetupNotComplete"), null, 'errors'); - } - if (!getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) { + setEventMessages($langs->trans("ErrorAccountingClosureSetupNotComplete"), null, 'errors'); + } elseif (!getDolGlobalString('ACCOUNTING_CLOSURE_ACCOUNTING_GROUPS_USED_FOR_INCOME_STATEMENT')) { $error++; - setEventMessages($langs->trans("ErrorModuleSetupNotComplete"), null, 'errors'); + setEventMessages($langs->trans("ErrorAccountingClosureSetupNotComplete"), null, 'errors'); } } @@ -315,9 +338,7 @@ print load_fiche_titre($langs->trans("Closure") . " - " . $fiscal_period_nav_tex if (empty($current_fiscal_period)) { print $langs->trans('ErrorNoFiscalPeriodActiveFound', $langs->transnoentitiesnoconv("Accounting"), $langs->transnoentitiesnoconv("Setup"), $langs->transnoentitiesnoconv("FiscalPeriod")); -} - -if (isset($current_fiscal_period)) { +} else { // Step 1 $head = array(); $head[0][0] = DOL_URL_ROOT . '/accountancy/closure/index.php?fiscal_period_id=' . $current_fiscal_period['id']; @@ -383,7 +404,7 @@ if (isset($current_fiscal_period)) { if (empty($count_by_month['total']) && empty($current_fiscal_period['status'])) { $button = '' . $langs->trans("AccountancyClosureClose") . ''; } else { - $button = '' . $langs->trans("AccountancyClosureClose") . ''; + $button = '' . $langs->trans("AccountancyClosureClose") . ''; } print_barre_liste('', '', '', '', '', '', '', -1, '', '', 0, $button, '', 0, 1, 0); diff --git a/htdocs/admin/accountant.php b/htdocs/admin/accountant.php index 0498ae77302..305a58254eb 100644 --- a/htdocs/admin/accountant.php +++ b/htdocs/admin/accountant.php @@ -105,6 +105,7 @@ if (!empty($conf->use_javascript_ajax)) { print "\n".''."\n"; + } + + // Create/Edit object - print '
'; + print ''; print ''; print ''; @@ -249,56 +262,10 @@ if ($action == 'create' || $object->fetch($id, $ref) > 0) { print ''.$langs->trans("ResourceFormLabel_ref").''; print ''; - // Address - print ''.$form->editfieldkey('Address', 'address', '', $object, 0).''; - print ''; - print $form->widgetForTranslation("address", $object, $permissiontoadd, 'textarea', 'alphanohtml', 'quatrevingtpercent'); - print ''; - - // Zip - print ''.$form->editfieldkey('Zip', 'zipcode', '', $object, 0).''; - print $formresource->select_ziptown($object->zip, 'zipcode', array('town', 'selectcountry_id', 'state_id'), 0, 0, '', 'maxwidth100'); - print ''; - print ''; - - // Town - print ''; - print ''.$form->editfieldkey('Town', 'town', '', $object, 0).''; - print $formresource->select_ziptown($object->town, 'town', array('zipcode', 'selectcountry_id', 'state_id')); - print $form->widgetForTranslation("town", $object, $permissiontoadd, 'string', 'alphanohtml', 'maxwidth100 quatrevingtpercent'); - print ''; - - // Origin country - print ''.$langs->trans("CountryOrigin").''; - print $form->select_country($object->country_id); - if ($user->admin) { - print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); - } - print ''; - - // State - if (!getDolGlobalString('SOCIETE_DISABLE_STATE')) { - if ((getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) { - print ''.$form->editfieldkey('Region-State', 'state_id', '', $object, 0).''; - } else { - print ''.$form->editfieldkey('State', 'state_id', '', $object, 0).''; - } - - if ($object->country_id) { - print img_picto('', 'state', 'class="pictofixedwidth"'); - print $formresource->select_state($object->state_id, $object->country_code); - } else { - print $langs->trans("ErrorSetACountryFirst").' ('.$langs->trans("SeeAbove").')'; - } - print ''; - } - // Type print ''.$langs->trans("ResourceType").''; print ''; - $formresource->select_types_resource($object->fk_code_type_resource, 'fk_code_type_resource', '', 2); + $formresource->select_types_resource($object->fk_code_type_resource, 'fk_code_type_resource', '', 2, 0, 0, 0, 1, 'minwidth200'); print ''; // Description @@ -309,6 +276,53 @@ if ($action == 'create' || $object->fetch($id, $ref) > 0) { $doleditor->Create(); print ''; + // Address + print ''.$form->editfieldkey('Address', 'address', '', $object, 0).''; + print ''; + print $form->widgetForTranslation("address", $object, $permissiontoadd, 'textarea', 'alphanohtml', 'quatrevingtpercent'); + print ''; + + // Zip + print ''.$form->editfieldkey('Zip', 'zipcode', '', $object, 0).''; + print $formresource->select_ziptown(GETPOSTISSET('zipcode') ? GETPOST('zipcode') : $object->zip, 'zipcode', array('town', 'selectcountry_id', 'state_id'), 0, 0, '', 'maxwidth100'); + print ''; + print ''; + + // Town + print ''; + print ''.$form->editfieldkey('Town', 'town', '', $object, 0).''; + print $formresource->select_ziptown(GETPOSTISSET('town') ? GETPOST('town') : $object->town, 'town', array('zipcode', 'selectcountry_id', 'state_id')); + print $form->widgetForTranslation("town", $object, $permissiontoadd, 'string', 'alphanohtml', 'maxwidth100 quatrevingtpercent'); + print ''; + + // Origin country + print ''.$langs->trans("CountryOrigin").''; + print $form->select_country(GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : $object->country_id, 'country_id'); + if ($user->admin) { + print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); + } + print ''; + + // State + $countryid = GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : $object->country_id; + if (!getDolGlobalString('SOCIETE_DISABLE_STATE') && $countryid > 0) { + if ((getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) { + print ''.$form->editfieldkey('Region-State', 'state_id', '', $object, 0).''; + } else { + print ''.$form->editfieldkey('State', 'state_id', '', $object, 0).''; + } + + if ($country_id > 0) { + print img_picto('', 'state', 'class="pictofixedwidth"'); + print $formresource->select_state($countryid, $country_id); + } else { + print ''.$langs->trans("ErrorSetACountryFirst").' ('.$langs->trans("SeeAbove").')'; + } + print ''; + } + // Phone print ''.$form->editfieldkey('Phone', 'phone', '', $object, 0).''; print ''; @@ -327,7 +341,7 @@ if ($action == 'create' || $object->fetch($id, $ref) > 0) { print ''.$form->editfieldkey('MaxUsers', 'max_users', '', $object, 0).''; print ''; print img_picto('', 'object_user', 'class="pictofixedwidth"'); - print ''; + print ''; print ''; // URL diff --git a/htdocs/resource/class/dolresource.class.php b/htdocs/resource/class/dolresource.class.php index cb106b7afeb..14578eecf8f 100644 --- a/htdocs/resource/class/dolresource.class.php +++ b/htdocs/resource/class/dolresource.class.php @@ -51,17 +51,17 @@ class Dolresource extends CommonObject public $picto = 'resource'; /** - * @var string description + * @var string Description */ public $description; /** - * @var string telephone number + * @var string Phone number */ public $phone; /** - * @var int Maximum users + * @var int|null Maximum users */ public $max_users; @@ -375,9 +375,6 @@ class Dolresource extends CommonObject if (isset($this->email)) { $this->email = trim($this->email); } - if (!is_numeric($this->max_users)) { - $this->max_users = 0; - } if (isset($this->url)) { $this->url = trim($this->url); } diff --git a/htdocs/resource/class/html.formresource.class.php b/htdocs/resource/class/html.formresource.class.php index 5471287c9f7..5edb677e850 100644 --- a/htdocs/resource/class/html.formresource.class.php +++ b/htdocs/resource/class/html.formresource.class.php @@ -174,9 +174,11 @@ class FormResource * @param int $empty 1=peut etre vide, 0 sinon * @param int $noadmininfo 0=Add admin info, 1=Disable admin info * @param int $maxlength Max length of label + * @param int $usejscombo 1=Use jscombo, 0=No js combo + * @param string $morecss Add more css * @return void */ - public function select_types_resource($selected = '', $htmlname = 'type_resource', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0) + public function select_types_resource($selected = '', $htmlname = 'type_resource', $filtertype = '', $format = 0, $empty = 0, $noadmininfo = 0, $maxlength = 0, $usejscombo = 0, $morecss = 'minwidth100') { // phpcs:enable global $langs, $user; @@ -192,7 +194,7 @@ class FormResource } $resourcestat->loadCacheCodeTypeResource(); - print ''; if ($empty) { print ''; } @@ -236,6 +238,10 @@ class FormResource } } print ''; + if ($usejscombo) { + print ajax_combobox("select".$htmlname); + } + if ($user->admin && !$noadmininfo) { print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); } diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index 783258014f7..53842b8b2d8 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -1193,6 +1193,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio } $("#selectcountry_id").change(function() { + console.log("selectcountry_id change"); document.formsoc.action.value="create"; document.formsoc.submit(); }); @@ -1202,7 +1203,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio dol_htmloutput_mesg(is_numeric($error) ? '' : $error, $errors, 'error'); - print ''; // Chrome ignor autocomplete + print ''; // Chrome ignores autocomplete print ''; print ''; @@ -2036,6 +2037,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayactio } $("#selectcountry_id").change(function() { + console.log("selectcountry_id change"); document.formsoc.action.value="edit"; document.formsoc.submit(); }); diff --git a/htdocs/societe/class/api_contacts.class.php b/htdocs/societe/class/api_contacts.class.php index 95e7de8d649..3499bf09b92 100644 --- a/htdocs/societe/class/api_contacts.class.php +++ b/htdocs/societe/class/api_contacts.class.php @@ -369,7 +369,7 @@ class Contacts extends DolibarrApi * Delete contact * * @param int $id Contact ID - * @return integer + * @return array[] */ public function delete($id) { @@ -385,7 +385,17 @@ class Contacts extends DolibarrApi throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } $this->contact->oldcopy = clone $this->contact; - return $this->contact->delete(DolibarrApiAccess::$user); + + if ($this->contact->delete(DolibarrApiAccess::$user) <= 0) { + throw new RestException(500, 'Error when delete contact ' . $this->contact->error); + } + + return array( + 'success' => array( + 'code' => 200, + 'message' => 'Contact deleted' + ) + ); } /** diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index a5748873d77..eb49f75e8da 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2118,7 +2118,7 @@ class Societe extends CommonObject * @param string $ref_alias Name_alias of third party (Warning, this can return several records) * @param int $is_client Only client third party * @param int $is_supplier Only supplier third party - * @return int >0 if OK, <0 if KO or if two records found, 0 if not found. + * @return int ID of thirdparty found if OK, <0 if KO or if two records found, 0 if not found. */ public function findNearest($rowid = 0, $ref = '', $ref_ext = '', $barcode = '', $idprof1 = '', $idprof2 = '', $idprof3 = '', $idprof4 = '', $idprof5 = '', $idprof6 = '', $email = '', $ref_alias = '', $is_client = 0, $is_supplier = 0) { diff --git a/htdocs/theme/eldy/dropdown.inc.php b/htdocs/theme/eldy/dropdown.inc.php index b59787308ed..cef22be8f12 100644 --- a/htdocs/theme/eldy/dropdown.inc.php +++ b/htdocs/theme/eldy/dropdown.inc.php @@ -362,7 +362,7 @@ a.dropdown-item { display: block !important; box-sizing: border-box; width: 100%; - padding: .3em 1.5em .4em 1em; + padding: .5em 1.5em .5em 1em; clear: both; font-weight: 400; color: #212529 !important; diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 3755aa1f2eb..5dd886ecb78 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -3503,10 +3503,10 @@ img.login, img.printer, img.entity { } .userimg.atoplogin img.userphoto, .userimgatoplogin img.userphoto { /* size for user photo in login bar */ /* border-radius: 8px; */ - width: 20px; - height: 20px; + width: px; + height: px; + border-radius: 50%; background-size: contain; - vertical-align: text-bottom; background-color: #FFF; } img.userphoto { /* size for user photo in lists */ diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index 4196a85326d..219feb82a0f 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -1711,6 +1711,8 @@ class Ticket extends CommonObject $this->db->begin(); + $this->status = Ticket::STATUS_READ; + $sql = "UPDATE ".MAIN_DB_PREFIX."ticket"; $sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'"; $sql .= " WHERE rowid = ".((int) $this->id); @@ -1721,7 +1723,7 @@ class Ticket extends CommonObject $this->context['actionmsg'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs)); $this->context['actionmsg2'] = $langs->trans('TicketLogMesgReadBy', $this->ref, $user->getFullName($langs)); - if (!$error && !$notrigger) { + if (!$notrigger) { // Call trigger $result = $this->call_trigger('TICKET_MODIFY', $user); if ($result < 0) { @@ -1734,12 +1736,16 @@ class Ticket extends CommonObject $this->db->commit(); return 1; } else { + $this->status = $this->oldcopy->status; + $this->db->rollback(); $this->error = implode(',', $this->errors); dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR); return -1; } } else { + $this->status = $this->oldcopy->status; + $this->db->rollback(); $this->error = $this->db->lasterror(); dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR); @@ -1894,26 +1900,37 @@ class Ticket extends CommonObject if ($actionid > 0) { if (is_array($attachedfiles) && array_key_exists('paths', $attachedfiles) && count($attachedfiles['paths']) > 0) { + // If there is some files, we must now link them to the event, so we can show them per event. foreach ($attachedfiles['paths'] as $key => $filespath) { - $destdir = $conf->agenda->dir_output.'/'.$actionid; - $destfile = $destdir.'/'.$attachedfiles['names'][$key]; - if (dol_mkdir($destdir) >= 0) { + // Disabled the move into another directory, Files for a ticket should be stored into ticket directory. It generates too much troubles. + $destdir = $conf->ticket->dir_output.'/'.$this->ref; + //$destfile = $destdir.'/'.$attachedfiles['names'][$key]; + //if (dol_mkdir($destdir) >= 0) { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - dol_move($filespath, $destfile); - if (in_array($actioncomm->code, array('TICKET_MSG', 'TICKET_MSG_SENTBYMAIL'))) { - $ecmfile = new EcmFiles($this->db); - $destdir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destdir); - $destdir = preg_replace('/[\\/]$/', '', $destdir); - $destdir = preg_replace('/^[\\/]/', '', $destdir); - $ecmfile->fetch(0, '', $destdir.'/'.$attachedfiles['names'][$key]); - require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; - $ecmfile->share = getRandomPassword(true); + //dol_move($filespath, $destfile); // Disabled, a file for a ticket should be stored into ticket directory. It generates big trouble. + if (in_array($actioncomm->code, array('TICKET_MSG', 'TICKET_MSG_SENTBYMAIL'))) { + $ecmfile = new EcmFiles($this->db); + $destdir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destdir); + $destdir = preg_replace('/[\\/]$/', '', $destdir); + $destdir = preg_replace('/^[\\/]/', '', $destdir); + + $result = $ecmfile->fetch(0, '', $destdir.'/'.$attachedfiles['names'][$key]); + + // TODO We must add a column into ecm_files table agenda_id to store the ID of event. + // $ecmfile->agenda_id = $actionid; + + // Disabled, serious security hole. A file published into the ERP should not become public for everybody. + //require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + //$ecmfile->share = getRandomPassword(true); + + if ($result > 0) { $result = $ecmfile->update($user); if ($result < 0) { setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); } } } + //} } } } @@ -2573,7 +2590,9 @@ class Ticket extends CommonObject } $moreinfo = array('description' => 'File saved by copyFilesForTicket', 'src_object_type' => $this->element, 'src_object_id' => $this->id); + $res = dol_move($filepath[$i], $destfile, 0, 1, 0, 1, $moreinfo); + if (!$res) { // Move has failed $this->error = "Failed to move file ".dirbasename($filepath[$i])." into ".dirbasename($destfile); diff --git a/htdocs/ticket/document.php b/htdocs/ticket/document.php index ffecc4e9197..b6e107e6588 100644 --- a/htdocs/ticket/document.php +++ b/htdocs/ticket/document.php @@ -211,7 +211,9 @@ if ($object->id) { // Build file list $filearray = dol_dir_list($upload_dir, "files", 0, '', '\.meta$', $sortfield, (strtolower($sortorder) == 'desc' ? SORT_DESC : SORT_ASC), 1); + // same as above for every messages + /* disabled. Too many bugs. All file of a ticket must be stored into ticket. File must be linked to an event by column agenda_id into llx_ecmfiles. $sql = 'SELECT id FROM '.MAIN_DB_PREFIX.'actioncomm'; $sql .= " WHERE fk_element = ".(int) $object->id." AND elementtype = 'ticket'"; $resql = $db->query($sql); @@ -229,6 +231,7 @@ if ($object->id) { $filearray = array_merge($filearray, $file_msg_array); } } + */ $totalsize = 0; foreach ($filearray as $key => $file) { diff --git a/htdocs/ticket/tpl/linkedobjectblock.tpl.php b/htdocs/ticket/tpl/linkedobjectblock.tpl.php index e70395eb79b..902c00ae5a0 100644 --- a/htdocs/ticket/tpl/linkedobjectblock.tpl.php +++ b/htdocs/ticket/tpl/linkedobjectblock.tpl.php @@ -47,7 +47,7 @@ foreach ($linkedObjectBlock as $key => $objectlink) { trans("Ticket"); ?> getNomUrl(0, '', 0, 1).'&action=selectlines" data-element="'.$objectlink->element.'" data-id="'.$objectlink->id.'" > getNomUrl(1); ?>