diff --git a/SECURITY.md b/SECURITY.md index a48cefa33f1..aacbeb1faf9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -110,8 +110,7 @@ Scope is the web application (backoffice) and the APIs. * Software or libraries versions, private IP disclosure, Stack traces or path disclosure when logged-in user is admin. * Vulnerabilities affecting outdated browsers or platforms, or vulnerabilities inside browsers themself. * Brute force attacks on login page, password forgotten page or any public pages (/public/*) are not qualified if the recommended fail2ban rules were not installed. -* SSL/TLS best practices +* SSL/TLS practices (cypher enabled or not) * Invalid or missing SPF (Sender Policy Framework) records (Incomplete or missing SPF/DKIM/DMARC) * Physical or social engineering attempts or issues that require physical access to a victim’s computer/device -* Vulnerabilities of type XSS exploited by using javascript into a website page (with permission to edit website pages) or by using php code into a website page - using the permission to edit php code are not qualified, except if this allow to get higher privileges (being able to set javascript or php code is the expected behaviour). +* Vulnerabilities of type XSS exploited by using javascript into a website page of the website module or by using php code into a website page (being able to set javascript or php code is the expected behaviour in the website module), except if the user does not have the permission to edit page or php code. diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index 1bd90fa4fbb..ea8caf60a69 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -54,12 +54,6 @@ parameters: count: 1 path: ../../../htdocs/accountancy/admin/categories_list.php - - - message: '#^Parameter \#12 \$tabcomplete of function complete_dictionary_with_modules expects array\\>\>, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/accountancy/admin/categories_list.php - - message: '#^Right side of && is always true\.$#' identifier: booleanAnd.rightAlwaysTrue @@ -102,12 +96,6 @@ parameters: count: 1 path: ../../../htdocs/accountancy/admin/journals_list.php - - - message: '#^Parameter \#12 \$tabcomplete of function complete_dictionary_with_modules expects array\\>\>, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/accountancy/admin/journals_list.php - - message: '#^Ternary operator condition is always true\.$#' identifier: ternary.alwaysTrue @@ -144,12 +132,6 @@ parameters: count: 1 path: ../../../htdocs/accountancy/admin/report_list.php - - - message: '#^Parameter \#12 \$tabcomplete of function complete_dictionary_with_modules expects array\\>\>, array\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/accountancy/admin/report_list.php - - message: '#^Ternary operator condition is always true\.$#' identifier: ternary.alwaysTrue @@ -1164,12 +1146,6 @@ parameters: count: 1 path: ../../../htdocs/admin/dict.php - - - message: '#^Parameter \#12 \$tabcomplete of function complete_dictionary_with_modules expects array\\>\>, array\\|string\>\> given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/admin/dict.php - - message: '#^Variable \$param in empty\(\) always exists and is not falsy\.$#' identifier: empty.variable @@ -3402,12 +3378,6 @@ parameters: count: 2 path: ../../../htdocs/bookmarks/bookmarks.lib.php - - - message: '#^Ternary operator condition is always false\.$#' - identifier: ternary.alwaysFalse - count: 1 - path: ../../../htdocs/bookmarks/bookmarks.lib.php - - message: '#^Variable \$contextpage in empty\(\) always exists and is not falsy\.$#' identifier: empty.variable @@ -3486,24 +3456,12 @@ parameters: count: 1 path: ../../../htdocs/categories/class/api_categories.class.php - - - message: '#^Left side of && is always true\.$#' - identifier: booleanAnd.leftAlwaysTrue - count: 1 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^Method Categorie\:\:get_full_arbo\(\) should return \-1\|array\ but returns array\\.$#' identifier: return.type count: 1 path: ../../../htdocs/categories/class/categorie.class.php - - - message: '#^Negated boolean expression is always true\.$#' - identifier: booleanNot.alwaysTrue - count: 3 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^Parameter \#1 \$array of function dol_sort_array contains unresolvable type\.$#' identifier: argument.unresolvableType @@ -3522,12 +3480,6 @@ parameters: count: 1 path: ../../../htdocs/categories/class/categorie.class.php - - - message: '#^Variable \$url in empty\(\) always exists and is not falsy\.$#' - identifier: empty.variable - count: 2 - path: ../../../htdocs/categories/class/categorie.class.php - - message: '#^If condition is always true\.$#' identifier: if.alwaysTrue @@ -8142,12 +8094,6 @@ parameters: count: 3 path: ../../../htdocs/core/actions_massactions.inc.php - - - message: '#^Variable \$permissiontoadd might not be defined\.$#' - identifier: variable.undefined - count: 10 - path: ../../../htdocs/core/actions_massactions.inc.php - - message: '#^Variable \$search_status might not be defined\.$#' identifier: variable.undefined @@ -19926,12 +19872,6 @@ parameters: count: 1 path: ../../../htdocs/master.inc.php - - - message: '#^Call to function is_array\(\) with array\ will always evaluate to true\.$#' - identifier: function.alreadyNarrowedType - count: 1 - path: ../../../htdocs/modulebuilder/index.php - - message: '#^Call to function is_array\(\) with non\-empty\-array\ will always evaluate to true\.$#' identifier: function.alreadyNarrowedType @@ -19944,12 +19884,6 @@ parameters: count: 2 path: ../../../htdocs/modulebuilder/index.php - - - message: '#^Parameter \#2 \$arrayreplacement of function dolReplaceInFile expects array\, array\\|string\> given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/modulebuilder/index.php - - message: '#^Right side of && is always true\.$#' identifier: booleanAnd.rightAlwaysTrue @@ -26661,7 +26595,7 @@ parameters: - message: '#^Variable \$prodcustprice might not be defined\.$#' identifier: variable.undefined - count: 36 + count: 3 path: ../../../htdocs/societe/price.php - @@ -27198,36 +27132,12 @@ parameters: count: 1 path: ../../../htdocs/theme/eldy/style.css.php - - - message: '#^Variable \$fontlist might not be defined\.$#' - identifier: variable.undefined - count: 4 - path: ../../../htdocs/theme/md/btn.inc.php - - - - message: '#^Variable \$left might not be defined\.$#' - identifier: variable.undefined - count: 2 - path: ../../../htdocs/theme/md/btn.inc.php - - message: '#^Variable \$nbtopmenuentries might not be defined\.$#' identifier: variable.undefined count: 2 path: ../../../htdocs/theme/md/btn.inc.php - - - message: '#^Variable \$right might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/theme/md/btn.inc.php - - - - message: '#^Variable \$user might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/theme/md/btn.inc.php - - message: '#^Variable \$left might not be defined\.$#' identifier: variable.undefined @@ -28362,12 +28272,6 @@ parameters: count: 8 path: ../../../htdocs/webportal/class/html.formwebportal.class.php - - - message: '#^Parameter \#3 \$preselectedvalue of method FormWebPortal\:\:selectForForms\(\) expects int, array\\|string given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/webportal/class/html.formwebportal.class.php - - message: '#^Call to function method_exists\(\) with \$this\(WebPortalInvoice\) and ''getLibStatut'' will always evaluate to true\.$#' identifier: function.alreadyNarrowedType @@ -28488,12 +28392,6 @@ parameters: count: 1 path: ../../../htdocs/webportal/class/webportalpropal.class.php - - - message: '#^Parameter \#1 \$authentication of function check_authentication expects array\{login\: string, password\: string, entity\: int\|null, dolibarrkey\: string\}, array\{login\: string, entity\: int\} given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/webservices/server_category.php - - message: '#^Negated boolean expression is always true\.$#' identifier: booleanNot.alwaysTrue @@ -28530,12 +28428,6 @@ parameters: count: 2 path: ../../../htdocs/website/class/website.class.php - - - message: '#^Parameter \#2 \$arrayreplacement of function dolReplaceInFile expects array\, array\ given\.$#' - identifier: argument.type - count: 3 - path: ../../../htdocs/website/class/website.class.php - - message: '#^Property Website\:\:\$description \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -28614,12 +28506,6 @@ parameters: count: 1 path: ../../../htdocs/website/index.php - - - message: '#^If condition is always true\.$#' - identifier: if.alwaysTrue - count: 1 - path: ../../../htdocs/website/index.php - - message: '#^Left side of && is always true\.$#' identifier: booleanAnd.leftAlwaysTrue @@ -28635,7 +28521,7 @@ parameters: - message: '#^Negated boolean expression is always false\.$#' identifier: booleanNot.alwaysFalse - count: 2 + count: 1 path: ../../../htdocs/website/index.php - @@ -28656,30 +28542,12 @@ parameters: count: 1 path: ../../../htdocs/website/index.php - - - message: '#^Variable \$cate_arbo might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/website/index.php - - - - message: '#^Variable \$containertype might not be defined\.$#' - identifier: variable.undefined - count: 2 - path: ../../../htdocs/website/index.php - - message: '#^Variable \$contextpage in empty\(\) always exists and is not falsy\.$#' identifier: empty.variable count: 1 path: ../../../htdocs/website/index.php - - - message: '#^Variable \$disabled might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/website/index.php - - message: '#^Variable \$dolibarr_main_url_root might not be defined\.$#' identifier: variable.undefined @@ -28692,36 +28560,6 @@ parameters: count: 1 path: ../../../htdocs/website/index.php - - - message: '#^Variable \$langcode might not be defined\.$#' - identifier: variable.undefined - count: 2 - path: ../../../htdocs/website/index.php - - - - message: '#^Variable \$otherfilters might not be defined\.$#' - identifier: variable.undefined - count: 2 - path: ../../../htdocs/website/index.php - - - - message: '#^Variable \$tmpobject might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/website/index.php - - - - message: '#^Variable \$urltograbdirrootwithoutslash might not be defined\.$#' - identifier: variable.undefined - count: 2 - path: ../../../htdocs/website/index.php - - - - message: '#^Variable \$urltograbdirwithoutslash might not be defined\.$#' - identifier: variable.undefined - count: 4 - path: ../../../htdocs/website/index.php - - message: '#^If condition is always false\.$#' identifier: if.alwaysFalse @@ -28770,12 +28608,6 @@ parameters: count: 1 path: ../../../htdocs/website/websiteaccount_card.php - - - message: '#^Method Workstations\:\:index\(\) return type has no value type specified in iterable type array\.$#' - identifier: missingType.iterableValue - count: 1 - path: ../../../htdocs/workstation/class/api_workstations.class.php - - message: '#^Call to function method_exists\(\) with \$this\(Workstation\) and ''getLibStatut'' will always evaluate to true\.$#' identifier: function.alreadyNarrowedType diff --git a/dev/tools/phan/baseline.txt b/dev/tools/phan/baseline.txt index f5df87a7bf0..8caebf69968 100644 --- a/dev/tools/phan/baseline.txt +++ b/dev/tools/phan/baseline.txt @@ -9,21 +9,21 @@ */ return [ // # Issue statistics: - // PhanTypeMismatchArgument : 1380+ occurrences - // PhanUndeclaredProperty : 500+ occurrences - // PhanTypeMismatchArgumentNullable : 310+ occurrences + // PhanTypeMismatchArgument : 1240+ occurrences + // PhanUndeclaredProperty : 480+ occurrences + // PhanTypeMismatchArgumentNullable : 290+ occurrences // PhanPluginUnknownArrayMethodReturnType : 170+ occurrences - // PhanTypeMismatchProperty : 120+ occurrences + // PhanTypeMismatchProperty : 160+ occurrences // PhanPluginUnknownArrayMethodParamType : 110+ occurrences // PhanUndeclaredGlobalVariable : 100+ occurrences - // PhanTypeMismatchArgumentProbablyReal : 35+ occurrences - // PhanTypeExpectedObjectPropAccess : 30+ occurrences - // PhanPossiblyUndeclaredGlobalVariable : 25+ occurrences - // PhanTypeInvalidDimOffset : 25+ occurrences + // PhanTypeExpectedObjectPropAccess : 25+ occurrences + // PhanTypeInvalidDimOffset : 20+ occurrences // PhanTypeMismatchDimFetch : 20+ occurrences // PhanPluginUndeclaredVariableIsset : 15+ occurrences + // PhanTypeMismatchArgumentProbablyReal : 15+ occurrences // PhanUndeclaredConstant : 15+ occurrences // PhanTypeMismatchArgumentNullableInternal : 10+ occurrences + // PhanPossiblyUndeclaredGlobalVariable : 9 occurrences // PhanUndeclaredMethod : 9 occurrences // PhanTypeComparisonFromArray : 7 occurrences // PhanPluginDuplicateExpressionBinaryOp : 6 occurrences @@ -47,11 +47,9 @@ return [ 'htdocs/accountancy/admin/account.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/admin/card.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/admin/categories.php' => ['PhanTypeMismatchArgumentNullable'], - 'htdocs/accountancy/admin/categories_list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], + 'htdocs/accountancy/admin/categories_list.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/accountancy/admin/fiscalyear_card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/accountancy/admin/journals_list.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/admin/productaccount.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/accountancy/admin/report_list.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/admin/subaccount.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/bookkeeping/card.php' => ['PhanTypeMismatchArgument'], 'htdocs/accountancy/bookkeeping/export.php' => ['PhanTypeMismatchArgument'], @@ -76,9 +74,8 @@ return [ 'htdocs/accountancy/supplier/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/accountancy/tpl/export_journal.tpl.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/admin/member.php' => ['PhanTypeMismatchArgument'], - 'htdocs/adherents/admin/website.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/canvas/actions_adherentcard_common.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/adherents/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/adherents/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/adherents/class/adherent.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/adherents/class/adherent_type.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/adherents/class/api_members.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -93,7 +90,6 @@ return [ 'htdocs/admin/bom.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/company.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/defaultvalues.php' => ['PhanTypeMismatchArgumentProbablyReal'], - 'htdocs/admin/dict.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/emailcollector_card.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/emailcollector_list.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/eventorganization.php' => ['PhanTypeMismatchArgument'], @@ -121,14 +117,13 @@ return [ 'htdocs/admin/ticket.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/tools/export.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/webhook.php' => ['PhanTypeMismatchArgument'], - 'htdocs/admin/website.php' => ['PhanTypeMismatchArgument'], 'htdocs/api/class/api_access.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanUndeclaredProperty'], 'htdocs/api/class/api_documents.class.php' => ['PhanPluginDuplicateExpressionBinaryOp', 'PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/api/class/api_login.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/api/class/api_setup.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/api/class/api_status.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/asset/admin/setup.php' => ['PhanTypeMismatchArgument'], - 'htdocs/asset/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/asset/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/asset/class/asset.class.php' => ['PhanPluginUndeclaredVariableIsset', 'PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/asset/class/assetdepreciationoptions.class.php' => ['PhanTypeInvalidDimOffset'], 'htdocs/asset/class/assetmodel.class.php' => ['PhanUndeclaredProperty'], @@ -160,7 +155,7 @@ return [ 'htdocs/categories/photos.php' => ['PhanTypeMismatchArgument'], 'htdocs/categories/viewcat.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/collab/index.php' => ['PhanParamTooMany', 'PhanUndeclaredProperty'], - 'htdocs/comm/action/card.php' => ['PhanPluginBothLiteralsBinaryOp', 'PhanTypeMismatchArgument'], + 'htdocs/comm/action/card.php' => ['PhanPluginBothLiteralsBinaryOp', 'PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/comm/action/class/actioncomm.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/comm/action/class/api_agendaevents.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchProperty'], 'htdocs/comm/action/class/cactioncomm.class.php' => ['PhanPluginUnknownArrayPropertyType'], @@ -168,10 +163,10 @@ return [ 'htdocs/comm/action/index.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty'], 'htdocs/comm/action/info.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/comm/action/list.php' => ['PhanTypeMismatchArgument'], - 'htdocs/comm/action/pertype.php' => ['PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchArgument', 'PhanTypeMismatchDimFetch'], + 'htdocs/comm/action/pertype.php' => ['PhanTypeComparisonFromArray', 'PhanTypeExpectedObjectPropAccess', 'PhanTypeMismatchDimFetch'], 'htdocs/comm/action/peruser.php' => ['PhanTypeComparisonFromArray', 'PhanTypeMismatchArgument'], 'htdocs/comm/action/rapport/index.php' => ['PhanTypeMismatchArgument'], - 'htdocs/comm/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/comm/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/comm/mailing/card.php' => ['PhanPluginSuspiciousParamPosition', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/comm/mailing/cibles.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/comm/mailing/class/advtargetemailing.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -191,7 +186,7 @@ return [ 'htdocs/comm/remise.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/remx.php' => ['PhanTypeMismatchArgument'], 'htdocs/commande/agenda.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], + 'htdocs/commande/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty'], 'htdocs/commande/class/api_orders.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/commande/class/commande.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/commande/class/orderline.class.php' => ['PhanTypeMismatchArgument'], @@ -231,7 +226,7 @@ return [ 'htdocs/compta/deplacement/stats/index.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/agenda-rec.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/agenda.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/facture/card-rec.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], + 'htdocs/compta/facture/card-rec.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty'], 'htdocs/compta/facture/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/compta/facture/class/api_invoices.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeComparisonFromArray', 'PhanTypeMismatchArgumentProbablyReal'], 'htdocs/compta/facture/class/facture-rec.class.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], @@ -260,7 +255,7 @@ return [ 'htdocs/compta/paiement/class/paiement.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/compta/paiement/list.php' => ['PhanPossiblyUndeclaredGlobalVariable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullableInternal', 'PhanUndeclaredGlobalVariable'], 'htdocs/compta/paiement/rapport.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/prelevement/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/compta/prelevement/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/compta/prelevement/class/bonprelevement.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/compta/prelevement/class/rejetprelevement.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/prelevement/demandes.php' => ['PhanTypeMismatchArgumentNullable'], @@ -269,7 +264,7 @@ return [ 'htdocs/compta/resultat/index.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/resultat/projects.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/resultat/result.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/sociales/card.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], + 'htdocs/compta/sociales/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/compta/sociales/list.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/sociales/payments.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/compta/stats/cabyprodserv.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -285,7 +280,7 @@ return [ 'htdocs/compta/tva/quadri_detail.php' => ['PhanTypeArraySuspiciousNull', 'PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/contact/ajax/contact.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/contact/canvas/actions_contactcard_common.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/contact/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/contact/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/contact/class/contact.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/contact/consumption.php' => ['PhanTypeMismatchArgument'], 'htdocs/contact/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -309,7 +304,6 @@ return [ 'htdocs/core/ajax/ajaxdirtree.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable'], 'htdocs/core/ajax/ajaxstatusprospect.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/contacts.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/ajax/editinline.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/loadinplace.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/saveinplace.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/ajax/selectobject.php' => ['PhanTypeMismatchArgumentNullable'], @@ -337,7 +331,6 @@ return [ 'htdocs/core/class/extrafields.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/class/fileupload.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/class/fiscalyear.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/class/hookmanager.class.php' => ['PhanUndeclaredProperty'], 'htdocs/core/class/html.form.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/class/html.formcompany.class.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/class/html.formfile.class.php' => ['PhanTypeMismatchArgument'], @@ -359,19 +352,16 @@ return [ 'htdocs/core/lib/date.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/expedition.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/files.lib.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/core/lib/functions.lib.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/lib/functions2.lib.php' => ['PhanUndeclaredProperty'], 'htdocs/core/lib/functionsnumtoword.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/images.lib.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/lib/invoice.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/loan.lib.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/lib/modulebuilder.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/pdf.lib.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/lib/product.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/project.lib.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/lib/security.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/sendings.lib.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/lib/website.lib.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/lib/xcal.lib.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/login/functions_dolibarr.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/login/functions_ldap.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -409,25 +399,6 @@ return [ 'htdocs/core/modules/import/import_xlsx.modules.php' => ['PhanTypeMismatchProperty'], 'htdocs/core/modules/member/doc/pdf_standard_member.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/member/modules_cards.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modAdherent.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modCommande.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modContrat.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modDon.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modExpedition.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modExpenseReport.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modFacture.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modFicheinter.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modFournisseur.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modHRM.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modMrp.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modPrelevement.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modProjet.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modPropale.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modReceiptPrinter.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modReception.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modStock.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modSupplierProposal.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/modTicket.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/movement/doc/pdf_standard_movementstock.modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/mrp/doc/pdf_vinci.modules.php' => ['PhanUndeclaredProperty'], 'htdocs/core/modules/mrp/mod_mo_advanced.php' => ['PhanUndeclaredProperty'], @@ -453,6 +424,7 @@ return [ 'htdocs/core/modules/workstation/mod_workstation_advanced.php' => ['PhanUndeclaredProperty'], 'htdocs/core/multicompany_page.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/search_page.php' => ['PhanTypeMismatchArgument'], + 'htdocs/core/tpl/document_actions_post_headers.tpl.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/tpl/extrafields_list_array_fields.tpl.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/tpl/extrafields_list_print_fields.tpl.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/tpl/extrafields_view.tpl.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], @@ -472,8 +444,10 @@ return [ 'htdocs/datapolicy/class/datapolicycron.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/dav/dav.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/debugbar/class/TraceableDB.php' => ['PhanTypeMismatchArgument'], + 'htdocs/delivery/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/delivery/class/delivery.class.php' => ['PhanUndeclaredProperty'], 'htdocs/don/admin/donation.php' => ['PhanUndeclaredMethod'], + 'htdocs/don/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/don/class/api_donations.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType'], 'htdocs/don/class/don.class.php' => ['PhanParamTooMany'], 'htdocs/don/document.php' => ['PhanUndeclaredGlobalVariable'], @@ -501,9 +475,10 @@ return [ 'htdocs/expedition/class/expedition.class.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/expedition/class/expeditionlinebatch.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/expedition/list.php' => ['PhanTypeMismatchArgument'], + 'htdocs/expedition/shipment.php' => ['PhanTypeMismatchProperty'], 'htdocs/expedition/stats/index.php' => ['PhanTypeMismatchArgument'], 'htdocs/expensereport/ajax/ajaxik.php' => ['PhanTypeMismatchArgument'], - 'htdocs/expensereport/card.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], + 'htdocs/expensereport/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/expensereport/class/api_expensereports.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType'], 'htdocs/expensereport/class/expensereport.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/expensereport/class/expensereportline.class.php' => ['PhanTypeMismatchArgument'], @@ -518,6 +493,7 @@ return [ 'htdocs/externalsite/frames.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/fichinter/agenda.php' => ['PhanTypeMismatchArgument'], 'htdocs/fichinter/card-rec.php' => ['PhanUndeclaredGlobalVariable'], + 'htdocs/fichinter/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/fichinter/class/api_interventions.class.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/fichinter/class/fichinterrec.class.php' => ['PhanUndeclaredProperty'], 'htdocs/fichinter/contact.php' => ['PhanTypeMismatchArgument'], @@ -527,6 +503,7 @@ return [ 'htdocs/fichinter/stats/index.php' => ['PhanTypeMismatchArgument'], 'htdocs/fichinter/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/filefunc.inc.php' => ['PhanPluginUndeclaredVariableIsset', 'PhanPossiblyUndeclaredGlobalVariable', 'PhanUndeclaredGlobalVariable'], + 'htdocs/fourn/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/fourn/class/api_supplier_invoices.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/fourn/class/api_supplier_orders.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgumentProbablyReal'], 'htdocs/fourn/class/fournisseur.commande.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], @@ -536,13 +513,14 @@ return [ 'htdocs/fourn/class/fournisseur.facture.ligne.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/fourn/class/fournisseur.orderline.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/fourn/class/fournisseur.product.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/fourn/commande/card.php' => ['PhanTypeMismatchDimAssignment', 'PhanTypeSuspiciousStringExpression', 'PhanUndeclaredProperty'], + 'htdocs/fourn/commande/card.php' => ['PhanTypeMismatchDimAssignment', 'PhanTypeMismatchProperty', 'PhanTypeSuspiciousStringExpression', 'PhanUndeclaredProperty'], 'htdocs/fourn/commande/dispatch.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/fourn/facture/card-rec.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], + 'htdocs/fourn/facture/card-rec.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/fourn/facture/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchProperty'], 'htdocs/fourn/facture/paiement.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/fourn/facture/rapport.php' => ['PhanTypeMismatchArgument'], 'htdocs/fourn/facture/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], + 'htdocs/holiday/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/holiday/card_group.php' => ['PhanTypeMismatchArgument'], 'htdocs/holiday/list.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/hrm/class/evaluation.class.php' => ['PhanUndeclaredProperty'], @@ -577,12 +555,15 @@ return [ 'htdocs/partnership/core/modules/partnership/mod_partnership_advanced.php' => ['PhanUndeclaredProperty'], 'htdocs/partnership/partnership_card.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/partnership/partnership_list.php' => ['PhanUndeclaredProperty'], + 'htdocs/product/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/product/class/api_products.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/product/class/html.formproduct.class.php' => ['PhanUndeclaredProperty'], 'htdocs/product/class/productfournisseurprice.class.php' => ['PhanUndeclaredMethod', 'PhanUndeclaredProperty'], 'htdocs/product/inventory/class/inventory.class.php' => ['PhanUndeclaredProperty'], 'htdocs/product/price.php' => ['PhanUndeclaredProperty'], + 'htdocs/product/price_suppliers.php' => ['PhanTypeMismatchProperty'], 'htdocs/product/reassort.php' => ['PhanTypeExpectedObjectPropAccessButGotNull'], + 'htdocs/product/stock/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/product/stock/class/api_stockmovements.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/product/stock/class/api_warehouses.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType'], 'htdocs/product/stock/info.php' => ['PhanUndeclaredProperty'], @@ -599,8 +580,9 @@ return [ 'htdocs/product/stock/tpl/stockcorrection.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/product/stock/tpl/stocktransfer.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/projet/admin/project.php' => ['PhanTypeMismatchArgumentProbablyReal'], - 'htdocs/projet/card.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredGlobalVariable'], + 'htdocs/projet/card.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable'], 'htdocs/projet/class/api_tasks.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], + 'htdocs/projet/tasks.php' => ['PhanTypeMismatchArgument'], 'htdocs/projet/tasks/time.php' => ['PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/projet/tasks/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/public/eventorganization/subscriptionok.php' => ['PhanUndeclaredGlobalVariable'], @@ -613,10 +595,10 @@ return [ 'htdocs/public/project/viewandvote.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/recruitment/view.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/webportal/tpl/menu.tpl.php' => ['PhanUndeclaredProperty'], - 'htdocs/reception/card.php' => ['PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], + 'htdocs/reception/card.php' => ['PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/reception/class/api_receptions.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/reception/class/reception.class.php' => ['PhanUndeclaredProperty'], - 'htdocs/reception/list.php' => ['PhanUndeclaredProperty'], + 'htdocs/reception/list.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/recruitment/class/recruitmentcandidature.class.php' => ['PhanUndeclaredProperty'], 'htdocs/recruitment/class/recruitmentjobposition.class.php' => ['PhanUndeclaredProperty'], 'htdocs/recruitment/core/modules/recruitment/doc/pdf_standard_recruitmentjobposition.modules.php' => ['PhanUndeclaredProperty'], @@ -633,11 +615,12 @@ return [ 'htdocs/salaries/paiement_salary.php' => ['PhanUndeclaredProperty'], 'htdocs/salaries/virement_request.php' => ['PhanUndeclaredProperty'], 'htdocs/societe/ajax/company.php' => ['PhanUndeclaredProperty'], + 'htdocs/societe/card.php' => ['PhanTypeMismatchProperty'], 'htdocs/societe/class/api_thirdparties.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentProbablyReal', 'PhanTypeMismatchProperty'], 'htdocs/societe/class/societe.class.php' => ['PhanTypeMismatchProperty'], 'htdocs/societe/paymentmodes.php' => ['PhanPossiblyUndeclaredGlobalVariable', 'PhanTypeMismatchArgument'], 'htdocs/stripe/class/stripe.class.php' => ['PhanTypeExpectedObjectPropAccess'], - 'htdocs/supplier_proposal/card.php' => ['PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], + 'htdocs/supplier_proposal/card.php' => ['PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/supplier_proposal/class/api_supplier_proposals.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType', 'PhanUndeclaredProperty'], 'htdocs/supplier_proposal/class/supplier_proposal.class.php' => ['PhanUndeclaredProperty'], 'htdocs/takepos/index.php' => ['PhanPluginUndeclaredVariableIsset'], @@ -672,14 +655,9 @@ return [ 'htdocs/webservices/server_supplier_invoice.php' => ['PhanUndeclaredProperty'], 'htdocs/webservices/server_thirdparty.php' => ['PhanUndeclaredProperty'], 'htdocs/webservices/server_user.php' => ['PhanUndeclaredProperty'], - 'htdocs/website/class/website.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullableInternal'], - 'htdocs/website/index.php' => ['PhanPossiblyUndeclaredGlobalVariable', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/website/samples/wrapper.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal'], 'htdocs/website/websiteaccount_card.php' => ['PhanUndeclaredProperty'], - 'htdocs/workstation/class/api_workstations.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/workstation/class/workstation.class.php' => ['PhanUndeclaredProperty'], - 'htdocs/workstation/workstation_card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanUndeclaredProperty'], - 'htdocs/workstation/workstation_list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal'], + 'htdocs/workstation/workstation_card.php' => ['PhanUndeclaredProperty'], 'htdocs/zapier/class/api_zapier.class.php' => ['PhanPluginUnknownArrayMethodParamType', 'PhanPluginUnknownArrayMethodReturnType'], 'htdocs/zapier/class/hook.class.php' => ['PhanUndeclaredProperty'], 'internal' => ['PhanUndeclaredConstant'], diff --git a/htdocs/accountancy/admin/categories_list.php b/htdocs/accountancy/admin/categories_list.php index 45bb66e8d23..ccc9d90da61 100644 --- a/htdocs/accountancy/admin/categories_list.php +++ b/htdocs/accountancy/admin/categories_list.php @@ -2,7 +2,7 @@ /* Copyright (C) 2004-2023 Laurent Destailleur * Copyright (C) 2011-2024 Alexandre Spangaro * Copyright (C) 2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,7 +67,7 @@ $actl[1] = img_picto($langs->trans("Activated"), 'switch_on', 'class="size15x"') $listoffset = GETPOST('listoffset', 'alpha'); $listlimit = GETPOSTINT('listlimit') > 0 ? GETPOSTINT('listlimit') : 1000; -$sortfield = GETPOST("sortfield", 'aZ09comma'); +$sortfield = (string) GETPOST("sortfield", 'aZ09comma'); $sortorder = GETPOST("sortorder", 'aZ09comma'); $page = GETPOSTISSET('pageplusone') ? (GETPOSTINT('pageplusone') - 1) : GETPOSTINT("page"); if (empty($page) || $page < 0 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha')) { diff --git a/htdocs/adherents/admin/website.php b/htdocs/adherents/admin/website.php index 401cb68a4b6..1c45e25c404 100644 --- a/htdocs/adherents/admin/website.php +++ b/htdocs/adherents/admin/website.php @@ -5,6 +5,7 @@ * Copyright (C) 2011 Juanjo Menent * Copyright (C) 2024 Alexandre Spangaro * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -273,7 +274,7 @@ if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) { print ''; print $langs->trans("MembersShowMembershipTypesTable"); print ''; - print $form->selectyesno("MEMBER_SHOW_TABLE", !$skiptable, 1, false, 0, 1); // Reverse the logic "hide -> show" for retrocompatibility + print $form->selectyesno("MEMBER_SHOW_TABLE", (int) !$skiptable, 1, false, 0, 1); // Reverse the logic "hide -> show" for retrocompatibility print "\n"; // Show "vote allowed" setting for membership types @@ -281,7 +282,7 @@ if (getDolGlobalString('MEMBER_ENABLE_PUBLIC')) { print ''; print $langs->trans("MembersShowVotesAllowed"); print ''; - print $form->selectyesno("MEMBER_SHOW_VOTE_ALLOWED", !$hidevoteallowed, 1, false, 0, 1); // Reverse the logic "hide -> show" for retrocompatibility + print $form->selectyesno("MEMBER_SHOW_VOTE_ALLOWED", (int) !$hidevoteallowed, 1, false, 0, 1); // Reverse the logic "hide -> show" for retrocompatibility print "\n"; // Jump to an online payment page diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index daf9a764c32..fa5887e13f3 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -275,7 +275,7 @@ $tabsql[DICT_ACTIONCOMM] = "SELECT a.id as rowid, a.code as code, a.libelle A $tabsql[DICT_CHARGESOCIALES] = "SELECT a.id as rowid, a.code as code, a.libelle AS libelle, a.accountancy_code as accountancy_code, c.code as country_code, c.label as country, a.fk_pays as country_id, a.active FROM ".MAIN_DB_PREFIX."c_chargesociales AS a, ".MAIN_DB_PREFIX."c_country as c WHERE a.fk_pays = c.rowid and c.active = 1"; $tabsql[DICT_TYPENT] = "SELECT t.id as rowid, t.code as code, t.libelle, t.fk_country as country_id, c.code as country_code, c.label as country, t.position, t.active FROM ".MAIN_DB_PREFIX."c_typent as t LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON t.fk_country=c.rowid"; $tabsql[DICT_CURRENCIES] = "SELECT c.code_iso as code, c.label, c.unicode, c.active FROM ".MAIN_DB_PREFIX."c_currencies AS c"; -$tabsql[DICT_TVA] = "SELECT t.rowid, t.entity, t.code, t.type_vat, t.taux, t.localtax1_type, t.localtax1, t.localtax2_type, t.localtax2, c.label as country, c.code as country_code, t.fk_pays as country_id, t.fk_department_buyer as department_buyer_id, db.nom as department_buyer, t.recuperableonly, t.note, t.active, t.accountancy_code_sell, t.accountancy_code_buy FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON t.fk_pays = c.rowid LEFT JOIN ".MAIN_DB_PREFIX."c_departements as db ON t.fk_department_buyer = db.rowid WHERE t.entity IN (".getEntity($tabname[DICT_TVA]).")"; +$tabsql[DICT_TVA] = "SELECT t.rowid, t.entity, t.code, t.type_vat, t.taux, t.localtax1_type, t.localtax1, t.localtax2_type, t.localtax2, c.label as country, c.code as country_code, t.fk_pays as country_id, t.fk_department_buyer as department_buyer_id, db.nom as department_buyer, t.recuperableonly, t.note, t.active, t.accountancy_code_sell, t.accountancy_code_buy, t.use_default FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON t.fk_pays = c.rowid LEFT JOIN ".MAIN_DB_PREFIX."c_departements as db ON t.fk_department_buyer = db.rowid WHERE t.entity IN (".getEntity($tabname[DICT_TVA]).")"; $tabsql[DICT_TYPE_CONTACT] = "SELECT t.rowid as rowid, t.element, t.source, t.code, t.libelle, t.position, t.active FROM ".MAIN_DB_PREFIX."c_type_contact AS t"; $tabsql[DICT_PAYMENT_TERM] = "SELECT c.rowid as rowid, c.code, c.libelle, c.libelle_facture, c.deposit_percent, c.nbjour, c.type_cdr, c.decalage, c.active, c.sortorder, c.entity FROM ".MAIN_DB_PREFIX."c_payment_term AS c WHERE c.entity IN (".getEntity($tabname[DICT_PAYMENT_TERM]).")"; $tabsql[DICT_PAIEMENT] = "SELECT c.id as rowid, c.code, c.libelle, c.type, c.active, c.entity FROM ".MAIN_DB_PREFIX."c_paiement AS c WHERE c.entity IN (".getEntity($tabname[DICT_PAIEMENT]).")"; @@ -369,7 +369,7 @@ $tabfield[DICT_ACTIONCOMM] = "code,libelle,type,color,position"; $tabfield[DICT_CHARGESOCIALES] = "code,libelle,country,accountancy_code"; $tabfield[DICT_TYPENT] = "code,libelle,country_id,country".(getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? ',position' : ''); $tabfield[DICT_CURRENCIES] = "code,label,unicode"; -$tabfield[DICT_TVA] = "country_id,country,department_buyer_id,department_buyer,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note"; +$tabfield[DICT_TVA] = "country_id,country,department_buyer_id,department_buyer,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,use_default,note"; $tabfield[DICT_TYPE_CONTACT] = "element,source,code,libelle,position"; $tabfield[DICT_PAYMENT_TERM] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder"; $tabfield[DICT_PAIEMENT] = "code,libelle,type"; @@ -416,7 +416,7 @@ $tabfieldvalue[DICT_ACTIONCOMM] = "code,libelle,type,color,position"; $tabfieldvalue[DICT_CHARGESOCIALES] = "code,libelle,country,accountancy_code"; $tabfieldvalue[DICT_TYPENT] = "code,libelle,country".(getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? ',position' : ''); $tabfieldvalue[DICT_CURRENCIES] = "code,label,unicode"; -$tabfieldvalue[DICT_TVA] = "country,department_buyer_id,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note"; +$tabfieldvalue[DICT_TVA] = "country,department_buyer_id,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,use_default,note"; $tabfieldvalue[DICT_TYPE_CONTACT] = "element,source,code,libelle,position"; $tabfieldvalue[DICT_PAYMENT_TERM] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder"; $tabfieldvalue[DICT_PAIEMENT] = "code,libelle,type"; @@ -463,7 +463,7 @@ $tabfieldinsert[DICT_ACTIONCOMM] = "code,libelle,type,color,position"; $tabfieldinsert[DICT_CHARGESOCIALES] = "code,libelle,fk_pays,accountancy_code"; $tabfieldinsert[DICT_TYPENT] = "code,libelle,fk_country".(getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? ',position' : ''); $tabfieldinsert[DICT_CURRENCIES] = "code_iso,label,unicode"; -$tabfieldinsert[DICT_TVA] = "fk_pays,fk_department_buyer,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note,entity"; +$tabfieldinsert[DICT_TVA] = "fk_pays,fk_department_buyer,code,type_vat,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,use_default,note,entity"; $tabfieldinsert[DICT_TYPE_CONTACT] = "element,source,code,libelle,position"; $tabfieldinsert[DICT_PAYMENT_TERM] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder,entity"; $tabfieldinsert[DICT_PAIEMENT] = "code,libelle,type,entity"; diff --git a/htdocs/admin/remotestore/class/externalModules.class.php b/htdocs/admin/remotestore/class/externalModules.class.php index 97d01ac602b..d0bc7d47aa2 100644 --- a/htdocs/admin/remotestore/class/externalModules.class.php +++ b/htdocs/admin/remotestore/class/externalModules.class.php @@ -1,7 +1,8 @@ + * Copyright (C) 2025 Mohamed DAOUD * Copyright (C) 2025 MDW + * Copyright (C) 2025 Frédéric France * * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); * it under the terms of the GNU General Public License as published bypliance with the License. @@ -126,7 +127,7 @@ class ExternalModules $this->debug_api = $debug; $this->file_source_url = "https://raw.githubusercontent.com/Dolibarr/dolibarr-community-modules/refs/heads/main/index.yaml"; - $this->cache_file = DOL_DOCUMENT_ROOT.'/admin/remotestore/sources/github_modules_file.yaml'; + $this->cache_file = DOL_DATA_ROOT.'/admin/remotestore/sources/github_modules_file.yaml'; $this->getRemoteYamlFile($this->file_source_url, 86400); $lang = $langs->defaultlang; diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php index 99a38e9a49e..13e5a502e29 100644 --- a/htdocs/admin/stock.php +++ b/htdocs/admin/stock.php @@ -194,12 +194,14 @@ $form = new Form($db); $formproduct = new FormProduct($db); - -$disabled = ''; +$disableStockCalculateOn = array(); if (isModEnabled('productbatch')) { // If module lot/serial enabled, we force the inc/dec mode to STOCK_CALCULATE_ON_SHIPMENT_CLOSE and STOCK_CALCULATE_ON_RECEPTION_CLOSE $langs->load("productbatch"); - $disabled = ' disabled'; + $disableStockCalculateOn[] = 'BILL'; + $disableStockCalculateOn[] = 'VALIDATE_ORDER'; + $disableStockCalculateOn[] = 'SUPPLIER_BILL'; + $disableStockCalculateOn[] = 'SUPPLIER_VALIDATE_ORDER'; // STOCK_CALCULATE_ON_SHIPMENT_CLOSE $descmode = $langs->trans('DeStockOnShipmentOnClosing'); @@ -239,7 +241,7 @@ print ''.$langs->trans("DeStockOnBill").''; print ''; if (isModEnabled('invoice')) { if ($conf->use_javascript_ajax) { - if ($disabled) { + if (in_array('BILL', $disableStockCalculateOn)) { print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); } else { print ajax_constantonoff('STOCK_CALCULATE_ON_BILL', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); @@ -261,7 +263,7 @@ print ''.$langs->trans("DeStockOnValidateOrder").''; print ''; if (isModEnabled('order')) { if ($conf->use_javascript_ajax) { - if ($disabled) { + if (in_array('VALIDATE_ORDER', $disableStockCalculateOn)) { print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); } else { print ajax_constantonoff('STOCK_CALCULATE_ON_VALIDATE_ORDER', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); @@ -285,7 +287,11 @@ print ''.$langs->trans("DeStockOnShipment").''; print ''; if (isModEnabled("shipping")) { if ($conf->use_javascript_ajax) { - print ajax_constantonoff('STOCK_CALCULATE_ON_SHIPMENT', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + if (in_array('SHIPMENT', $disableStockCalculateOn)) { + print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); + } else { + print ajax_constantonoff('STOCK_CALCULATE_ON_SHIPMENT', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + } } else { $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); print $form->selectarray("STOCK_CALCULATE_ON_SHIPMENT", $arrval, getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT')); @@ -302,7 +308,11 @@ print ''.$langs->trans("DeStockOnShipmentOnClosing").''; print ''; if (isModEnabled("shipping")) { if ($conf->use_javascript_ajax) { - print ajax_constantonoff('STOCK_CALCULATE_ON_SHIPMENT_CLOSE', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + if (in_array('SHIPMENT_CLOSE', $disableStockCalculateOn)) { + print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); + } else { + print ajax_constantonoff('STOCK_CALCULATE_ON_SHIPMENT_CLOSE', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + } } else { $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); print $form->selectarray("STOCK_CALCULATE_ON_SHIPMENT_CLOSE", $arrval, getDolGlobalString('STOCK_CALCULATE_ON_SHIPMENT_CLOSE')); @@ -335,7 +345,7 @@ print ''.$langs->trans("ReStockOnBill").''; print ''; if (isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) { if ($conf->use_javascript_ajax) { - if ($disabled) { + if (in_array('SUPPLIER_BILL', $disableStockCalculateOn)) { print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); } else { print ajax_constantonoff('STOCK_CALCULATE_ON_SUPPLIER_BILL', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); @@ -357,7 +367,7 @@ print ''.$langs->trans("ReStockOnValidateOrder").''; print ''; if (isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) { if ($conf->use_javascript_ajax) { - if ($disabled) { + if (in_array('SUPPLIER_VALIDATE_ORDER', $disableStockCalculateOn)) { print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); } else { print ajax_constantonoff('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); @@ -379,7 +389,11 @@ if (isModEnabled("reception")) { print ''; if ($conf->use_javascript_ajax) { - print ajax_constantonoff('STOCK_CALCULATE_ON_RECEPTION', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + if (in_array('RECEPTION', $disableStockCalculateOn)) { + print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); + } else { + print ajax_constantonoff('STOCK_CALCULATE_ON_RECEPTION', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + } } else { $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); print $form->selectarray("STOCK_CALCULATE_ON_RECEPTION", $arrval, getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION')); @@ -394,7 +408,11 @@ if (isModEnabled("reception")) { print ''; if ($conf->use_javascript_ajax) { - print ajax_constantonoff('STOCK_CALCULATE_ON_RECEPTION_CLOSE', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + if (in_array('RECEPTION_CLOSE', $disableStockCalculateOn)) { + print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); + } else { + print ajax_constantonoff('STOCK_CALCULATE_ON_RECEPTION_CLOSE', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + } } else { $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); print $form->selectarray("STOCK_CALCULATE_ON_RECEPTION_CLOSE", $arrval, getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')); @@ -409,7 +427,11 @@ if (isModEnabled("reception")) { print ''; if (isModEnabled("supplier_order")) { if ($conf->use_javascript_ajax) { - print ajax_constantonoff('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + if (in_array('SUPPLIER_DISPATCH_ORDER', $disableStockCalculateOn)) { + print img_picto($langs->trans("Disabled"), 'off', 'class="opacitymedium"'); + } else { + print ajax_constantonoff('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER', array(), null, 0, 0, 0, 2, 1, 0, '', '', 'reposition'); + } } else { $arrval = array('0' => $langs->trans("No"), '1' => $langs->trans("Yes")); print $form->selectarray("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", $arrval, getDolGlobalString('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER')); diff --git a/htdocs/admin/website.php b/htdocs/admin/website.php index 8979ee62e67..ed762155d01 100644 --- a/htdocs/admin/website.php +++ b/htdocs/admin/website.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -258,7 +258,7 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) { // Modifie valeur des champs if ($tabrowid[$id] && !in_array($tabrowid[$id], $listfieldmodify)) { $sql .= $tabrowid[$id]."="; - $sql .= "'".$db->escape($rowid)."', "; + $sql .= "'".$db->escape((string) $rowid)."', "; } $i = 0; foreach ($listfieldmodify as $field) { diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index 1ce3201aa9c..e7be7cfef13 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -48,7 +48,7 @@ * @var string $action */ ' -@phan-var-force CommonObjectLine $line +@phan-var-force BOMLine $line @phan-var-force int $num @phan-var-force int $i @phan-var-force CommonObject $this diff --git a/htdocs/bookmarks/bookmarks.lib.php b/htdocs/bookmarks/bookmarks.lib.php index 0034df39904..fbf2bd232cf 100644 --- a/htdocs/bookmarks/bookmarks.lib.php +++ b/htdocs/bookmarks/bookmarks.lib.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 Frédéric France +/* Copyright (C) 2009 Laurent Destailleur + * Copyright (C) 2024-2025 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -57,7 +57,7 @@ function printDropdownBookmarksList() $tmpurl = ''; // No urlencode, all param $url will be urlencoded later if ($sortfield) { - $tmpurl .= ($tmpurl ? '&' : '').'sortfield='.urlencode($sortfield); + $tmpurl .= /* ($tmpurl ? '&' : ''). */'sortfield='.urlencode($sortfield); } if ($sortorder) { $tmpurl .= ($tmpurl ? '&' : '').'sortorder='.urlencode($sortorder); diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 6620bda7696..58e9046c4d3 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -10,7 +10,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2016-2024 Charlene Benke - * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2023-2024 Benjamin Falière * Copyright (C) 2024 MDW * @@ -578,11 +578,9 @@ class Categorie extends CommonObject $action = 'create'; // Actions on extra fields - if (!$error) { - $result = $this->insertExtraFields(); - if ($result < 0) { - $error++; - } + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; } if (!$error && !$notrigger) { @@ -661,11 +659,9 @@ class Categorie extends CommonObject $action = 'update'; // Actions on extra fields - if (!$error) { - $result = $this->insertExtraFields(); - if ($result < 0) { - $error++; - } + $result = $this->insertExtraFields(); + if ($result < 0) { + $error++; } if (!$error && !$notrigger) { @@ -709,7 +705,7 @@ class Categorie extends CommonObject $this->db->begin(); - if (!$error && !$notrigger) { + if (/* !$error && */ !$notrigger) { // Call trigger $result = $this->call_trigger('CATEGORY_DELETE', $user); if ($result < 0) { @@ -1843,7 +1839,7 @@ class Categorie extends CommonObject if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { $add_save_lastsearch_values = 1; } - if ($url && $add_save_lastsearch_values) { + if (/* $url && */ $add_save_lastsearch_values) { $url .= '&save_lastsearch_values=1'; } } @@ -1868,13 +1864,13 @@ class Categorie extends CommonObject $linkclose = ' class="'.$forced_color.($morecss ? ' '.$morecss : '').'"'; } - if ($option == 'nolink' || empty($url)) { + if ($option == 'nolink' /* || empty($url) */) { $linkstart = ''; - if ($option == 'nolink' || empty($url)) { + if ($option == 'nolink' /* || empty($url) */) { $linkend = ''; } else { $linkend = ''; diff --git a/htdocs/categories/edit.php b/htdocs/categories/edit.php index aa1c2a32439..d10758189df 100644 --- a/htdocs/categories/edit.php +++ b/htdocs/categories/edit.php @@ -4,7 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2007 Patrick Raguin * Copyright (C) 2020-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -110,7 +110,7 @@ if (empty($reshook)) { // Action mise a jour d'une categorie if ($action == 'update' && $user->hasRight('categorie', 'creer')) { - $object->oldcopy = dol_clone($object, 2); + $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty $object->label = $label; $object->description = dol_htmlcleanlastbr($description); diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index fbdb640bf5d..3ffddeb50cb 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -1169,20 +1169,26 @@ if (empty($reshook)) { if ($result) { // If there is some prices specific to the customer if (count($prodcustprice->lines) > 0) { - $pricebycustomerexist = true; - $pu_ht = price($prodcustprice->lines[0]->price); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_min = price($prodcustprice->lines[0]->price_min); - $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pricebycustomerexist = true; + $pu_ht = price($custprice_line->price); + $pu_ttc = price($custprice_line->price_ttc); + $price_min = price($custprice_line->price_min); + $price_min_ttc = price($custprice_line->price_min_ttc); + $price_base_type = $custprice_line->price_base_type; + /*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx); + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' ('.$custprice_line->default_vat_code.')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + }*/ + break; + } } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; - }*/ } } @@ -1227,19 +1233,25 @@ if (empty($reshook)) { if ($result) { // If there is some prices specific to the customer if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_min = price($prodcustprice->lines[0]->price_min); - $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - /*$tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pu_ht = price($custprice_line->price); + $pu_ttc = price($custprice_line->price_ttc); + $price_min = price($custprice_line->price_min); + $price_min_ttc = price($custprice_line->price_min_ttc); + $price_base_type = $custprice_line->price_base_type; + /*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx); + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' ('.$custprice_line->default_vat_code.')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + }*/ + break; + } } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; - }*/ } } } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) { diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 2f8723a7c8b..626d9e315f3 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1542,10 +1542,17 @@ class Propal extends CommonObject if ($result) { // If there is some prices specific to the customer if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $tva_tx = ($prodcustprice->lines[0]->default_vat_code ? $prodcustprice->lines[0]->tva_tx.' ('.$prodcustprice->lines[0]->default_vat_code.' )' : $prodcustprice->lines[0]->tva_tx); - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pu_ht = price($custprice_line->price); + $tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx . ' (' . $custprice_line->default_vat_code . ' )' : $custprice_line->tva_tx); + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' (' . $custprice_line->default_vat_code . ')'; + } + $remise_percent = $custprice_line->discount_percent; + break; + } } } } diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index f10e6e3aa6c..913dc87d333 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -877,19 +877,25 @@ if (empty($reshook)) { $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result >= 0) { if (count($prodcustprice->lines) > 0) { - $pricebycustomerexist = true; - $pu_ht = price($prodcustprice->lines[0]->price); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_min = price($prodcustprice->lines[0]->price_min); - $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - $tva_tx = $prodcustprice->lines[0]->tva_tx; - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', (string) $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; - } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pricebycustomerexist = true; + $pu_ht = price($custprice_line->price); + $pu_ttc = price($custprice_line->price_ttc); + $price_min = price($custprice_line->price_min); + $price_min_ttc = price($custprice_line->price_min_ttc); + $price_base_type = $custprice_line->price_base_type; + $tva_tx = $custprice_line->tva_tx; + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', (string) $tva_tx)) { + $tva_tx .= ' (' . $custprice_line->default_vat_code . ')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + } + break; + } } } } else { @@ -938,18 +944,24 @@ if (empty($reshook)) { $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result >= 0) { if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_min = price($prodcustprice->lines[0]->price_min); - $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - $tva_tx = $prodcustprice->lines[0]->tva_tx; - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; - } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pu_ht = price($custprice_line->price); + $pu_ttc = price($custprice_line->price_ttc); + $price_min = price($custprice_line->price_min); + $price_min_ttc = price($custprice_line->price_min_ttc); + $price_base_type = $custprice_line->price_base_type; + $tva_tx = $custprice_line->tva_tx; + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' (' . $custprice_line->default_vat_code . ')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + } + break; + } } } } else { diff --git a/htdocs/compta/paymentbybanktransfer/index.php b/htdocs/compta/paymentbybanktransfer/index.php index 0135859786d..d178a45db85 100644 --- a/htdocs/compta/paymentbybanktransfer/index.php +++ b/htdocs/compta/paymentbybanktransfer/index.php @@ -80,7 +80,7 @@ $thirdpartystatic = new Societe($db); $invoicestatic = new FactureFournisseur($db); $bprev = new BonPrelevement($db); $salary = new Salary($db); -$user = new User($db); +$userstatic = new User($db); $newcardbutton = ''; if ($usercancreate) { @@ -240,7 +240,7 @@ if (isModEnabled('salaries')) { while ($j < $numRow && $j < 10) { $objSalary = $db->fetch_object($resql2); - $user->fetch($objSalary->fk_user); + $userstatic->fetch($objSalary->fk_user); $salary->fetch($objSalary->fk_salary); @@ -251,7 +251,7 @@ if (isModEnabled('salaries')) { print ''; print ''; - print $user->getNomUrl(-1); + print $userstatic->getNomUrl(-1); print ''; print ''; diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 7102d907a6d..e2f11457698 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -572,16 +572,22 @@ if (empty($reshook)) { $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result) { if (count($prodcustprice->lines) > 0) { - $price_min = price($prodcustprice->lines[0]->price_min); - $price_min_ttc = price($prodcustprice->lines[0]->price_min_ttc); - /*$tva_tx = $prodcustprice->lines[0]->tva_tx; - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $price_min = price($custprice_line->price_min); + $price_min_ttc = price($custprice_line->price_min_ttc); + /*$tva_tx = $custprice_line->tva_tx; + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' ('.$custprice_line->default_vat_code.')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + }*/ + break; + } } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; - }*/ } } } diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 35a67a4c272..1b26cc5595c 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -4,7 +4,7 @@ * Copyright (C) 2018-2021 Nicolas ZABOURI * Copyright (C) 2018 Juanjo Menent * Copyright (C) 2019 Ferran Marcet - * Copyright (C) 2019-2024 Frédéric France + * Copyright (C) 2019-2025 Frédéric France * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -47,6 +47,7 @@ * @var User $user * * @var string $dolibarr_main_url_root + * @var ?string $permissiontoadd * @var ?string $permissiontoread * @var ?string $permissiontodelete * @var ?string $permissiontoclose diff --git a/htdocs/core/ajax/editinline.php b/htdocs/core/ajax/editinline.php index 6ed0ecae1b9..75810a9f8c5 100644 --- a/htdocs/core/ajax/editinline.php +++ b/htdocs/core/ajax/editinline.php @@ -1,6 +1,7 @@ * Copyright (C) 2024 Frédéric France + * Copyright (C) 2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,7 +73,7 @@ top_httphead(); if (!empty($action) && $action === 'updatedElementContent' && $usercanmodify && !empty($content) && !empty($element_id) && !empty($website_ref) && !empty($page_id)) { // Page object $objectpage = new WebsitePage($db); - $res = $objectpage->fetch($page_id); + $res = $objectpage->fetch((int) $page_id); if (!$res) { print "Cannot find page with ID = " . $page_id . "."; exit; diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index bfc13a8d337..033e546c59d 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -3,7 +3,7 @@ /* Copyright (C) 2010-2016 Laurent Destailleur * Copyright (C) 2010-2014 Regis Houssin * Copyright (C) 2010-2011 Juanjo Menent - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -150,7 +150,8 @@ class HookManager '@phan-var-force CommonHookActions $actionInstance'; - $priority = empty($actionInstance->priority) ? 50 : $actionInstance->priority; + // @phan-suppress-next-line PhanUndeclaredProperty + $priority = property_exists($actionInstance, 'priority') && empty($actionInstance->priority) ? 50 : $actionInstance->priority; $this->hooks[$context][$module] = $actionInstance; $this->hooksSorted[$context][$priority.':'.$module] = $actionInstance; @@ -189,7 +190,7 @@ class HookManager * * @param string $method Name of method hooked ('doActions', 'printSearchForm', 'showInputField', ...) * @param array $parameters Array of parameters - * @param object $object Object to use hooks on + * @param null|Object|string $object Object to use hooks on @phan-ignore-reference * @param string $action Action code on calling page ('create', 'edit', 'view', 'add', 'update', 'delete'...) * @return int<-1,1> For 'addreplace' hooks (doActions, formConfirm, formObjectOptions, pdf_xxx,...): Return 0 if we want to keep standard actions, >0 if we want to stop/replace standard actions, <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. * For 'output' hooks (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...): Return 0 if we want to keep standard actions, >0 uf we want to stop/replace standard actions (at least one > 0 and replacement will be done), <0 if KO. Things to print are returned into ->resprints and set into ->resPrint. Things to return are returned into ->results by hook and set into ->resArray for caller. @@ -309,7 +310,7 @@ class HookManager $actionclassinstance->errors = array(); if (getDolGlobalInt('MAIN_HOOK_DEBUG')) { - // This his too much verbose, enabled if const enabled only + // This is too verbose, enabled if const enabled only // False positive about id & element: @phan-suppress-next-line PhanUndeclaredProperty dol_syslog(get_class($this)."::executeHooks Qualified hook found (hooktype=".$hooktype."). We call method ".get_class($actionclassinstance).'->'.$method.", context=".$context.", module=".$module.", action=".$action.((is_object($object) && property_exists($object, 'id')) ? ', object id='.$object->id : '').((is_object($object) && property_exists($object, 'element')) ? ', object element='.$object->element : ''), LOG_DEBUG); } @@ -347,8 +348,8 @@ class HookManager } else { // Generic hooks that return a string or array (printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) - // TODO. this test should be done into the method of hook by returning nothing @phan-suppress-next-line PhanTypeInvalidDimOffset - if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) { + // TODO. this test should be done in the hook method by returning nothing @phan-suppress-next-line PhanTypeInvalidDimOffset,PhanUndeclaredProperty + if (is_array($parameters) && !empty($parameters['special_code']) && $parameters['special_code'] > 3 && (property_exists($actionclassinstance, 'module_number') && ($parameters['special_code'] != $actionclassinstance->module_number))) { continue; } diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 77c8eb3e137..8cd33589397 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -2995,8 +2995,8 @@ class Form //Price by customer if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) { $sql .= ', pcp.rowid as idprodcustprice, pcp.price as custprice, pcp.price_ttc as custprice_ttc,'; - $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref'; - $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref"; + $sql .= ' pcp.price_base_type as custprice_base_type, pcp.tva_tx as custtva_tx, pcp.default_vat_code as custdefault_vat_code, pcp.ref_customer as custref, pcp.discount_percent as custdiscount_percent'; + $selectFields .= ", idprodcustprice, custprice, custprice_ttc, custprice_base_type, custtva_tx, custdefault_vat_code, custref, custdiscount_percent"; } // Units if (getDolGlobalInt('PRODUCT_USE_UNITS')) { @@ -3047,7 +3047,20 @@ class Form //Price by customer if ((getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($socid)) { - $sql .= " LEFT JOIN " . $this->db->prefix() . "product_customer_price as pcp ON pcp.fk_soc=" . ((int) $socid) . " AND pcp.fk_product=p.rowid"; + $now = dol_now(); + $sql .= " LEFT JOIN ("; + $sql .= " SELECT pcp1.*"; + $sql .= " FROM " . $this->db->prefix() . "product_customer_price AS pcp1"; + $sql .= " LEFT JOIN ("; + $sql .= " SELECT fk_soc, fk_product, MIN(date_begin) AS date_begin"; + $sql .= " FROM " . $this->db->prefix() . "product_customer_price"; + $sql .= " WHERE fk_soc = " . ((int) $socid); + $sql .= " AND date_begin <= '" . $this->db->idate($now) . "'"; + $sql .= " AND (date_end IS NULL OR '" . $this->db->idate($now) . "' <= date_end)"; + $sql .= " GROUP BY fk_soc, fk_product"; + $sql .= " ) AS pcp2 ON pcp1.fk_soc = pcp2.fk_soc AND pcp1.fk_product = pcp2.fk_product AND pcp1.date_begin = pcp2.date_begin"; + $sql .= " WHERE pcp2.fk_soc IS NOT NULL"; + $sql .= " ) AS pcp ON pcp.fk_soc = " . ((int) $socid) . " AND pcp.fk_product = p.rowid"; } // Units if (getDolGlobalInt('PRODUCT_USE_UNITS')) { @@ -3588,6 +3601,7 @@ class Form $outpricebasetype = $objp->custprice_base_type; $outtva_tx = $objp->custtva_tx; $outdefault_vat_code = $objp->custdefault_vat_code; + $outdiscount = $objp->custdiscount_percent; } } diff --git a/htdocs/core/class/html.formwebsite.class.php b/htdocs/core/class/html.formwebsite.class.php index afea3d81e3c..1ce7e41cccc 100644 --- a/htdocs/core/class/html.formwebsite.class.php +++ b/htdocs/core/class/html.formwebsite.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -258,7 +258,7 @@ class FormWebsite * @param int<0,1> $showempty Show empty record * @param string $action Action on page that use this select list * @param string $morecss More CSS - * @param null|string[] $excludeids Exclude some ID in list + * @param ?array $excludeids Exclude some ID in list * @return string HTML select component with list of block containers */ public function selectContainer($website, $htmlname = 'pageid', $pageid = 0, $showempty = 0, $action = '', $morecss = 'minwidth200', $excludeids = null) diff --git a/htdocs/core/db/Database.interface.php b/htdocs/core/db/Database.interface.php index 046f8504722..d60fcde4962 100644 --- a/htdocs/core/db/Database.interface.php +++ b/htdocs/core/db/Database.interface.php @@ -5,7 +5,7 @@ * Copyright (C) 2006 Andre Cianfarani * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2014-2015 Raphaël Doursenaud - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -338,7 +338,7 @@ interface Database * Create a table into database * * @param string $table Name of table - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Associative table [field name][table of descriptions] + * @param array|string,position?:int,notnull?:int,visible?:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Associative table [field name][table of descriptions] * @param string $primary_key Name of the field that will be the primary key * @param string $type Type of the table * @param ?array $unique_keys Associative array Name of fields that will be unique key => value diff --git a/htdocs/core/db/mysqli.class.php b/htdocs/core/db/mysqli.class.php index 160805761bc..1d7d7c083cc 100644 --- a/htdocs/core/db/mysqli.class.php +++ b/htdocs/core/db/mysqli.class.php @@ -825,7 +825,7 @@ class DoliDBMysqli extends DoliDB * Create a table into database * * @param string $table Name of table - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Tableau associatif [nom champ][tableau des descriptions] + * @param array|string,position?:int,notnull?:int,visible?:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Tableau associatif [nom champ][tableau des descriptions] * @param string $primary_key Nom du champ qui sera la clef primaire * @param string $type Type de la table * @param ?array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php index 02288a05e21..9f7e0134397 100644 --- a/htdocs/core/db/pgsql.class.php +++ b/htdocs/core/db/pgsql.class.php @@ -1058,7 +1058,7 @@ class DoliDBPgsql extends DoliDB * Create a table into database * * @param string $table Nom de la table - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Tableau associatif [nom champ][tableau des descriptions] + * @param array|string,position?:int,notnull?:int,visible?:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Tableau associatif [nom champ][tableau des descriptions] * @param string $primary_key Nom du champ qui sera la clef primaire * @param string $type Type de la table * @param ?array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php index e10cda471b0..3f44a73de5d 100644 --- a/htdocs/core/db/sqlite3.class.php +++ b/htdocs/core/db/sqlite3.class.php @@ -5,7 +5,7 @@ * Copyright (C) 2006 Andre Cianfarani * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2015 Raphaël Doursenaud - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -966,7 +966,7 @@ class DoliDBSqlite3 extends DoliDB * Create a table into database * * @param string $table Nom de la table - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>,value?:string,attribute?:string,null?:string,extra?:string}> $fields Tableau associatif [nom champ][tableau des descriptions] + * @param array|string,position?:int,notnull?:int,visible?:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>,value?:string,attribute?:string,null?:string,extra?:string}> $fields Tableau associatif [nom champ][tableau des descriptions] * @param string $primary_key Nom du champ qui sera la clef primaire * @param string $type Type de la table * @param ?array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 7d9beb89411..690e1e2c106 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -4,7 +4,7 @@ * Copyright (C) 2012 J. Fernando Lagrange * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2023 Eric Seigne - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -1380,7 +1380,7 @@ function unActivateModule($value, $requiredby = 1) * @param string[] $tabrowid Tabrowid * @param bool[] $tabcond Tabcond * @param array> $tabhelp Tabhelp - * @param array>> $tabcomplete Tab complete (will replace all other in future). Key is table name. + * @param array>> $tabcomplete Tab complete (will replace all other in future). Key is table name. * @return int 1 */ function complete_dictionary_with_modules(&$taborder, &$tabname, &$tablib, &$tabsql, &$tabsqlsort, &$tabfield, &$tabfieldvalue, &$tabfieldinsert, &$tabrowid, &$tabcond, &$tabhelp, &$tabcomplete) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 93e275787e8..a77ac94e92b 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -6,7 +6,7 @@ * Copyright (C) 2016 Raphaël Doursenaud * Copyright (C) 2019-2024 Frédéric France * Copyright (C) 2023 Lenin Rivas - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -685,7 +685,7 @@ function dol_fileperm($pathoffile) * Make replacement of strings into a file. * * @param string $srcfile Source file (can't be a directory) - * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) + * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. * @param string $newmask Mask for new file. '0' by default means getDolGlobalString('MAIN_UMASK'). Example: '0666'. * @param int $indexdatabase 1=index new file into database. diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index b102c45408c..f5ed6cac0ba 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1180,7 +1180,9 @@ function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto', $saverestore = '') $minute = intval($m[2]); $second = intval($m[3]); } elseif ($hourTime === 'end') { - $hour = 23; $minute = 59; $second = 59; + $hour = 23; + $minute = 59; + $second = 59; } else { $hour = $minute = $second = 0; } @@ -2432,7 +2434,7 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = if (!array_key_exists($level, $logLevels)) { dol_syslog('Error Bad Log Level '.$level, LOG_ERR); - $level = $logLevels[LOG_ERR]; + $level = LOG_ERR; } if ($level > getDolGlobalInt('SYSLOG_LEVEL')) { return; @@ -2461,12 +2463,12 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = $data = array( 'message' => $message, - 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false), + 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : ''), 'level' => $level, - 'user' => ((is_object($user) && $user->id) ? $user->login : false), - 'ip' => false, - 'osuser' => function_exists('posix_getuid') ? posix_getuid() : false, - 'ospid' => getmypid() // on linux, max value is defined into cat /proc/sys/kernel/pid_max + 'user' => ((is_object($user) && $user->id) ? $user->login : ''), + 'ip' => '', + 'osuser' => function_exists('posix_getuid') ? (string) posix_getuid() : '', + 'ospid' => (string) getmypid() // on linux, max value is defined into cat /proc/sys/kernel/pid_max ); $remoteip = getUserRemoteIP(); // Get ip when page run on a web server @@ -2480,20 +2482,20 @@ function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = } } elseif (!empty($_SERVER['SERVER_ADDR'])) { // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache) - $data['ip'] = $_SERVER['SERVER_ADDR']; + $data['ip'] = (string) $_SERVER['SERVER_ADDR']; } elseif (!empty($_SERVER['COMPUTERNAME'])) { // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defines it). - $data['ip'] = $_SERVER['COMPUTERNAME']; + $data['ip'] = (string) $_SERVER['COMPUTERNAME']; } else { $data['ip'] = '???'; } if (!empty($_SERVER['USERNAME'])) { // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but useful if OS defines it). - $data['osuser'] = $_SERVER['USERNAME']; + $data['osuser'] = (string) $_SERVER['USERNAME']; } elseif (!empty($_SERVER['LOGNAME'])) { // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but useful if OS defines it). - $data['osuser'] = $_SERVER['LOGNAME']; + $data['osuser'] = (string) $_SERVER['LOGNAME']; } // Loop on each log handler and send output @@ -3149,7 +3151,7 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi } } } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo' or 'memberphoto' - $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos); + $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0); } if ($phototoshow) { @@ -3211,12 +3213,14 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi $morehtmlstatus .= ''.$object->getLibStatut(6, 1).''; } } elseif (in_array($object->element, array('salary'))) { + '@phan-var-force Salary $object'; $tmptxt = $object->getLibStatut(6, $object->alreadypaid); if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) { $tmptxt = $object->getLibStatut(5, $object->alreadypaid); } $morehtmlstatus .= $tmptxt; } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid + '@phan-var-force Facture|FactureFournisseur|CommonInvoice $object'; $totalallpayments = $object->getSommePaiement(0); $totalallpayments += $object->getSumCreditNotesUsed(0); $totalallpayments += $object->getSumDepositsUsed(0); @@ -3226,6 +3230,7 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi } $morehtmlstatus .= $tmptxt; } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid + '@phan-var-force ChargeSociales|Loan|Tva $object'; $tmptxt = $object->getLibStatut(6, $object->totalpaid); if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) { $tmptxt = $object->getLibStatut(5, $object->totalpaid); @@ -4769,9 +4774,9 @@ function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $char } if (empty($reshook)) { if (empty($charfornl)) { - $out .= nl2br($address); + $out .= nl2br((string) $address); } else { - $out .= preg_replace('/[\r\n]+/', $charfornl, $address); + $out .= preg_replace('/[\r\n]+/', $charfornl, (string) $address); } // TODO Remove this block, we can add this using the hook now @@ -6412,9 +6417,9 @@ function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin } else { $tmptooltip = array($tooltip); } - $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), (empty($tmptooltip[2]) ? 1 : $tmptooltip[2]), 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1])); + $out .= $form->textwithpicto($langs->trans((string) $name), $langs->trans($tmptooltip[0]), (empty($tmptooltip[2]) ? '1' : $tmptooltip[2]), 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1])); } else { - $out .= $langs->trans($name); + $out .= $langs->trans((string) $name); } if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field @@ -7188,7 +7193,7 @@ function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round * @param int $local Local tax to search and return (1 or 2 return only tax rate 1 or tax rate 2) * @param ?Societe $thirdparty_buyer Object of buying third party * @param ?Societe $thirdparty_seller Object of selling third party ($mysoc if not defined) - * @param int $vatnpr If vat rate is NPR or not + * @param int<0,1> $vatnpr If vat rate is NPR or not * @return int<0,0>|string 0 if not found, localtax rate if found (Can be '20', '-19:-15:-9') * @see get_default_tva() */ @@ -7298,7 +7303,7 @@ function get_localtax($vatrate, $local, $thirdparty_buyer = null, $thirdparty_se if (!empty($vatratecode)) { $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority } else { - $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'"; + $sql .= " AND t.recuperableonly = '".$db->escape((string) $vatnpr)."'"; } $resql = $db->query($sql); @@ -7545,7 +7550,7 @@ function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournpric ) { // If country of thirdparty to consider is ours if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object - $result = $product->get_buyprice($idprodfournprice, 0, 0, 0); + $result = $product->get_buyprice($idprodfournprice, 0, 0, ''); if ($result > 0) { $ret = $product->vatrate_supplier; if ($product->default_vat_code_supplier) { @@ -10152,7 +10157,7 @@ function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $no dol_print_error(null, 'Bad parameter style='.$style.' for setEventMessages'); } if (empty($mesgs)) { - setEventMessage($mesg, $style, $noduplicate, $attop); + setEventMessage((string) $mesg, $style, $noduplicate, $attop); } else { if (!empty($mesg) && !in_array($mesg, $mesgs)) { setEventMessage($mesg, $style, $noduplicate, $attop); // Add message string if not already into array @@ -10674,14 +10679,14 @@ function dol_eval_new($s) { // Only this global variables can be read by eval function and returned to caller global $conf, // Read of const is done with getDolGlobalString() but we need $conf->currency for example - $db, $langs, $user, $website, $websitepage, - $action, $mainmenu, $leftmenu, - $mysoc, - $objectoffield, // To allow the use of $objectoffield in computed fields + $db, $langs, $user, $website, $websitepage, + $action, $mainmenu, $leftmenu, + $mysoc, + $objectoffield, // To allow the use of $objectoffield in computed fields - // Old variables used - $object, - $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object + // Old variables used + $object, + $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object // PHP < 7.4.0 defined('T_COALESCE_EQUAL') || define('T_COALESCE_EQUAL', PHP_INT_MAX); @@ -11870,10 +11875,23 @@ function dolExplodeKeepIfQuotes($input) preg_match_all('/"([^"]*)"|\'([^\']*)\'|(\S+)/', $input, $matches); // Merge result and delete empty values - // @phan-suppress-next-line PhanPluginUnknownClosureParamType, PhanPluginUnknownClosureReturnType - return array_filter(array_map(function ($a, $b, $c) { - return $a ?: ($b ?: $c); - }, $matches[1], $matches[2], $matches[3])); + return array_filter(array_map( + /** + * Return first non-empty item, or empty string + * + * @param string $a Possibly empty item - match "" + * @param string $b Possibly empty item - match '' + * @param string $c Non empty string if $a and $b are empty + * + * @return string + */ + static function ($a, $b, $c) { + return $a ?: ($b ?: $c); + }, + $matches[1], + $matches[2], + $matches[3] + )); } @@ -12901,7 +12919,7 @@ function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $st } else { // If a title was forced from $params['badgeParams']['attr']['title'], we set the class to get it as a tooltip. $dolGetBadgeParams['attr']['class'] .= ' classfortooltip'; // And if we use tooltip, we can output title in HTML @phan-suppress-next-line PhanTypeInvalidDimOffset - $dolGetBadgeParams['attr']['title'] = dol_htmlentitiesbr($dolGetBadgeParams['attr']['title'], 1); + $dolGetBadgeParams['attr']['title'] = dol_htmlentitiesbr((string) $dolGetBadgeParams['attr']['title'], 1); } if ($displayMode == 3) { diff --git a/htdocs/core/lib/modulebuilder.lib.php b/htdocs/core/lib/modulebuilder.lib.php index 67d57193729..eb7cfa1ad56 100644 --- a/htdocs/core/lib/modulebuilder.lib.php +++ b/htdocs/core/lib/modulebuilder.lib.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -143,10 +143,10 @@ function rebuildObjectClass($destdir, $module, $objectname, $newmask, $readdir = $texttoinsert .= " 'notnull' => ".(empty($val['notnull']) ? 0 : (int) $val['notnull']).","; $texttoinsert .= ' "visible" => "'.($val['visible'] !== '' ? dol_escape_js($val['visible']) : -1).'",'; if (!empty($val['noteditable'])) { - $texttoinsert .= ' "noteditable" => "'.dol_escape_php($val['noteditable']).'",'; + $texttoinsert .= ' "noteditable" => "'.dol_escape_php((string) $val['noteditable']).'",'; } if (!empty($val['alwayseditable'])) { - $texttoinsert .= ' "alwayseditable" => "'.dol_escape_php($val['alwayseditable']).'",'; + $texttoinsert .= ' "alwayseditable" => "'.dol_escape_php((string) $val['alwayseditable']).'",'; } if (array_key_exists('default', $val) && (!empty($val['default']) || $val['default'] === '0')) { $texttoinsert .= ' "default" => "'.dol_escape_php($val['default']).'",'; @@ -555,7 +555,7 @@ function deletePerms($file) * @param int|string $a value 1 * @param int|string $b value 2 * @return int<-1,1> <=0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal. -*/ + */ function compareFirstValue($a, $b) { return strcmp($a[0], $b[0]); diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 4b11ccc758d..8a2fdc2f978 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -1747,9 +1747,18 @@ function pdf_getlinedesc($object, $i, $outputlangs, $hideref = 0, $hidedesc = 0, $nbCustomerPrices = $productCustomerPriceStatic->fetchAll('', '', 1, 0, $filter); if ($nbCustomerPrices > 0) { - $productCustomerPrice = $productCustomerPriceStatic->lines[0]; + $productCustomerPrice = null; + if (count($productCustomerPriceStatic->lines) > 0) { + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($productCustomerPriceStatic->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $productCustomerPrice = $custprice_line; + break; + } + } + } - if (!empty($productCustomerPrice->ref_customer)) { + if (isset($productCustomerPrice) && !empty($productCustomerPrice->ref_customer)) { switch ($conf->global->PRODUIT_CUSTOMER_PRICES_PDF_REF_MODE) { case 1: $ref_prodserv = $productCustomerPrice->ref_customer; diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index ae13e84ebe6..1590d5a0bf4 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -1,7 +1,7 @@ * Copyright (C) 2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -530,7 +530,7 @@ function redirectToContainer($containerref, $containeraliasalt = '', $containeri include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; $tmpwebsitepage = new WebsitePage($db); // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - $result = $tmpwebsitepage->fetch(0, $website->id, '', $containeraliasalt); + $result = $tmpwebsitepage->fetch(0, (string) $website->id, '', $containeraliasalt); if ($result > 0) { $containerref = $tmpwebsitepage->pageurl; } else { @@ -554,7 +554,7 @@ function redirectToContainer($containerref, $containeraliasalt = '', $containeri include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; $tmpwebsitepage = new WebsitePage($db); // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - $result = $tmpwebsitepage->fetch(0, $website->id, $containerref); + $result = $tmpwebsitepage->fetch(0, (string) $website->id, $containerref); unset($tmpwebsitepage); } if ($result > 0) { @@ -622,7 +622,7 @@ function includeContainer($containerref, $once = 0, $cachedelay = 0, $cachekey = $fullpathcache = ''; // If we ask to use the cache delay if ($cachedelay > 0 && !getDolGlobalString("WEBSITE_DISABLE_CACHE_OF_CONTAINERS")) { - $fullpathcache = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/temp/'.$websitekey.'-'.$websitepage->id.'-'.$containerref.($cachekey ? '-'.$cachekey: '').'.cache'; + $fullpathcache = DOL_DATA_ROOT.($conf->entity > 1 ? '/'.$conf->entity : '').'/website/temp/'.$websitekey.'-'.$websitepage->id.'-'.$containerref.($cachekey ? '-'.$cachekey : '').'.cache'; } if (empty($includehtmlcontentopened)) { @@ -638,7 +638,7 @@ function includeContainer($containerref, $once = 0, $cachedelay = 0, $cachekey = // We don't print info messages for pages of type library or service if (!empty($websitepage->type_container) && !in_array($websitepage->type_container, array('library', 'service'))) { - print "\n".''."\n"; + print "\n".''."\n"; } $tmpoutput = ''; diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 6e5c0fddea4..0a30d577bbb 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -8,7 +8,7 @@ * Copyright (C) 2014 Raphaël Doursenaud * Copyright (C) 2018 Josep Lluís Amador * Copyright (C) 2019-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -208,13 +208,13 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it /** * Module last version - * @var string $lastVersion + * @var string */ public $lastVersion = ''; /** * true indicate this module need update - * @var bool $needUpdate + * @var bool */ public $needUpdate = false; @@ -427,7 +427,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it * Another example : array('always'=>array("modBanque", "modFacture", "modProduct", "modCategorie"), 'FR'=>array('modBlockedLog')); * Note: Example in modTakePos: array('always'=>array("modBanque", "modFacture", "modProduct", "modCategorie"), 'FR'=>array('modBlockedLog')); * Example in modAccounting: array("modFacture", "modBanque", "modTax"); - + * * @see $requiredby */ public $depends; @@ -528,7 +528,7 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it * Enables a module. * Inserts all information into database. * - * @param array}>|array $array_sql SQL requests to be executed when enabling module + * @param array}>|string[] $array_sql SQL requests to be executed when enabling module * @param string $options String with options when disabling module: * - 'noboxes' = Do all actions but do not insert boxes * - 'newboxdefonly' = Do all actions but for boxes, insert def of boxes only and not boxes activation diff --git a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php index 0c16ff7e5f6..705bf58ac5b 100644 --- a/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_espadon.modules.php @@ -730,6 +730,17 @@ class pdf_espadon extends ModelePdfExpedition } } + $parameters = array( + 'object' => $object, + 'i' => $i, + 'pdf' => & $pdf, + 'curY' => & $curY, + 'nexY' => & $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook = $hookmanager->executeHooks('printPDFline', $parameters, $this); + // Add line if (getDolGlobalString('MAIN_PDF_DASH_BETWEEN_LINES') && $i < ($nblines - 1)) { $pdf->setPage($pageposafter); diff --git a/htdocs/core/modules/facture/doc/pdf_octopus.modules.php b/htdocs/core/modules/facture/doc/pdf_octopus.modules.php index 792d86938fc..cf5e3aa55f2 100644 --- a/htdocs/core/modules/facture/doc/pdf_octopus.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_octopus.modules.php @@ -241,6 +241,7 @@ class pdf_octopus extends ModelePDFFactures $this->atleastonediscount = 0; $this->situationinvoice = true; if (!empty($object)) { + '@phan-var-force Facture $object'; // Supposing $object is Facture; $this->TDataSituation = $this->getDataSituation($object); } else { dol_syslog("object is empty, do not call getDataSituation..."); diff --git a/htdocs/core/modules/modProduct.class.php b/htdocs/core/modules/modProduct.class.php index 166cf89dd38..b2ff61b9e58 100644 --- a/htdocs/core/modules/modProduct.class.php +++ b/htdocs/core/modules/modProduct.class.php @@ -380,11 +380,14 @@ class modProduct extends DolibarrModules $this->export_fields_array[$r] = array('p.rowid' => "Id", 'p.ref' => "Ref", 'p.label' => "Label", 's.nom' => 'ThirdParty', 's.code_client' => 'CodeClient', + 'pr.date_begin' => "AppliedPricesFrom", + 'pr.date_end' => "AppliedPricesTo", 'pr.price_base_type' => "PriceBase", 'pr.price' => "PriceUnitPriceHT", 'pr.price_ttc' => "PriceUnitPriceTTC", 'pr.price_min' => "MinPriceUnitPriceHT", 'pr.price_min_ttc' => "MinPriceUnitPriceTTC", 'pr.tva_tx' => 'PriceVATRate', 'pr.default_vat_code' => 'PriceVATCode', + 'pr.discount_percent' => 'Discount', 'pr.datec' => 'DateCreation'); if (is_object($mysoc) && $usenpr) { $this->export_fields_array[$r]['pr.recuperableonly'] = 'NPR'; @@ -392,11 +395,14 @@ class modProduct extends DolibarrModules $this->export_entities_array[$r] = array('p.rowid' => "product", 'p.ref' => "product", 'p.label' => "Label", 's.nom' => 'company', 's.code_client' => 'company', + 'pr.date_begin' => "product", + 'pr.date_end' => "product", 'pr.price_base_type' => "product", 'pr.price' => "product", 'pr.price_ttc' => "product", 'pr.price_min' => "product", 'pr.price_min_ttc' => "product", 'pr.tva_tx' => 'product', 'pr.default_vat_code' => 'product', + 'pr.discount_percent' => 'product', 'pr.recuperableonly' => 'product', 'pr.datec' => "product"); $this->export_sql_start[$r] = 'SELECT DISTINCT '; diff --git a/htdocs/core/modules/modService.class.php b/htdocs/core/modules/modService.class.php index b93531bdd6e..f4b7592eb13 100644 --- a/htdocs/core/modules/modService.class.php +++ b/htdocs/core/modules/modService.class.php @@ -327,22 +327,28 @@ class modService extends DolibarrModules $this->export_permission[$r] = array(array("service", "export")); $this->export_fields_array[$r] = array('p.rowid' => "Id", 'p.ref' => "Ref", 's.nom' => 'ThirdParty', + 'pr.date_begin' => "AppliedPricesFrom", + 'pr.date_end' => "AppliedPricesTo", 'pr.price_base_type' => "PriceBase", 'pr.price' => "PriceUnitPriceHT", 'pr.price_ttc' => "PriceUnitPriceTTC", 'pr.price_min' => "MinPriceUnitPriceHT", 'pr.price_min_ttc' => "MinPriceUnitPriceTTC", 'pr.tva_tx' => 'PriceVATRate', 'pr.default_vat_code' => 'PriceVATCode', + 'pr.discount_percent' => 'Discount', 'pr.datec' => 'DateCreation'); if (is_object($mysoc) && $usenpr) { $this->export_fields_array[$r]['pr.recuperableonly'] = 'NPR'; } $this->export_entities_array[$r] = array('p.rowid' => "product", 'p.ref' => "product", 's.nom' => 'company', + 'pr.date_begin' => "product", + 'pr.date_end' => "product", 'pr.price_base_type' => "product", 'pr.price' => "product", 'pr.price_ttc' => "product", 'pr.price_min' => "product", 'pr.price_min_ttc' => "product", 'pr.tva_tx' => 'product', 'pr.default_vat_code' => 'product', + 'pr.discount_percent' => 'product', 'pr.recuperableonly' => 'product', 'pr.datec' => "product"); $this->export_sql_start[$r] = 'SELECT DISTINCT '; diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index df96090135a..fa0044433ac 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -938,6 +938,13 @@ if (!empty($usemargins) && $user->hasRight('margins', 'creer')) { $('#tva_tx option[value="'+stringforvatrateselection+'"]').prop('selected', true); socid)) { + ?> + $("#remise_percent").val(data.discount); + var proddesc = data.desc_trans; diff --git a/htdocs/debugbar/class/TraceableDB.php b/htdocs/debugbar/class/TraceableDB.php index a7b45a7da6b..577abd4dd3a 100644 --- a/htdocs/debugbar/class/TraceableDB.php +++ b/htdocs/debugbar/class/TraceableDB.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -496,7 +496,7 @@ class TraceableDB extends DoliDB * Create a table into database * * @param string $table Name of table - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Associative table [field name][table of descriptions] + * @param array|string,position?:int,notnull?:int,visible?:int<-2,5>|string,alwayseditable?:int<0,1>,noteditable?:int<0,1>,default?:string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,autofocusoncreate?:int<0,1>,comment?:string,copytoclipboard?:int<1,2>,validate?:int<0,1>}> $fields Associative table [field name][table of descriptions] * @param string $primary_key Nom du champ qui sera la clef primaire * @param string $type Type de la table * @param ?array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur diff --git a/htdocs/install/mysql/data/llx_00_c_country.sql b/htdocs/install/mysql/data/llx_00_c_country.sql index 829d6ffe8cb..e0f0f2e4caf 100644 --- a/htdocs/install/mysql/data/llx_00_c_country.sql +++ b/htdocs/install/mysql/data/llx_00_c_country.sql @@ -532,8 +532,8 @@ UPDATE llx_c_country SET numeric_code = '716' WHERE code_iso = 'ZWE'; -- Set field eec -UPDATE llx_c_country SET eec = 1 WHERE code IN ('AT','BE','BG','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','NL','HU','IE','IT','LT','LU','LV','MC','MT','PL','PT','RO','SE','SK','SI'); - - +UPDATE llx_c_country SET eec = 1 WHERE code IN ('AT','BE','BG','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MC','MT','NL','PL','PT','RO','SE','SI','SK'); +-- Set field sepa +UPDATE llx_c_country SET sepa = 1 WHERE code IN ('AD','AT','BE','BG','CH','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MC','MT','NL','PL','PT','RO','SE','SI','SK','SM','VA'); diff --git a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql index f4a86314771..25b303514d6 100644 --- a/htdocs/install/mysql/migration/21.0.0-22.0.0.sql +++ b/htdocs/install/mysql/migration/21.0.0-22.0.0.sql @@ -44,8 +44,7 @@ ALTER TABLE llx_societe_account ADD UNIQUE INDEX uk_societe_account_login_websit -- V22 migration ALTER TABLE llx_c_country ADD COLUMN sepa tinyint DEFAULT 0 NOT NULL; - -UPDATE llx_c_country SET sepa = 1 WHERE sepa = 0 AND eec = 1; +UPDATE llx_c_country SET sepa = 1 WHERE code IN ('AD','AT','BE','BG','CH','CY','CZ','DE','DK','EE','ES','FI','FR','GR','HR','HU','IE','IT','LT','LU','LV','MC','MT','NL','PL','PT','RO','SE','SI','SK','SM','VA'); -- fix element UPDATE llx_c_type_contact set element='shipping' WHERE element='expedition'; @@ -179,3 +178,17 @@ ALTER TABLE llx_supplier_proposaldet ADD COLUMN extraparams varchar(255); ALTER TABLE llx_facture_rec ADD COLUMN rule_for_lines_dates varchar(255) DEFAULT 'prepaid'; +ALTER TABLE llx_product_customer_price ADD COLUMN date_begin date AFTER ref_customer; +ALTER TABLE llx_product_customer_price ADD COLUMN date_end date AFTER date_begin; +ALTER TABLE llx_product_customer_price ADD COLUMN discount_percent real DEFAULT 0 AFTER localtax2_type; +ALTER TABLE llx_product_customer_price_log ADD COLUMN date_begin date AFTER ref_customer; +ALTER TABLE llx_product_customer_price_log ADD COLUMN date_end date AFTER date_begin; +ALTER TABLE llx_product_customer_price_log ADD COLUMN discount_percent real DEFAULT 0 AFTER localtax2_type; +ALTER TABLE llx_product_customer_price DROP CONSTRAINT fk_product_customer_price_fk_product; +ALTER TABLE llx_product_customer_price DROP CONSTRAINT fk_product_customer_price_fk_soc; +ALTER TABLE llx_product_customer_price DROP INDEX uk_customer_price_fk_product_fk_soc; +ALTER TABLE llx_product_customer_price ADD UNIQUE INDEX uk_customer_price_fk_product_fk_soc (fk_product, fk_soc, date_begin); +ALTER TABLE llx_product_customer_price ADD CONSTRAINT fk_product_customer_price_fk_product FOREIGN KEY (fk_product) REFERENCES llx_product(rowid); +ALTER TABLE llx_product_customer_price ADD CONSTRAINT fk_product_customer_price_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe(rowid); +UPDATE llx_product_customer_price SET date_begin = datec WHERE date_begin IS NULL; +UPDATE llx_product_customer_price_log SET date_begin = datec WHERE date_begin IS NULL; diff --git a/htdocs/install/mysql/tables/llx_product_customer_price.key.sql b/htdocs/install/mysql/tables/llx_product_customer_price.key.sql index 2b827740b60..afb43008569 100644 --- a/htdocs/install/mysql/tables/llx_product_customer_price.key.sql +++ b/htdocs/install/mysql/tables/llx_product_customer_price.key.sql @@ -20,7 +20,7 @@ ALTER TABLE llx_product_customer_price ADD INDEX idx_product_customer_price_fk_user (fk_user); ALTER TABLE llx_product_customer_price ADD INDEX idx_product_customer_price_fk_soc (fk_soc); -ALTER TABLE llx_product_customer_price ADD UNIQUE INDEX uk_customer_price_fk_product_fk_soc (fk_product, fk_soc); +ALTER TABLE llx_product_customer_price ADD UNIQUE INDEX uk_customer_price_fk_product_fk_soc (fk_product, fk_soc, date_begin); ALTER TABLE llx_product_customer_price ADD CONSTRAINT fk_product_customer_price_fk_user FOREIGN KEY (fk_user) REFERENCES llx_user (rowid); ALTER TABLE llx_product_customer_price ADD CONSTRAINT fk_product_customer_price_fk_product FOREIGN KEY (fk_product) REFERENCES llx_product(rowid); diff --git a/htdocs/install/mysql/tables/llx_product_customer_price.sql b/htdocs/install/mysql/tables/llx_product_customer_price.sql index bc25a0f0b2d..04757667cad 100644 --- a/htdocs/install/mysql/tables/llx_product_customer_price.sql +++ b/htdocs/install/mysql/tables/llx_product_customer_price.sql @@ -29,6 +29,8 @@ create table llx_product_customer_price fk_product integer NOT NULL, fk_soc integer NOT NULL, ref_customer varchar(128), + date_begin date, + date_end date, price double(24,8) DEFAULT 0, price_ttc double(24,8) DEFAULT 0, price_min double(24,8) DEFAULT 0, @@ -41,6 +43,7 @@ create table llx_product_customer_price localtax1_type varchar(10) NOT NULL DEFAULT '0', localtax2_tx double(7,4) DEFAULT 0, -- Other local VAT 2 localtax2_type varchar(10) NOT NULL DEFAULT '0', + discount_percent real DEFAULT 0, fk_user integer, price_label varchar(255), import_key varchar(14) -- Import key diff --git a/htdocs/install/mysql/tables/llx_product_customer_price_log.sql b/htdocs/install/mysql/tables/llx_product_customer_price_log.sql index 43f70f4f984..e7761bc022e 100644 --- a/htdocs/install/mysql/tables/llx_product_customer_price_log.sql +++ b/htdocs/install/mysql/tables/llx_product_customer_price_log.sql @@ -28,6 +28,8 @@ create table llx_product_customer_price_log fk_product integer NOT NULL, fk_soc integer DEFAULT 0 NOT NULL, ref_customer varchar(30), + date_begin date, + date_end date, price double(24,8) DEFAULT 0, price_ttc double(24,8) DEFAULT 0, price_min double(24,8) DEFAULT 0, @@ -40,6 +42,7 @@ create table llx_product_customer_price_log localtax1_type varchar(10) NOT NULL DEFAULT '0', localtax2_tx double(7,4) DEFAULT 0, -- Other local VAT 2 localtax2_type varchar(10) NOT NULL DEFAULT '0', + discount_percent real DEFAULT 0, fk_user integer, price_label varchar(255), import_key varchar(14) -- Import key diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 84cfffe0780..23636fb9779 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -69,6 +69,8 @@ UpdateVAT=Update VAT UpdateDefaultPrice=Update default price UpdateLevelPrices=Update prices for each level AppliedPricesFrom=Applied from +AppliedPricesTo=Applied to +ErrorAppliedPricesIntersectAnotherPeriod=The begin or end date intersect to another existing period. SellingPrice=Selling price SellingPriceHT=Selling price (excl. tax) SellingPriceTTC=Selling price (inc. tax) diff --git a/htdocs/langs/en_US/salaries.lang b/htdocs/langs/en_US/salaries.lang index 2987021be4e..570242b8386 100644 --- a/htdocs/langs/en_US/salaries.lang +++ b/htdocs/langs/en_US/salaries.lang @@ -31,5 +31,9 @@ MakeTransferRequest=Make transfer request VirementOrder=Credit transfer request WithdrawalReceipt=Credit transfer order OrderWaiting=Pending order -FillEndOfMonth=Fill with end of month +FillEndOfMonth=End of month +PreviousMonthShort=PrevMonth +CurrentMonthShort=CurrMonth +PreviousWeekShort=PrevWeek +CurrentWeekShort=CurrWeek UserPaySlip=Pay Slip diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang index 0b5954b3394..53734c04008 100644 --- a/htdocs/langs/fr_FR/products.lang +++ b/htdocs/langs/fr_FR/products.lang @@ -69,6 +69,8 @@ UpdateVAT=Mettre à jour la TVA UpdateDefaultPrice=Modifier prix par défaut UpdateLevelPrices=Modifier prix pour chaque niveau AppliedPricesFrom=Pratiqués à partir du +AppliedPricesTo=Pratiqués jusqu'au +ErrorAppliedPricesIntersectAnotherPeriod=La date de début ou de fin rentre en conflit avec une période de dates existante. SellingPrice=Prix de vente SellingPriceHT=Prix de vente HT SellingPriceTTC=Prix de vente TTC diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php index a947d497024..630ee86f467 100644 --- a/htdocs/modulebuilder/index.php +++ b/htdocs/modulebuilder/index.php @@ -66,7 +66,7 @@ $cancel = GETPOST('cancel', 'alpha'); $sortfield = GETPOST('sortfield', 'alpha'); $sortorder = GETPOST('sortorder', 'aZ09'); -$module = GETPOST('module', 'alpha'); +$module = (string) GETPOST('module', 'alpha'); $tab = (string) GETPOST('tab', 'aZ09'); $tabobj = GETPOST('tabobj', 'alpha'); $tabdic = GETPOST('tabdic', 'alpha'); @@ -90,12 +90,12 @@ $find = GETPOST('find', 'alpha'); $modulename = dol_sanitizeFileName(GETPOST('modulename', 'alpha')); $objectname = dol_sanitizeFileName(GETPOST('objectname', 'alpha')); $dicname = dol_sanitizeFileName(GETPOST('dicname', 'alpha')); -$editorname = GETPOST('editorname', 'alpha'); -$editorurl = GETPOST('editorurl', 'alpha'); -$version = GETPOST('version', 'alpha'); -$family = GETPOST('family', 'alpha'); -$picto = GETPOST('idpicto', 'alpha'); -$idmodule = GETPOST('idmodule', 'alpha'); +$editorname = (string) GETPOST('editorname', 'alpha'); +$editorurl = (string) GETPOST('editorurl', 'alpha'); +$version = (string) GETPOST('version', 'alpha'); +$family = (string) GETPOST('family', 'alpha'); +$picto = (string) GETPOST('idpicto', 'alpha'); +$idmodule = (string) GETPOST('idmodule', 'alpha'); $format = ''; // Prevent undefined in css tab // Security check @@ -418,7 +418,7 @@ if ($dirins && $action == 'initmodule' && $modulename && $user->hasRight("module } // @phan-suppress-next-line PhanPluginSuspiciousParamPosition - $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); + $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); // @phpstan-ignore-line //var_dump($result); if ($result < 0) { setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors'); @@ -1655,7 +1655,7 @@ if ($dirins && $action == 'initobject' && $module && $objectname && $user->hasRi $arrayreplacement['---Replace with your own copyright and developer email---'] = dol_print_date($now, '%Y').' ' . getDolGlobalString('MODULEBUILDER_SPECIFIC_AUTHOR'); } - $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); + $result = dolReplaceInFile($phpfileval['fullname'], $arrayreplacement); // @phpstan-ignore-line //var_dump($result); if ($result < 0) { setEventMessages($langs->trans("ErrorFailToMakeReplacementInto", $phpfileval['fullname']), null, 'errors'); @@ -3297,7 +3297,7 @@ $h++; $linktoenabledisable = ''; -if (is_array($listofmodules) && count($listofmodules) > 0) { +if (/* is_array($listofmodules) && */ count($listofmodules) > 0) { // Define $linktoenabledisable $modulelowercase = strtolower($module); diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index 274de7cce07..85e9a6fcfc5 100644 --- a/htdocs/product/ajax/products.php +++ b/htdocs/product/ajax/products.php @@ -220,13 +220,20 @@ if ($action == 'fetch' && !empty($id)) { $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result) { if (count($prodcustprice->lines) > 0) { - $found = true; - $outprice_ht = price($prodcustprice->lines[0]->price); - $outprice_ttc = price($prodcustprice->lines[0]->price_ttc); - $outpricebasetype = $prodcustprice->lines[0]->price_base_type; - $outtva_tx_formated = price($prodcustprice->lines[0]->tva_tx); - $outtva_tx = price2num($prodcustprice->lines[0]->tva_tx); - $outdefault_vat_code = $prodcustprice->lines[0]->default_vat_code; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $found = true; + $outprice_ht = price($custprice_line->price); + $outprice_ttc = price($custprice_line->price_ttc); + $outpricebasetype = $custprice_line->price_base_type; + $outtva_tx_formated = price($custprice_line->tva_tx); + $outtva_tx = price2num($custprice_line->tva_tx); + $outdefault_vat_code = $custprice_line->default_vat_code; + $outdiscount = $custprice_line->discount_percent; + break; + } + } } } } diff --git a/htdocs/product/card.php b/htdocs/product/card.php index f685f012a5b..63bf5565aed 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1156,10 +1156,16 @@ if (empty($reshook)) { $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result) { if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines [0]->price); - $pu_ttc = price($prodcustprice->lines [0]->price_ttc); - $price_base_type = $prodcustprice->lines [0]->price_base_type; - $tva_tx = $prodcustprice->lines [0]->tva_tx; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pu_ht = price($custprice_line->price); + $pu_ttc = price($custprice_line->price_ttc); + $price_base_type = $custprice_line->price_base_type; + $tva_tx = $custprice_line->tva_tx; + break; + } + } } } } diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index b7d714b1722..88ab82da615 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2354,18 +2354,24 @@ class Product extends CommonObject $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result) { if (count($prodcustprice->lines) > 0) { - $pricebycustomerexist = true; - $pu_ht = price($prodcustprice->lines[0]->price); - $price_min = price($prodcustprice->lines[0]->price_min); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - $tva_tx = $prodcustprice->lines[0]->tva_tx; - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; - } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pricebycustomerexist = true; + $pu_ht = price($custprice_line->price); + $price_min = price($custprice_line->price_min); + $pu_ttc = price($custprice_line->price_ttc); + $price_base_type = $custprice_line->price_base_type; + $tva_tx = $custprice_line->tva_tx; + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' (' . $custprice_line->default_vat_code . ')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + } + break; + } } } } @@ -2415,17 +2421,23 @@ class Product extends CommonObject $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result) { if (count($prodcustprice->lines) > 0) { - $pu_ht = price($prodcustprice->lines[0]->price); - $price_min = price($prodcustprice->lines[0]->price_min); - $pu_ttc = price($prodcustprice->lines[0]->price_ttc); - $price_base_type = $prodcustprice->lines[0]->price_base_type; - $tva_tx = $prodcustprice->lines[0]->tva_tx; - if ($prodcustprice->lines[0]->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { - $tva_tx .= ' ('.$prodcustprice->lines[0]->default_vat_code.')'; - } - $tva_npr = $prodcustprice->lines[0]->recuperableonly; - if (empty($tva_tx)) { - $tva_npr = 0; + $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours + foreach ($prodcustprice->lines as $k => $custprice_line) { + if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) { + $pu_ht = price($custprice_line->price); + $price_min = price($custprice_line->price_min); + $pu_ttc = price($custprice_line->price_ttc); + $price_base_type = $custprice_line->price_base_type; + $tva_tx = $custprice_line->tva_tx; + if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) { + $tva_tx .= ' (' . $custprice_line->default_vat_code . ')'; + } + $tva_npr = $custprice_line->recuperableonly; + if (empty($tva_tx)) { + $tva_npr = 0; + } + break; + } } } } @@ -5923,9 +5935,9 @@ class Product extends CommonObject /** * Return label of status of object * - * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto - * @param int $type 0=Sell, 1=Buy, 2=Batch Number management - * @return string Label of status + * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * @param int<0,2> $type 0=Sell, 1=Buy, 2=Batch Number management + * @return string Label of status */ public function getLibStatut($mode = 0, $type = 0) { @@ -5947,8 +5959,8 @@ class Product extends CommonObject * Return label of a given status * * @param int $status Statut - * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @param int $type 0=Status "to sell", 1=Status "to buy", 2=Status "to Batch" + * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @param int<0,2> $type 0=Status "to sell", 1=Status "to buy", 2=Status "to Batch" * @return string Label of status */ public function LibStatut($status, $mode = 0, $type = 0) diff --git a/htdocs/product/class/productcustomerprice.class.php b/htdocs/product/class/productcustomerprice.class.php index 4838885cb07..fe073e962f5 100644 --- a/htdocs/product/class/productcustomerprice.class.php +++ b/htdocs/product/class/productcustomerprice.class.php @@ -38,7 +38,8 @@ class ProductCustomerPrice extends CommonObject 'ref' => array('type' => 'varchar(128)', 'label' => 'Ref', 'enabled' => 1, 'visible' => 4, 'position' => 10, 'notnull' => 1, 'default' => '(PROV)', 'index' => 1, 'searchall' => 1, 'comment' => "Reference of object", 'showoncombobox' => 1, 'noteditable' => 1), 'fk_product' => array('type' => 'integer:Product:product/class/product.class.php:0', 'label' => 'Product', 'enabled' => '$conf->product->enabled', 'visible' => 1, 'position' => 35, 'notnull' => 1, 'index' => 1, 'comment' => "Product to produce", 'css' => 'maxwidth300', 'csslist' => 'tdoverflowmax100', 'picto' => 'product'), 'ref_customer' => array('type' => 'varchar(128)', 'label' => 'RefCustomer', 'enabled' => 1, 'visible' => 4, 'position' => 10, 'notnull' => 1,), - 'datec' => array('type' => 'datetime', 'label' => 'AppliedPricesFrom', 'enabled' => 1, 'visible' => 1, 'position' => 500, 'notnull' => 1,), + 'date_begin' => array('type' => 'date', 'label' => 'AppliedPricesFrom', 'enabled' => 1, 'visible' => 1, 'position' => 500, 'notnull' => 1,), + 'date_end' => array('type' => 'date', 'label' => 'AppliedPricesTo', 'enabled' => 1, 'visible' => 1, 'position' => 501, 'notnull' => 1,), 'price_base_type' => array('type' => 'varchar(255)', 'label' => 'PriceBase', 'enabled' => 1, 'visible' => 1, 'position' => 11, 'notnull' => -1, 'comment' => 'Price Base Type'), 'tva_tx' => array('type' => 'decimal(20,6)', 'label' => 'VAT', 'enabled' => 1, 'visible' => 1, 'position' => 12, 'notnull' => -1, 'comment' => 'TVA Tax Rate'), 'price' => array('type' => 'decimal(20,6)', 'label' => 'HT', 'enabled' => 1, 'visible' => 1, 'position' => 8, 'notnull' => -1, 'comment' => 'Price HT'), @@ -46,6 +47,7 @@ class ProductCustomerPrice extends CommonObject 'price_min' => array('type' => 'decimal(20,6)', 'label' => 'MinPriceHT', 'enabled' => 1, 'visible' => 1, 'position' => 9, 'notnull' => -1, 'comment' => 'Minimum Price'), 'price_min_ttc' => array('type' => 'decimal(20,6)', 'label' => 'MinPriceTTC', 'enabled' => 1, 'visible' => 1, 'position' => 10, 'notnull' => -1, 'comment' => 'Minimum Price TTC'), 'price_label' => array('type' => 'varchar(255)', 'label' => 'PriceLabel', 'enabled' => 1, 'visible' => 1, 'position' => 20, 'notnull' => -1, 'comment' => 'Price Label'), + 'discount_percent' => array('type' => 'decimal(20,6)', 'label' => 'Discount', 'enabled' => 1, 'visible' => 1, 'position' => 30, 'notnull' => -1, 'comment' => 'Discount'), 'fk_user' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserModif', 'enabled' => 1, 'visible' => 1, 'position' => 510, 'notnull' => 1, 'foreignkey' => 'user.rowid', 'csslist' => 'tdoverflowmax100'), ); @@ -136,6 +138,18 @@ class ProductCustomerPrice extends CommonObject * @var string */ public $price_label; + /** + * @var float|string|'' + */ + public $discount_percent; + /** + * @var string|int + */ + public $date_begin = ''; + /** + * @var string|int + */ + public $date_end = ''; /** * @var int User ID @@ -158,6 +172,46 @@ class ProductCustomerPrice extends CommonObject $this->db = $db; } + /** + * Check if begin and end dates intersect other dates periods + * + * @return int Result <0 if KO, >0 if OK + */ + public function verifyDates() + { + global $langs; + + $sql = "SELECT COUNT(*) AS nb"; + $sql .= " FROM " . $this->db->prefix() . "product_customer_price as t"; + $sql .= " WHERE (t.date_begin = '" . $this->db->idate($this->date_begin) . "' OR t.date_end = '" . $this->db->idate($this->date_begin) . "'"; + $sql .= " OR t.date_begin = '" . $this->db->idate($this->date_end) . "' OR t.date_end = '" . $this->db->idate($this->date_end) . "'"; + $sql .= " OR (t.date_begin <= '" . $this->db->idate($this->date_begin) . "' AND '" . $this->db->idate($this->date_begin) . "' <= t.date_end)"; + $sql .= " OR (t.date_begin <= '" . $this->db->idate($this->date_end) . "' AND '" . $this->db->idate($this->date_end) . "' <= t.date_end))"; + if ($this->fk_product > 0) $sql .= " AND t.fk_product = " . ((int) $this->fk_product); + if ($this->fk_soc > 0) $sql .= " AND t.fk_soc = " . ((int) $this->fk_soc); + if ($this->id > 0) $sql .= " AND t.rowid != " . ((int) $this->id); + + dol_syslog(get_class($this) . "::fetch", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $this->errors[] = "Error " . $this->db->lasterror(); + return -1; + } + + $nb = 0; + if ($obj = $this->db->fetch_object($resql)) { + $nb = (int) $obj->nb; + } + $this->db->free($resql); + + if ($nb > 0) { + $this->errors[] = $langs->trans('ErrorAppliedPricesIntersectAnotherPeriod'); + return -1; + } + + return 1; + } + /** * Create object into database * @@ -170,6 +224,7 @@ class ProductCustomerPrice extends CommonObject { global $conf, $langs; $error = 0; + $now = dol_now(); // Clean parameters @@ -212,6 +267,12 @@ class ProductCustomerPrice extends CommonObject if (isset($this->localtax2_tx)) { $this->localtax2_tx = trim($this->localtax2_tx); } + if (empty($this->discount_percent) || !is_numeric($this->discount_percent)) { + $this->discount_percent = 0; + } + if (empty($this->date_begin)) { + $this->date_begin = $now; + } if (isset($this->fk_user)) { $this->fk_user = (int) $this->fk_user; } @@ -224,6 +285,10 @@ class ProductCustomerPrice extends CommonObject // Check parameters // Put here code to add control on parameters values + $result = $this->verifyDates(); + if ($result < 0) { + return -1; + } if ($this->price != '' || $this->price == 0) { $vatRate = (float) $this->tva_tx; @@ -276,12 +341,15 @@ class ProductCustomerPrice extends CommonObject $sql .= "localtax1_tx,"; $sql .= "localtax2_type,"; $sql .= "localtax2_tx,"; + $sql .= "discount_percent,"; + $sql .= "date_begin,"; + $sql .= "date_end,"; $sql .= "fk_user,"; $sql .= "price_label,"; $sql .= "import_key"; $sql .= ") VALUES ("; $sql .= " ".((int) $conf->entity).","; - $sql .= " '".$this->db->idate(dol_now())."',"; + $sql .= " '".$this->db->idate($now)."',"; $sql .= " ".(!isset($this->fk_product) ? 'NULL' : ((int) $this->fk_product)).","; $sql .= " ".(!isset($this->fk_soc) ? 'NULL' : ((int) $this->fk_soc)).","; $sql .= " ".(!isset($this->ref_customer) ? 'NULL' : "'".$this->db->escape($this->ref_customer)."'").","; @@ -297,6 +365,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " ".(!isset($this->localtax1_tx) ? 'NULL' : (empty($this->localtax1_tx) ? 0 : $this->localtax1_tx)).","; $sql .= " ".(empty($this->localtax2_type) ? "'0'" : "'".$this->db->escape($this->localtax2_type)."'").","; $sql .= " ".(!isset($this->localtax2_tx) ? 'NULL' : (empty($this->localtax2_tx) ? 0 : $this->localtax2_tx)).","; + $sql .= " ".(empty($this->discount_percent) ? '0' : "'".$this->db->escape(price2num($this->discount_percent))."'").","; + $sql .= " '".$this->db->idate($this->date_begin)."',"; + $sql .= " ".(empty($this->date_end) ? 'NULL' : "'".$this->db->idate($this->date_end)."'").","; $sql .= " ".((int) $user->id).","; $sql .= " ".(!isset($this->price_label) ? 'NULL' : "'".$this->db->escape($this->price_label)."'").","; $sql .= " ".(!isset($this->import_key) ? 'NULL' : "'".$this->db->escape($this->import_key)."'"); @@ -371,6 +442,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " t.recuperableonly,"; $sql .= " t.localtax1_tx,"; $sql .= " t.localtax2_tx,"; + $sql .= " t.discount_percent,"; + $sql .= " t.date_begin,"; + $sql .= " t.date_end,"; $sql .= " t.fk_user,"; $sql .= " t.price_label,"; $sql .= " t.import_key"; @@ -401,6 +475,9 @@ class ProductCustomerPrice extends CommonObject $this->recuperableonly = $obj->recuperableonly; $this->localtax1_tx = $obj->localtax1_tx; $this->localtax2_tx = $obj->localtax2_tx; + $this->discount_percent = $obj->discount_percent; + $this->date_begin = $this->db->jdate($obj->date_begin); + $this->date_end = $this->db->jdate($obj->date_end); $this->fk_user = $obj->fk_user; $this->price_label = $obj->price_label; $this->import_key = $obj->import_key; @@ -433,7 +510,7 @@ class ProductCustomerPrice extends CommonObject public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '') { if (empty($sortfield)) { - $sortfield = "t.rowid"; + $sortfield = "t.date_begin"; } if (empty($sortorder)) { $sortorder = "DESC"; @@ -459,6 +536,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " t.localtax2_tx,"; $sql .= " t.localtax1_type,"; $sql .= " t.localtax2_type,"; + $sql .= " t.discount_percent,"; + $sql .= " t.date_begin,"; + $sql .= " t.date_end,"; $sql .= " t.fk_user,"; $sql .= " t.price_label,"; $sql .= " t.import_key,"; @@ -482,7 +562,7 @@ class ProductCustomerPrice extends CommonObject $sql .= " AND ".$this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'"; } elseif ($key == 'prod.ref' || $key == 'prod.label') { $sql .= " AND ".$this->db->sanitize($key)." LIKE '%".$this->db->escape($this->db->escapeforlike($value))."%'"; - } elseif ($key == 't.price' || $key == 't.price_ttc') { + } elseif ($key == 't.price' || $key == 't.price_ttc' || $key == 't.discount_percent') { $sql .= " AND ".$this->db->sanitize($key)." = ".((float) price2num($value)); } else { $sql .= " AND ".$this->db->sanitize($key)." = ".((int) $value); @@ -536,6 +616,9 @@ class ProductCustomerPrice extends CommonObject $line->localtax2_tx = $obj->localtax2_tx; $line->localtax1_type = $obj->localtax1_type; $line->localtax2_type = $obj->localtax2_type; + $line->discount_percent = $obj->discount_percent; + $line->date_begin = $this->db->jdate($obj->date_begin); + $line->date_end = $this->db->jdate($obj->date_end); $line->fk_user = $obj->fk_user; $line->price_label = $obj->price_label; $line->import_key = $obj->import_key; @@ -565,10 +648,10 @@ class ProductCustomerPrice extends CommonObject */ public function fetchAllLog($sortorder, $sortfield, $limit, $offset, $filter = array()) { - if (!empty($sortfield)) { - $sortfield = "t.rowid"; + if (empty($sortfield)) { + $sortfield = "t.date_begin"; } - if (!empty($sortorder)) { + if (empty($sortorder)) { $sortorder = "DESC"; } @@ -589,6 +672,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " t.recuperableonly,"; $sql .= " t.localtax1_tx,"; $sql .= " t.localtax2_tx,"; + $sql .= " t.discount_percent,"; + $sql .= " t.date_begin,"; + $sql .= " t.date_end,"; $sql .= " t.fk_user,"; $sql .= " t.price_label,"; $sql .= " t.import_key,"; @@ -645,6 +731,9 @@ class ProductCustomerPrice extends CommonObject $line->recuperableonly = $obj->recuperableonly; $line->localtax1_tx = $obj->localtax1_tx; $line->localtax2_tx = $obj->localtax2_tx; + $line->discount_percent = $obj->discount_percent; + $line->date_begin = $this->db->jdate($obj->date_begin); + $line->date_end = $this->db->jdate($obj->date_end); $line->fk_user = $obj->fk_user; $line->price_label = $obj->price_label; $line->import_key = $obj->import_key; @@ -674,6 +763,7 @@ class ProductCustomerPrice extends CommonObject { global $conf, $langs; $error = 0; + $now = dol_now(); // Clean parameters @@ -716,6 +806,12 @@ class ProductCustomerPrice extends CommonObject if (isset($this->localtax2_tx)) { $this->localtax2_tx = trim((string) $this->localtax2_tx); } + if (empty($this->discount_percent) || !is_numeric($this->discount_percent)) { + $this->discount_percent = 0; + } + if (empty($this->date_begin)) { + $this->date_begin = $now; + } if (isset($this->fk_user)) { $this->fk_user = (int) $this->fk_user; } @@ -728,6 +824,10 @@ class ProductCustomerPrice extends CommonObject // Check parameters // Put here code to add a control on parameters values + $result = $this->verifyDates(); + if ($result < 0) { + return -1; + } if ($this->price != '' || $this->price == 0) { $vatRate = (float) $this->tva_tx; @@ -782,6 +882,9 @@ class ProductCustomerPrice extends CommonObject $sql .= "localtax2_tx,"; $sql .= "localtax1_type,"; $sql .= "localtax2_type,"; + $sql .= "discount_percent,"; + $sql .= "date_begin,"; + $sql .= "date_end,"; $sql .= "fk_user,"; $sql .= "price_label,"; $sql .= "import_key"; @@ -806,6 +909,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " t.localtax2_tx,"; $sql .= " t.localtax1_type,"; $sql .= " t.localtax2_type,"; + $sql .= " t.discount_percent,"; + $sql .= " t.date_begin,"; + $sql .= " t.date_end,"; $sql .= " t.fk_user,"; $sql .= " t.price_label,"; $sql .= " t.import_key"; @@ -825,7 +931,7 @@ class ProductCustomerPrice extends CommonObject $sql = "UPDATE ".$this->db->prefix()."product_customer_price SET"; $sql .= " entity=".((int) $conf->entity).","; - $sql .= " datec='".$this->db->idate(dol_now())."',"; + $sql .= " datec='".$this->db->idate($now)."',"; $sql .= " tms=".(dol_strlen((string) $this->tms) != 0 ? "'".$this->db->idate($this->tms)."'" : 'null').","; $sql .= " fk_product=".(isset($this->fk_product) ? $this->fk_product : "null").","; $sql .= " fk_soc=".(isset($this->fk_soc) ? $this->fk_soc : "null").","; @@ -842,6 +948,9 @@ class ProductCustomerPrice extends CommonObject $sql .= " localtax2_tx=".(isset($this->localtax2_tx) ? (empty($this->localtax2_tx) ? 0 : $this->localtax2_tx) : "null").","; $sql .= " localtax1_type=".(!empty($this->localtax1_type) ? "'".$this->db->escape($this->localtax1_type)."'" : "'0'").","; $sql .= " localtax2_type=".(!empty($this->localtax2_type) ? "'".$this->db->escape($this->localtax2_type)."'" : "'0'").","; + $sql .= " discount_percent=".(!empty($this->discount_percent) ? "'".price2num($this->discount_percent)."'" : "0").","; + $sql .= " date_begin='".$this->db->idate($this->date_begin)."',"; + $sql .= " date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").","; $sql .= " fk_user=".((int) $user->id).","; $sql .= " price_label=".(isset($this->price_label) ? "'".$this->db->escape($this->price_label)."'" : "null").","; $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null"); @@ -939,6 +1048,9 @@ class ProductCustomerPrice extends CommonObject $prodsocpriceupd->tva_tx = $this->tva_tx; $prodsocpriceupd->recuperableonly = $this->recuperableonly; $prodsocpriceupd->price_label = $this->price_label; + $prodsocpriceupd->discount_percent = $this->discount_percent; + $prodsocpriceupd->date_begin = $this->date_begin; + $prodsocpriceupd->date_end = $this->date_end; $resultupd = $prodsocpriceupd->update($user, 0, $forceupdateaffiliate); if ($resultupd < 0) { @@ -958,6 +1070,9 @@ class ProductCustomerPrice extends CommonObject $prodsocpricenew->tva_tx = $this->tva_tx; $prodsocpricenew->recuperableonly = $this->recuperableonly; $prodsocpricenew->price_label = $this->price_label; + $prodsocpricenew->discount_percent = $this->discount_percent; + $prodsocpricenew->date_begin = $this->date_begin; + $prodsocpricenew->date_end = $this->date_end; $resultupd = $prodsocpricenew->create($user, 0, $forceupdateaffiliate); if ($resultupd < 0) { @@ -1102,6 +1217,9 @@ class ProductCustomerPrice extends CommonObject $this->recuperableonly = ''; $this->localtax1_tx = ''; $this->localtax2_tx = ''; + $this->discount_percent = ''; + $this->date_begin = ''; + $this->date_end = ''; $this->fk_user = 0; $this->price_label = ''; $this->import_key = ''; @@ -1185,6 +1303,18 @@ class PriceByCustomerLine extends CommonObjectLine * @var float */ public $localtax2_tx; + /** + * @var float|string|'' + */ + public $discount_percent; + /** + * @var string|int + */ + public $date_begin = ''; + /** + * @var string|int + */ + public $date_end = ''; /** * @var int User ID diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 6c6a98b126e..eadcd487538 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -754,6 +754,9 @@ if (empty($reshook)) { $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU'); $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha'); $prodcustprice->price_label = GETPOST("price_label", 'alpha'); + $prodcustprice->discount_percent = price2num(GETPOST("discount_percent")); + $prodcustprice->date_begin = dol_mktime(0, 0, 0, GETPOSTINT('date_beginmonth'), GETPOSTINT('date_beginday'), GETPOSTINT('date_beginyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server; + $prodcustprice->date_end = dol_mktime(0, 0, 0, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server $extralabels = $extrafields->fetch_name_optionals_label("product_customer_price"); $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price"); @@ -864,11 +867,11 @@ if (empty($reshook)) { if ($result < 0) { setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors'); + $action = 'add_customer_price'; } else { setEventMessages($langs->trans('RecordSaved'), null, 'mesgs'); + $action = ''; } - - $action = ''; } } @@ -906,6 +909,9 @@ if (empty($reshook)) { $prodcustprice->price_min = price2num(GETPOST("price_min"), 'MU'); $prodcustprice->price_base_type = GETPOST("price_base_type", 'alpha'); $prodcustprice->price_label = GETPOST("price_label", 'alpha'); + $prodcustprice->discount_percent = price2num(GETPOST("discount_percent")); + $prodcustprice->date_begin = dol_mktime(0, 0, 0, GETPOSTINT('date_beginmonth'), GETPOSTINT('date_beginday'), GETPOSTINT('date_beginyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server; + $prodcustprice->date_end = dol_mktime(0, 0, 0, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server $extralabels = $extrafields->fetch_name_optionals_label("product_customer_price"); $extrafield_values = $extrafields->getOptionalsFromPost("product_customer_price"); @@ -1009,11 +1015,11 @@ if (empty($reshook)) { if ($result < 0) { setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors'); + $action = 'update_customer_price'; } else { setEventMessages($langs->trans("Save"), null, 'mesgs'); + $action = ''; } - - $action = ''; } } } @@ -2002,10 +2008,10 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT $pageprev = $page - 1; $pagenext = $page + 1; if (!$sortorder) { - $sortorder = "ASC"; + $sortorder = "ASC,ASC"; } if (!$sortfield) { - $sortfield = "soc.nom"; + $sortfield = "soc.nom,t.date_begin"; } // Build filter to display only concerned lines @@ -2034,7 +2040,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$langs->trans('ThirdParty').''; print ''; $filter = '(s.client:IN:1,2,3)'; - print img_picto('', 'company').$form->select_company('', 'socid', $filter, 'SelectThirdParty', 0, 0, array(), 0, 'minwidth300'); + print img_picto('', 'company').$form->select_company(GETPOSTINT('socid'), 'socid', $filter, 'SelectThirdParty', 0, 0, array(), 0, 'minwidth300'); print ''; print ''; @@ -2042,6 +2048,18 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print '' . $langs->trans('RefCustomer') . ''; print ''; + // Applied Prices From + $date_begin = dol_mktime(0, 0, 0, GETPOSTINT('date_beginmonth'), GETPOSTINT('date_beginday'), GETPOSTINT('date_beginyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server; + print ''.$langs->trans("AppliedPricesFrom").''; + print $form->selectDate(!empty($date_begin) ? $date_begin : dol_now(), "date_begin", 0, 0, 1, "date_begin"); + print ''; + + // Applied Prices To + $date_end = dol_mktime(0, 0, 0, GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'), 'tzserver'); // If we enter the 02 january, we need to save the 02 january for server + print ''.$langs->trans("AppliedPricesTo").''; + print $form->selectDate($date_end, "date_end", 0, 0, 1, "date_end"); + print ''; + // VAT print ''.$langs->trans("DefaultTaxRate").''; print $form->load_tva("tva_tx", $object->default_vat_code ? $object->tva_tx.' ('.$object->default_vat_code.')' : $object->tva_tx, $mysoc, null, $object->id, $object->tva_npr, $object->type, false, 1); @@ -2090,6 +2108,12 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''; print ''; + // Discount + $discount_percent = price2num(GETPOST("discount_percent")); + print ''.$langs->trans("Discount").''; + print ''; + print ''; + // Extrafields $extrafields->fetch_name_optionals_label("product_customer_price"); $extralabels = !empty($extrafields->attributes["product_customer_price"]['label']) ? $extrafields->attributes["product_customer_price"]['label'] : ''; @@ -2159,6 +2183,16 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print '' . $langs->trans('RefCustomer') . ''; print ''; + // Applied Prices From + print ''.$langs->trans("AppliedPricesFrom").''; + print $form->selectDate($prodcustprice->date_begin, "date_begin", 0, 0, 1, "date_begin"); + print ''; + + // Applied Prices To + print ''.$langs->trans("AppliedPricesTo").''; + print $form->selectDate($prodcustprice->date_end, "date_end", 0, 0, 1, "date_end"); + print ''; + // VAT print ''.$langs->trans("DefaultTaxRate").''; print $form->load_tva("tva_tx", $prodcustprice->default_vat_code ? $prodcustprice->tva_tx.' ('.$prodcustprice->default_vat_code.')' : $prodcustprice->tva_tx, $mysoc, null, $object->id, $prodcustprice->recuperableonly, $object->type, false, 1); @@ -2201,8 +2235,6 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT } print ''; - - // Price Label print ''; print $langs->trans('PriceLabel'); @@ -2211,6 +2243,11 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''; print ''; + // Discount + print ''.$langs->trans("Discount").''; + print ''; + print ''; + // Extrafields $extrafields->fetch_name_optionals_label("product_customer_price"); $extralabels = !empty($extrafields->attributes["product_customer_price"]['label']) ? $extrafields->attributes["product_customer_price"]['label'] : ''; @@ -2280,6 +2317,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT // List of all log of prices by customers print ''."\n"; + $sortfield = 't.datec'; $filter = array('t.fk_product' => (string) $object->id, 't.fk_soc' => (string) GETPOSTINT('socid')); // Count total nb of records @@ -2318,6 +2356,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$langs->trans("ThirdParty").''; print ''.$langs->trans('RefCustomer').''; print ''.$langs->trans("AppliedPricesFrom").''; + print ''.$langs->trans("AppliedPricesTo").''; print ''.$langs->trans("PriceBase").''; print ''.$langs->trans("DefaultTaxRate").''; print ''.$langs->trans("HT").''; @@ -2328,8 +2367,9 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$langs->trans("MinPrice").' '.$langs->trans("HT").''; print ''.$langs->trans("MinPrice").' '.$langs->trans("TTC").''; print ''.$langs->trans("PriceLabel").''; + print ''.$langs->trans("Discount").''; print ''.$langs->trans("ChangedBy").''; - print ' '; + print ''.$langs->trans("DateCreation").''; print ''; foreach ($prodcustprice->lines as $line) { @@ -2361,7 +2401,8 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$staticsoc->getNomUrl(1).""; print ''.$line->ref_customer.''; - print "".dol_print_date($line->datec, "dayhour", 'tzuserrel').""; + print "".dol_print_date($line->date_begin, "day", 'tzuserrel').""; + print "".dol_print_date($line->date_end, "day", 'tzuserrel').""; print ''.$langs->trans($line->price_base_type).""; print ''; @@ -2393,6 +2434,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.price($line->price_min).''; print ''.price($line->price_min_ttc).''; print ''.$line->price_label.''; + print ''.price($line->discount_percent).''; // User $userstatic = new User($db); @@ -2401,6 +2443,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print $userstatic->getNomUrl(1, '', 0, 0, 24, 0, 'login'); //print $userstatic->getLoginUrl(1); print ''; + print "".dol_print_date($line->datec, "dayhour", 'tzuserrel').""; print ''; } print ""; @@ -2440,9 +2483,9 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT $extrafields->fetch_name_optionals_label("product_customer_price"); $custom_price_extralabels = !empty($extrafields->attributes["product_customer_price"]['label']) ? $extrafields->attributes["product_customer_price"]['label'] : ''; if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) { - $colspan = 10; - } else { $colspan = 11; + } else { + $colspan = 12; } if ($mysoc->localtax1_assuj == "1" || $mysoc->localtax2_assuj == "1") { $colspan++; @@ -2466,6 +2509,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$langs->trans("ThirdParty").''; print ''.$langs->trans('RefCustomer').''; print ''.$langs->trans("AppliedPricesFrom").''; + print ''.$langs->trans("AppliedPricesTo").''; print ''.$langs->trans("PriceBase").''; print ''.$langs->trans("DefaultTaxRate").''; print ''.$langs->trans("HT").''; @@ -2476,6 +2520,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$langs->trans("MinPrice").' '.$langs->trans("HT").''; print ''.$langs->trans("MinPrice").' '.$langs->trans("TTC").''; print ''.$langs->trans("PriceLabel").''; + print ''.$langs->trans("Discount").''; // fetch optionals attributes and labels $extrafields->fetch_name_optionals_label("product_customer_price"); if ($extrafields->attributes["product_customer_price"] && array_key_exists('label', $extrafields->attributes["product_customer_price"])) { @@ -2522,7 +2567,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT if (!getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) { print ''."\n"; print ''; - print '' . $langs->trans('Default') . ''; + print '' . $langs->trans('Default') . ''; print ''.$langs->trans($object->price_base_type).""; @@ -2560,6 +2605,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.price($object->price_min_ttc).''; print ''.$object->price_label.''; print ''; + print ''; if (!empty($extralabels)) { foreach ($extralabels as $key) { // Show field if not hidden @@ -2612,7 +2658,8 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.$staticsoc->getNomUrl(1).""; print ''.dol_escape_htmltag($line->ref_customer).''; - print "".dol_print_date($line->datec, "dayhour", 'tzuserrel').""; + print "".dol_print_date($line->date_begin, "day", 'tzuserrel').""; + print "".dol_print_date($line->date_end, "day", 'tzuserrel').""; print ''.$langs->trans($line->price_base_type).""; // VAT Rate print ''; @@ -2646,6 +2693,7 @@ if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES') || getDolGlobalString('PRODUIT print ''.price($line->price_min).''; print ''.price($line->price_min_ttc).''; print ''.$line->price_label.''; + print ''.price($line->discount_percent).''; // Extrafields $extrafields->fetch_name_optionals_label("product_customer_price"); diff --git a/htdocs/projet/tasks/task.php b/htdocs/projet/tasks/task.php index 6afc01197d9..b82b92940ea 100644 --- a/htdocs/projet/tasks/task.php +++ b/htdocs/projet/tasks/task.php @@ -109,7 +109,7 @@ if ($action == 'update' && !GETPOST("cancel") && $user->hasRight('projet', 'cree setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Label")), null, 'errors'); } if (!$error) { - $object->oldcopy = clone $object; + $object->oldcopy = clone $object; // @phan-suppress-current-line PhanTypeMismatchProperty $tmparray = explode('_', GETPOST('task_parent')); $task_parent = $tmparray[1]; diff --git a/htdocs/resource/class/html.formresource.class.php b/htdocs/resource/class/html.formresource.class.php index 6f517272040..52a601551a9 100644 --- a/htdocs/resource/class/html.formresource.class.php +++ b/htdocs/resource/class/html.formresource.class.php @@ -73,7 +73,7 @@ class FormResource /** * Output html form to select a resource * - * @param int $selected Preselected resource id + * @param int|int[] $selected Preselected resource id * @param string $htmlname Name of field in form * @param string $filter Optional filters criteria (example: 's.rowid <> x') * @param int<0,1> $showempty Add an empty field diff --git a/htdocs/salaries/card.php b/htdocs/salaries/card.php index 04b44c2dcb3..0a0505fa8ec 100644 --- a/htdocs/salaries/card.php +++ b/htdocs/salaries/card.php @@ -1,13 +1,14 @@ * Copyright (C) 2014-2020 Laurent Destailleur - * Copyright (C) 2015 Jean-François Ferry - * Copyright (C) 2015 Charlie BENKE - * Copyright (C) 2018-2024 Frédéric France - * Copyright (C) 2021 Gauthier VERDOL - * Copyright (C) 2023 Maxime Nicolas - * Copyright (C) 2023 Benjamin GREMBI - * Copyright (C) 2024-2025 MDW + * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2015 Charlie BENKE + * Copyright (C) 2018-2024 Frédéric France + * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2023 Maxime Nicolas + * Copyright (C) 2023 Benjamin GREMBI + * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 Nick Fragoulis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -761,21 +762,67 @@ if ($id > 0) { ); //$formquestion[] = array('type' => 'date', 'name' => 'clone_date_ech', 'label' => $langs->trans("Date"), 'value' => -1); - $formquestion[] = array('type' => 'date', 'name' => 'clone_date_start', 'label' => $langs->trans("DateStart"), 'value' => -1); + if (!empty($object->dateep)) { + $formquestion[] = array('type' => 'date', 'name' => 'clone_date_start', 'label' => $langs->trans("DateStart"), 'value' => ($object->dateep) + 86400); + } else { + $formquestion[] = array('type' => 'date', 'name' => 'clone_date_start', 'label' => $langs->trans("DateStart"), 'value' => -1); + } $formquestion[] = array('type' => 'date', 'name' => 'clone_date_end', 'label' => $langs->trans("DateEnd"), 'value' => -1); $formquestion[] = array('type' => 'text', 'name' => 'amount', 'label' => $langs->trans("Amount"), 'value' => price($object->amount), 'morecss' => 'width100 right'); - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneSalary', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 280); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneSalary', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 300); - //Add fill with end of month button + //Add buttons to fill start and end dates $formconfirm .= "