diff --git a/ChangeLog b/ChangeLog index 0ac6d7906a6..b8c397b4bf7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,7 +19,7 @@ WARNING: The following changes may create regressions for some external modules, but were necessary to make Dolibarr better: * The directory /build has been moved into /dev/build. * The use of GETPOST function is not allowed inside extrafields conditions or any strings that contains dynamic code evaluated with dol_eval() - +* The deprecated variable $trigger_name (duplicate of variable $triggersendname) has been removed. You must use $triggersendname everywhere now. ***** ChangeLog for 21.0.0 compared to 20.0 ***** diff --git a/dev/build/phpstan/phpstan-baseline.neon b/dev/build/phpstan/phpstan-baseline.neon index ce8c2a8fa80..1bb49a384e7 100644 --- a/dev/build/phpstan/phpstan-baseline.neon +++ b/dev/build/phpstan/phpstan-baseline.neon @@ -4206,30 +4206,6 @@ parameters: count: 5 path: ../../../htdocs/commande/class/commande.class.php - - - message: '#^Parameter \#15 \$pu_devise of function calcul_price_total expects float, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Parameter \#2 \$pu of function calcul_price_total expects float, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Parameter \#5 \$uselocaltax1_rate of function calcul_price_total expects float, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - - - message: '#^Parameter \#6 \$uselocaltax2_rate of function calcul_price_total expects float, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/commande/class/commande.class.php - - message: '#^Property Commande\:\:\$mode_reglement_id \(int\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -7512,12 +7488,6 @@ parameters: count: 1 path: ../../../htdocs/core/actions_sendmails.inc.php - - - message: '#^Variable \$paramname2 might not be defined\.$#' - identifier: variable.undefined - count: 1 - path: ../../../htdocs/core/actions_sendmails.inc.php - - message: '#^Variable \$result might not be defined\.$#' identifier: variable.undefined @@ -8556,18 +8526,6 @@ parameters: count: 1 path: ../../../htdocs/core/class/commonobject.class.php - - - message: '#^Parameter \#20 \$fk_unit of method SupplierProposal\:\:updateline\(\) expects int, float given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/core/class/commonobject.class.php - - - - message: '#^Parameter \#21 \$situation_percent of method Facture\:\:updateline\(\) expects int, float given\.$#' - identifier: argument.type - count: 1 - path: ../../../htdocs/core/class/commonobject.class.php - - message: '#^Property CommonObject\:\:\$childtables \(array\\|string\>\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -20214,6 +20172,18 @@ parameters: count: 1 path: ../../../htdocs/product/class/api_products.class.php + - + message: '#^Method Products\:\:getPurchasePrices\(\) should return array\ but returns object\.$#' + identifier: return.type + count: 1 + path: ../../../htdocs/product/class/api_products.class.php + + - + message: '#^Unable to resolve the template type T in call to method Products\:\:_cleanObjectDatas\(\)$#' + identifier: argument.templateType + count: 1 + path: ../../../htdocs/product/class/api_products.class.php + - message: '#^Method Products\:\:getSubproducts\(\) return type has no value type specified in iterable type array\.$#' identifier: missingType.iterableValue @@ -21804,6 +21774,18 @@ parameters: count: 1 path: ../../../htdocs/projet/class/api_tasks.class.php + - + message: '#^Method Tasks\:\:getRoles\(\) should return array but returns list\\.$#' + identifier: return.type + count: 1 + path: ../../../htdocs/projet/class/api_tasks.class.php + + - + message: '#^Unable to resolve the template type T in call to method Tasks\:\:_cleanObjectDatas\(\)$#' + identifier: argument.templateType + count: 1 + path: ../../../htdocs/projet/class/api_tasks.class.php + - message: '#^Parameter \#1 \$object of method Tasks\:\:_cleanObjectDatas\(\) expects object, string given\.$#' identifier: argument.type diff --git a/dev/tools/phan/baseline.txt b/dev/tools/phan/baseline.txt index 95c289a6295..5eef4ce5338 100644 --- a/dev/tools/phan/baseline.txt +++ b/dev/tools/phan/baseline.txt @@ -9,13 +9,12 @@ */ return [ // # Issue statistics: - // PhanTypeMismatchArgument : 1230+ occurrences - // PhanUndeclaredProperty : 480+ occurrences - // PhanTypeMismatchArgumentNullable : 310+ occurrences - // PhanTypeMismatchProperty : 160+ occurrences + // PhanTypeMismatchArgument : 1000+ occurrences + // PhanUndeclaredProperty : 470+ occurrences + // PhanTypeMismatchArgumentNullable : 260+ occurrences + // PhanTypeMismatchProperty : 140+ occurrences // PhanUndeclaredGlobalVariable : 100+ occurrences - // PhanPluginUnknownArrayMethodReturnType : 60+ occurrences - // PhanTypeExpectedObjectPropAccess : 25+ occurrences + // PhanTypeExpectedObjectPropAccess : 20+ occurrences // PhanTypeInvalidDimOffset : 20+ occurrences // PhanTypeMismatchDimFetch : 20+ occurrences // PhanPluginUndeclaredVariableIsset : 15+ occurrences @@ -24,23 +23,22 @@ return [ // PhanTypeMismatchArgumentNullableInternal : 10+ occurrences // PhanPossiblyUndeclaredGlobalVariable : 9 occurrences // PhanUndeclaredMethod : 9 occurrences - // PhanTypeComparisonFromArray : 7 occurrences // PhanPluginDuplicateExpressionBinaryOp : 6 occurrences // PhanTypeArraySuspiciousNull : 6 occurrences + // PhanTypeComparisonFromArray : 6 occurrences // PhanParamTooMany : 4 occurrences // PhanPluginDuplicateArrayKey : 4 occurrences // PhanEmptyFQSENInClasslike : 3 occurrences // PhanInvalidFQSENInClasslike : 3 occurrences // PhanPluginSuspiciousParamPosition : 2 occurrences // PhanTypeMismatchDimAssignment : 2 occurrences + // PhanTypeMismatchReturn : 2 occurrences // PhanTypeSuspiciousStringExpression : 2 occurrences - // PhanAccessMethodProtected : 1 occurrence // PhanPluginBothLiteralsBinaryOp : 1 occurrence // PhanPluginDuplicateExpressionAssignmentOperation : 1 occurrence // PhanPluginUnknownArrayPropertyType : 1 occurrence // PhanPossiblyUndeclaredVariable : 1 occurrence // PhanTypeExpectedObjectPropAccessButGotNull : 1 occurrence - // PhanTypeMismatchReturn : 1 occurrence // Currently, file_suppressions and directory_suppressions are the only supported suppressions 'file_suppressions' => [ @@ -108,8 +106,6 @@ return [ 'htdocs/admin/pdf_other.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/prelevement.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/receiptprinter.php' => ['PhanTypeMismatchArgument'], - 'htdocs/admin/remotestore/class/PSWebServiceLibrary.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/admin/remotestore/class/dolistore.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/system/filecheck.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/system/modules.php' => ['PhanTypeMismatchArgument'], 'htdocs/admin/taxes.php' => ['PhanTypeMismatchArgumentNullable'], @@ -145,14 +141,12 @@ return [ 'htdocs/bookcal/class/availabilities.class.php' => ['PhanUndeclaredMethod', 'PhanUndeclaredProperty'], 'htdocs/bookcal/class/calendar.class.php' => ['PhanUndeclaredMethod', 'PhanUndeclaredProperty'], 'htdocs/bookmarks/card.php' => ['PhanTypeMismatchArgument'], - 'htdocs/categories/class/api_categories.class.php' => ['PhanAccessMethodProtected', 'PhanPluginUnknownArrayMethodReturnType'], 'htdocs/categories/class/categorie.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/categories/photos.php' => ['PhanTypeMismatchArgument'], 'htdocs/categories/viewcat.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/collab/index.php' => ['PhanUndeclaredProperty'], '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' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchProperty'], 'htdocs/comm/action/class/cactioncomm.class.php' => ['PhanPluginUnknownArrayPropertyType'], 'htdocs/comm/action/document.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/action/index.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty'], @@ -169,7 +163,6 @@ return [ 'htdocs/comm/multiprix.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/propal/agenda.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/propal/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty'], - 'htdocs/comm/propal/class/api_proposals.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/comm/propal/class/propal.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/comm/propal/class/propaleligne.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/propal/contact.php' => ['PhanTypeMismatchArgument'], @@ -180,18 +173,12 @@ return [ 'htdocs/comm/propal/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/comm/remise.php' => ['PhanTypeMismatchArgument'], 'htdocs/comm/remx.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/agenda.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty'], - 'htdocs/commande/class/api_orders.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], - 'htdocs/commande/class/commande.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/commande/class/orderline.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/contact.php' => ['PhanTypeMismatchArgument'], + 'htdocs/commande/card.php' => ['PhanTypeMismatchArgument'], + 'htdocs/commande/class/api_orders.class.php' => ['PhanTypeMismatchArgument'], + 'htdocs/commande/class/commande.class.php' => ['PhanUndeclaredProperty'], 'htdocs/commande/customer.php' => ['PhanUndeclaredGlobalVariable'], - 'htdocs/commande/document.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/commande/list_det.php' => ['PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], - 'htdocs/commande/note.php' => ['PhanTypeMismatchArgument'], - 'htdocs/commande/stats/index.php' => ['PhanTypeMismatchArgument'], + 'htdocs/commande/list.php' => ['PhanUndeclaredProperty'], + 'htdocs/commande/list_det.php' => ['PhanTypeInvalidDimOffset'], 'htdocs/commande/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/compta/accounting-files.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/bank/account_statement_document.php' => ['PhanUndeclaredGlobalVariable'], @@ -200,7 +187,6 @@ return [ 'htdocs/compta/bank/card.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/bank/categ.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/bank/class/account.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/compta/bank/class/api_bankaccounts.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal'], 'htdocs/compta/bank/class/paymentvarious.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/bank/graph.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/bank/line.php' => ['PhanUndeclaredGlobalVariable'], @@ -219,22 +205,15 @@ return [ 'htdocs/compta/deplacement/class/deplacement.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/deplacement/class/deplacementstats.class.php' => ['PhanTypeMismatchArgument'], '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', 'PhanTypeMismatchProperty'], - 'htdocs/compta/facture/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], - 'htdocs/compta/facture/class/api_invoices.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeComparisonFromArray', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal'], - 'htdocs/compta/facture/class/facture-rec.class.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], + 'htdocs/compta/facture/card-rec.php' => ['PhanTypeMismatchArgument'], + 'htdocs/compta/facture/card.php' => ['PhanUndeclaredProperty'], + 'htdocs/compta/facture/class/api_invoices.class.php' => ['PhanTypeMismatchArgumentProbablyReal'], + 'htdocs/compta/facture/class/facture-rec.class.php' => ['PhanUndeclaredProperty'], 'htdocs/compta/facture/class/facture.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], - 'htdocs/compta/facture/class/factureligne.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/facture/class/paymentterm.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/facture/contact.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/facture/document.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/invoicetemplate_list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/compta/facture/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/compta/facture/messaging.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/note.php' => ['PhanTypeMismatchArgument'], - 'htdocs/compta/facture/prelevement.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/stats/index.php' => ['PhanTypeMismatchArgument'], 'htdocs/compta/facture/tpl/linkedobjectblock.tpl.php' => ['PhanEmptyFQSENInClasslike', 'PhanInvalidFQSENInClasslike', 'PhanTypeMismatchArgumentNullableInternal'], 'htdocs/compta/facture/tpl/linkedobjectblockForRec.tpl.php' => ['PhanUndeclaredProperty'], @@ -281,7 +260,6 @@ return [ 'htdocs/contact/list.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/contrat/agenda.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal'], 'htdocs/contrat/card.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredGlobalVariable'], - 'htdocs/contrat/class/api_contracts.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/contrat/class/contrat.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/contrat/class/contratligne.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/contrat/contact.php' => ['PhanTypeMismatchArgument'], @@ -300,7 +278,7 @@ return [ 'htdocs/core/ajax/ajaxstatusprospect.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/contacts.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/loadinplace.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/ajax/saveinplace.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], + 'htdocs/core/ajax/saveinplace.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/ajax/selectobject.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/class/CMailFile.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/class/canvas.class.php' => ['PhanParamTooMany', 'PhanUndeclaredMethod'], @@ -308,7 +286,7 @@ return [ 'htdocs/core/class/cgenericdic.class.php' => ['PhanUndeclaredProperty'], 'htdocs/core/class/commondocgenerator.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/class/commoninvoice.class.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/class/commonobject.class.php' => ['PhanParamTooMany', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchArgumentProbablyReal', 'PhanUndeclaredProperty'], + 'htdocs/core/class/commonobject.class.php' => ['PhanParamTooMany', 'PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentProbablyReal', 'PhanUndeclaredProperty'], 'htdocs/core/class/commonpeople.class.php' => ['PhanUndeclaredProperty'], 'htdocs/core/class/commonsocialnetworks.class.php' => ['PhanUndeclaredProperty'], 'htdocs/core/class/commonstickergenerator.class.php' => ['PhanTypeMismatchArgument'], @@ -370,7 +348,6 @@ return [ 'htdocs/core/modules/cheque/modules_chequereceipts.php' => ['PhanTypeMismatchArgument'], 'htdocs/core/modules/commande/doc/pdf_einstein.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], 'htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchDimFetch', 'PhanTypeMismatchProperty', 'PhanUndeclaredProperty'], - 'htdocs/core/modules/commande/mod_commande_saphir.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/contract/doc/pdf_strato.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/delivery/doc/pdf_storm.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/delivery/doc/pdf_typhon.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], @@ -381,7 +358,7 @@ return [ 'htdocs/core/modules/expedition/doc/pdf_rouget.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable'], 'htdocs/core/modules/expensereport/doc/pdf_standard_expensereport.modules.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/core/modules/expensereport/mod_expensereport_jade.php' => ['PhanTypeMismatchArgument'], - 'htdocs/core/modules/facture/doc/pdf_crabe.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], + 'htdocs/core/modules/facture/doc/pdf_crabe.modules.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/facture/doc/pdf_octopus.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/facture/doc/pdf_sponge.modules.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/core/modules/facture/modules_facture.php' => ['PhanTypeMismatchArgument'], @@ -443,7 +420,6 @@ return [ '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' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/don/class/don.class.php' => ['PhanParamTooMany'], 'htdocs/don/document.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/don/info.php' => ['PhanUndeclaredGlobalVariable'], @@ -466,7 +442,6 @@ return [ 'htdocs/eventorganization/core/actions_massactions_mail.inc.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/expedition/ajax/searchfrombarcode.php' => ['PhanTypeMismatchArgument'], 'htdocs/expedition/card.php' => ['PhanTypeMismatchArgument', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], - 'htdocs/expedition/class/api_shipments.class.php' => ['PhanTypeMismatchProperty'], 'htdocs/expedition/class/expedition.class.php' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/expedition/class/expeditionlinebatch.class.php' => ['PhanTypeMismatchArgumentNullable'], 'htdocs/expedition/list.php' => ['PhanTypeMismatchArgument'], @@ -498,7 +473,6 @@ return [ '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' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/fourn/class/api_supplier_orders.class.php' => ['PhanTypeMismatchArgumentProbablyReal'], 'htdocs/fourn/class/fournisseur.commande.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/fourn/class/fournisseur.facture-rec.class.php' => ['PhanTypeMismatchArgument'], @@ -530,7 +504,6 @@ return [ 'htdocs/hrm/skill_card.php' => ['PhanTypeExpectedObjectPropAccess', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/imports/import.php' => ['PhanTypeMismatchArgument'], 'htdocs/intracommreport/card.php' => ['PhanUndeclaredGlobalVariable'], - 'htdocs/knowledgemanagement/class/api_knowledgemanagement.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/knowledgemanagement/class/knowledgerecord.class.php' => ['PhanUndeclaredProperty'], 'htdocs/knowledgemanagement/knowledgerecord_card.php' => ['PhanTypeMismatchArgument'], 'htdocs/loan/class/paymentloan.class.php' => ['PhanTypeMismatchArgument'], @@ -540,17 +513,16 @@ return [ 'htdocs/mrp/class/mo.class.php' => ['PhanTypeMismatchProperty'], 'htdocs/mrp/mo_movements.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/mrp/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], - 'htdocs/multicurrency/class/api_multicurrencies.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], + 'htdocs/multicurrency/class/api_multicurrencies.class.php' => ['PhanTypeMismatchArgument'], 'htdocs/multicurrency/class/multicurrency.class.php' => ['PhanTypeExpectedObjectPropAccess'], 'htdocs/multicurrency/multicurrency_rate.php' => ['PhanTypeMismatchArgument'], 'htdocs/opensurvey/results.php' => ['PhanUndeclaredGlobalVariable'], - 'htdocs/partnership/class/api_partnerships.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/partnership/class/partnership.class.php' => ['PhanUndeclaredProperty'], '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' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], + 'htdocs/product/class/api_products.class.php' => ['PhanTypeMismatchArgument', 'PhanTypeMismatchReturn', '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'], @@ -558,8 +530,6 @@ return [ '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' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], - 'htdocs/product/stock/class/api_warehouses.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/product/stock/info.php' => ['PhanUndeclaredProperty'], 'htdocs/product/stock/list.php' => ['PhanUndeclaredProperty'], 'htdocs/product/stock/movement_card.php' => ['PhanPluginUndeclaredVariableIsset', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], @@ -575,7 +545,6 @@ return [ 'htdocs/product/stock/tpl/stocktransfer.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/projet/admin/project.php' => ['PhanTypeMismatchArgumentProbablyReal'], 'htdocs/projet/card.php' => ['PhanTypeMismatchArgumentNullable', 'PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable'], - 'htdocs/projet/class/api_tasks.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanTypeMismatchArgument'], 'htdocs/projet/tasks.php' => ['PhanTypeMismatchArgument'], 'htdocs/projet/tasks/time.php' => ['PhanTypeInvalidDimOffset', 'PhanTypeMismatchArgument', 'PhanUndeclaredProperty'], 'htdocs/projet/tasks/tpl/linkedobjectblock.tpl.php' => ['PhanUndeclaredProperty'], @@ -590,7 +559,6 @@ return [ 'htdocs/public/recruitment/view.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/public/webportal/tpl/menu.tpl.php' => ['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' => ['PhanTypeMismatchArgumentNullable', 'PhanUndeclaredProperty'], 'htdocs/recruitment/class/recruitmentcandidature.class.php' => ['PhanUndeclaredProperty'], @@ -605,24 +573,20 @@ return [ 'htdocs/recruitment/recruitmentjobposition_card.php' => ['PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/recruitment/recruitmentjobposition_document.php' => ['PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], 'htdocs/recruitment/recruitmentjobposition_note.php' => ['PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], - 'htdocs/salaries/class/api_salaries.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], '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' => ['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' => ['PhanTypeMismatchProperty', 'PhanUndeclaredGlobalVariable', 'PhanUndeclaredProperty'], - 'htdocs/supplier_proposal/class/api_supplier_proposals.class.php' => ['PhanPluginUnknownArrayMethodReturnType', 'PhanUndeclaredProperty'], + 'htdocs/supplier_proposal/class/api_supplier_proposals.class.php' => ['PhanUndeclaredProperty'], 'htdocs/supplier_proposal/class/supplier_proposal.class.php' => ['PhanUndeclaredProperty'], 'htdocs/takepos/index.php' => ['PhanPluginUndeclaredVariableIsset'], 'htdocs/takepos/invoice.php' => ['PhanPossiblyUndeclaredGlobalVariable', 'PhanUndeclaredGlobalVariable'], 'htdocs/takepos/split.php' => ['PhanPluginUndeclaredVariableIsset'], 'htdocs/ticket/card.php' => ['PhanUndeclaredProperty'], 'htdocs/ticket/class/actions_ticket.class.php' => ['PhanUndeclaredProperty'], - 'htdocs/ticket/class/api_tickets.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/ticket/class/cticketcategory.class.php' => ['PhanUndeclaredProperty'], 'htdocs/ticket/class/ticket.class.php' => ['PhanUndeclaredProperty'], 'htdocs/ticket/contact.php' => ['PhanTypeMismatchArgument'], @@ -631,7 +595,6 @@ return [ 'htdocs/variants/tpl/productattributevalueline_edit.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/variants/tpl/productattributevalueline_view.tpl.php' => ['PhanUndeclaredProperty'], 'htdocs/viewimage.php' => ['PhanUndeclaredMethod'], - 'htdocs/webhook/class/api_webhook.class.php' => ['PhanPluginUnknownArrayMethodReturnType'], 'htdocs/webhook/class/target.class.php' => ['PhanUndeclaredMethod'], 'htdocs/webhook/target_card.php' => ['PhanUndeclaredGlobalVariable'], 'htdocs/webportal/admin/setup.php' => ['PhanTypeMismatchArgument'], diff --git a/dev/tools/phan/config.php b/dev/tools/phan/config.php index d45a1e422c0..2b371b1d984 100644 --- a/dev/tools/phan/config.php +++ b/dev/tools/phan/config.php @@ -462,7 +462,7 @@ return [ 'PhanPluginUnknownClosureReturnType', // When we use closure (we must avoid), we do not have PHP doc // 'PhanPluginUnknownArrayMethodParamType', // All fixed - // 'PhanPluginUnknownArrayMethodReturnType', // All fixed, except in api_* + // 'PhanPluginUnknownArrayMethodReturnType', // All fixed // 'PhanUndeclaredGlobalVariable', // Helps identify variables that are not set/defined - add '@phan-var-force TYPE $varname' in tpl or includes to help type the variable // 'PhanPluginUnknownObjectMethodCall', // False positive for some class. Is enabled in config_extended only. 'PhanTypeSuspiciousNonTraversableForeach', // Reports on `foreach ($object as $key => $value)` which works without php notices, so we ignore it because this is intentional in the code. diff --git a/dev/tools/phan/config_extended.php b/dev/tools/phan/config_extended.php index fa84a395df7..c42693162df 100644 --- a/dev/tools/phan/config_extended.php +++ b/dev/tools/phan/config_extended.php @@ -87,7 +87,7 @@ $config['suppress_issue_types'] = [ 'PhanPluginNonBoolBranch', // Not essential - 31240+ occurrences 'PhanPluginNumericalComparison', // Not essential - 19870+ occurrences - 'PhanTypeMismatchArgument', // Not showing in cti.dolibarr until low count - Can detect missing array keys, invalid types, objects being passed when scalar expected - Not all reported by phpstan - <=3800 cases (was: 12300+ before) + 'PhanTypeMismatchArgument', // Not showing in cti.dolibarr until low count - Can detect missing array keys, invalid types, objects being passed when scalar expected - Not all reported by phpstan - <=1200 cases (was: 12300+ before) 'PhanPluginNonBoolInLogicalArith', // Not essential - 11040+ occurrences 'PhanPluginConstantVariableScalar', // Not essential - 5180+ occurrences 'PhanPluginDuplicateAdjacentStatement', @@ -98,7 +98,7 @@ $config['suppress_issue_types'] = [ 'PhanPluginDuplicateCatchStatementBody', // Requires PHP7.1 - 50+ occurrences // 'PhanPluginUnknownArrayMethodParamType', // All fixed - 'PhanPluginUnknownArrayMethodReturnType', // All fixed, except in api_* at this time + // 'PhanPluginUnknownArrayMethodReturnType', // All fixed 'PhanTypeSuspiciousNonTraversableForeach', // Reports on `foreach ($object as $key => $value)` which works without php notices, so we ignore it because this is intentional in the code. ]; diff --git a/dev/tools/phan/config_fixer.php b/dev/tools/phan/config_fixer.php index 521cbcbedbf..1dc33a4c5e7 100644 --- a/dev/tools/phan/config_fixer.php +++ b/dev/tools/phan/config_fixer.php @@ -16,7 +16,8 @@ $config = include __DIR__.DIRECTORY_SEPARATOR."config.php"; //require_once __DIR__.'/plugins/SelectDateFixer.php'; //require_once __DIR__.'/plugins/setPageOrientationFixer.php'; //require_once __DIR__.'/plugins/textwithpictoFixer.php'; -require_once __DIR__.'/plugins/ifsqlFixer.php'; +//require_once __DIR__.'/plugins/ifsqlFixer.php'; +require_once __DIR__.'/plugins/writeHTMLCellFixer.php'; //require_once __DIR__.'/plugins/MultiCellFixer.php'; //require_once __DIR__.'/plugins/setAutoPageBreakFixer.php'; //require_once __DIR__.'/plugins/CellFixer.php'; diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index c6e40ccfbfc..3cd1f3cc5ac 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -1580,7 +1580,7 @@ class BookKeeping extends CommonObject $this->db->begin(); // Call triggers - if (! $error && ! $notrigger) { + if (!$notrigger) { $result = $this->call_trigger('BOOKKEEPING_DELETE', $user); if ($result < 0) { $error++; @@ -1711,11 +1711,12 @@ class BookKeeping extends CommonObject * * @param int $piecenum Piecenum to delete * @param string $mode Mode ('' or '_tmp') + * @param int $notrigger 0=launch triggers after, 1=disable triggers * @return int Nb of record deleted */ - public function deleteMvtNum($piecenum, $mode = '') + public function deleteMvtNum($piecenum, $mode = '', $notrigger = 0) { - global $conf; + global $conf, $user; $sql_filter = $this->getCanModifyBookkeepingSQL(); if (!isset($sql_filter)) { @@ -1723,34 +1724,50 @@ class BookKeeping extends CommonObject } $nbprocessed = 0; + $error = 0; $this->db->begin(); - // first check if line not yet in bookkeeping - $sql = "DELETE"; - $sql .= " FROM ".$this->db->prefix().$this->table_element.$mode; - $sql .= " WHERE piece_num = ".(int) $piecenum; - $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion - $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features - $sql .= $sql_filter; - - $resql = $this->db->query($sql); - - if (!$resql) { - $this->errors[] = "Error ".$this->db->lasterror(); - foreach ($this->errors as $errmsg) { - dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); - $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + // Call triggers + if (! $error && ! $notrigger) { + $result = $this->call_trigger('BOOKKEEPING_DELETE', $user); + if ($result < 0) { + $error++; } - $this->db->rollback(); - return -1; - } else { - $nbprocessed = $this->db->affected_rows($resql); } - $this->db->commit(); + if (!$error) { + // first check if line not yet in bookkeeping + $sql = "DELETE"; + $sql .= " FROM ".$this->db->prefix().$this->table_element.$mode; + $sql .= " WHERE piece_num = ".(int) $piecenum; + $sql .= " AND date_validated IS NULL"; // For security, exclusion of validated entries at the time of deletion + $sql .= " AND entity = " . ((int) $conf->entity); // Do not use getEntity for accounting features + $sql .= $sql_filter; - return $nbprocessed; + $resql = $this->db->query($sql); + + if (!$resql) { + $this->errors[] = "Error ".$this->db->lasterror(); + foreach ($this->errors as $errmsg) { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error .= ($this->error ? ', '.$errmsg : $errmsg); + } + $this->db->rollback(); + return -1; + } else { + $nbprocessed = $this->db->affected_rows($resql); + } + } + + // Commit or rollback + if ($error) { + $this->db->rollback(); + return -1 * $error; + } else { + $this->db->commit(); + return $nbprocessed; + } } /** @@ -2584,10 +2601,9 @@ class BookKeeping extends CommonObject /** * Get list of fiscal period ordered by start date. * - * @param string $filter Filter * @return array|int Return integer <0 if KO, Fiscal periods : [[id, date_start, date_end, label], ...] */ - public function getFiscalPeriods($filter = '') + public function getFiscalPeriods() { global $conf; $list = array(); @@ -2595,9 +2611,6 @@ class BookKeeping extends CommonObject $sql = "SELECT rowid, label, date_start, date_end, statut"; $sql .= " FROM " . $this->db->prefix() . "accounting_fiscalyear"; $sql .= " WHERE entity = " . ((int) $conf->entity); - if (!empty($filter)) { - $sql .= " AND (" . $this->db->sanitize($filter, 1, 1, 1) . ')'; - } $sql .= $this->db->order('date_start', 'ASC'); $resql = $this->db->query($sql); diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index 34ef215eb13..e1794d87f0a 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -3211,7 +3211,7 @@ class Adherent extends CommonObject $sendtocc = ''; $sendtobcc = ''; $actioncode = 'EMAIL'; - $extraparams = ''; + $extraparams = array(); $actionmsg = ''; $actionmsg2 = $langs->transnoentities('MailSentByTo', CMailFile::getValidAddress($from, 4, 0, 1), CMailFile::getValidAddress($sendto, 4, 0, 1)); diff --git a/htdocs/adherents/class/api_members.class.php b/htdocs/adherents/class/api_members.class.php index a08dc6cc2db..9d2d9cda8d5 100644 --- a/htdocs/adherents/class/api_members.class.php +++ b/htdocs/adherents/class/api_members.class.php @@ -541,7 +541,7 @@ class Members extends DolibarrApi * @param Object $object Object to clean * @return Object Object with cleaned properties */ - protected function _cleanObjectDatas($object) + public function _cleanObjectDatas($object) { // phpcs:enable $object = parent::_cleanObjectDatas($object); diff --git a/htdocs/admin/remotestore/class/externalModules.class.php b/htdocs/admin/remotestore/class/externalModules.class.php index f1e68c6978d..86dbbf4bdf8 100644 --- a/htdocs/admin/remotestore/class/externalModules.class.php +++ b/htdocs/admin/remotestore/class/externalModules.class.php @@ -190,9 +190,12 @@ class ExternalModules $url = $this->dolistore_api_url . (preg_match('/\/$/', $this->dolistore_api_url) ? '' : '/') . $resource; + $options['apikey'] = $this->dolistore_api_key; + if ($options) { $url .= '?' . http_build_query($options); } + $url .= (preg_match('/\?/', $url) ? '&' : '?').'apikey='.$this->dolistore_api_key; $response = getURLContent($url, 'GET', '', 1, $httpheader); @@ -650,10 +653,11 @@ class ExternalModules * * @param string $file_source_url URL of the remote source * @param int $cache_time Cache time - * @return string Uri of the cache file + * @return bool|string File content */ public function getRemoteYamlFile($file_source_url, $cache_time) { + $yaml = ''; $cache_file = $this->cache_file; $cache_folder = dirname($cache_file); @@ -662,8 +666,6 @@ class ExternalModules dol_mkdir($cache_folder, DOL_DATA_ROOT); } - $yaml = ''; - if (!file_exists($cache_file) || filemtime($cache_file) < (dol_now() - $cache_time)) { // We get remote url $result = getURLContent($file_source_url); diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index ceae1f08b0c..d707562f3b8 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -2,7 +2,7 @@ /* Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2016 Laurent Destailleur * Copyright (C) 2020-2025 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 @@ -29,12 +29,12 @@ require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; class DolibarrApi { /** - * @var DoliDB $db Database object + * @var DoliDB Database object */ protected $db; /** - * @var Restler $r Restler object + * @var Restler Restler object */ public $r; @@ -129,9 +129,13 @@ class DolibarrApi /** * Filter properties that will be returned on object * + * @phpstan-template T of Object + * * @param Object $object Object to clean - * @param String $properties Comma separated list of properties names + * @param string $properties Comma separated list of properties names * @return Object Object with cleaned properties + * @phpstan-param T $object + * @phpstan-return T */ protected function _filterObjectProperties($object, $properties) { diff --git a/htdocs/api/class/api_access.class.php b/htdocs/api/class/api_access.class.php index 304a2b690c5..c7c92f9514d 100644 --- a/htdocs/api/class/api_access.class.php +++ b/htdocs/api/class/api_access.class.php @@ -55,7 +55,7 @@ class DolibarrApiAccess implements iAuthenticate public $db; /** - * @var array role required by API method user / external / admin + * @var string[] role required by API method user / external / admin */ public static $requires = array('user', 'external', 'admin'); diff --git a/htdocs/categories/class/api_categories.class.php b/htdocs/categories/class/api_categories.class.php index 96af20da374..47b792a1121 100644 --- a/htdocs/categories/class/api_categories.class.php +++ b/htdocs/categories/class/api_categories.class.php @@ -69,7 +69,9 @@ class Categories extends DolibarrApi * * @param int $id ID of category * @param bool $include_childs Include child categories list (true or false) - * @return array|mixed data without useless information + * @return array Data without useless information + * @phan-return Categorie + * @phpstan-return Categorie * * @throws RestException */ @@ -115,6 +117,8 @@ class Categories extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of category objects + * @phan-return Categorie[] + * @phpstan-return Categorie[] * * @throws RestException */ @@ -217,6 +221,8 @@ class Categories extends DolibarrApi * @phan-param ?array $request_data * @phpstan-param ?array $request_data * @return Object Updated object + * @phan-return Categorie + * @phpstan-return Categorie */ public function put($id, $request_data = null) { @@ -306,6 +312,8 @@ class Categories extends DolibarrApi * @param int $limit Limit for list * @param int $page Page number * @return array Array of category objects + * @phan-return array,visible:int,ref_ext:string,multilangs?:array}> + * @phpstan-return array,visible:int,ref_ext:string,multilangs?:array}> * * @throws RestException * @@ -360,6 +368,8 @@ class Categories extends DolibarrApi * @param int $object_id ID of object * * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} * @throws RestException * * @url POST {id}/objects/{type}/{object_id} @@ -441,6 +451,8 @@ class Categories extends DolibarrApi * @param string $object_ref Reference of object * * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} * @throws RestException * * @url POST {id}/objects/{type}/ref/{object_ref} @@ -522,6 +534,8 @@ class Categories extends DolibarrApi * @param int $object_id ID of the object * * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} * @throws RestException * * @url DELETE {id}/objects/{type}/{object_id} @@ -601,6 +615,8 @@ class Categories extends DolibarrApi * @param string $object_ref Reference of the object * * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} * @throws RestException * * @url DELETE {id}/objects/{type}/ref/{object_ref} diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 2cc989ecbf3..ca01e2935fb 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -1,18 +1,19 @@ - * Copyright (C) 2005 Davoleau Brice - * Copyright (C) 2005 Rodolphe Quiedeville - * Copyright (C) 2006-2012 Regis Houssin - * Copyright (C) 2006-2012 Laurent Destailleur - * Copyright (C) 2007 Patrick Raguin - * Copyright (C) 2013-2016 Juanjo Menent - * Copyright (C) 2013-2018 Philippe Grand - * Copyright (C) 2015 Marcos García - * Copyright (C) 2015 Raphaël Doursenaud - * Copyright (C) 2016-2024 Charlene Benke - * Copyright (C) 2018-2025 Frédéric France - * Copyright (C) 2023-2024 Benjamin Falière - * Copyright (C) 2024 MDW +/* Copyright (C) 2005 Matthieu Valleton + * Copyright (C) 2005 Davoleau Brice + * Copyright (C) 2005 Rodolphe Quiedeville + * Copyright (C) 2006-2012 Regis Houssin + * Copyright (C) 2006-2012 Laurent Destailleur + * Copyright (C) 2007 Patrick Raguin + * Copyright (C) 2013-2016 Juanjo Menent + * Copyright (C) 2013-2018 Philippe Grand + * Copyright (C) 2015 Marcos García + * Copyright (C) 2015 Raphaël Doursenaud + * Copyright (C) 2016-2024 Charlene Benke + * Copyright (C) 2018-2025 Frédéric France + * Copyright (C) 2022-2023 Solution Libre SAS + * Copyright (C) 2023-2024 Benjamin Falière + * Copyright (C) 2024 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 @@ -64,6 +65,7 @@ class Categorie extends CommonObject const TYPE_KNOWLEDGEMANAGEMENT = 'knowledgemanagement'; const TYPE_FICHINTER = 'fichinter'; const TYPE_ORDER = 'order'; + const TYPE_INVOICE = 'invoice'; /** * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png @@ -91,6 +93,7 @@ class Categorie extends CommonObject 'knowledgemanagement' => 13, 'fichinter' => 14, 'order' => 16, + 'invoice' => 17, ); /** @@ -115,6 +118,7 @@ class Categorie extends CommonObject 13 => 'knowledgemanagement', 14 => 'fichinter', 16 => 'order', + 17 => 'invoice', ); /** @@ -162,6 +166,7 @@ class Categorie extends CommonObject 'knowledgemanagement' => 'KnowledgeRecord', 'fichinter' => 'Fichinter', 'order' => 'Commande', + 'invoice' => 'Facture' ); /** @@ -186,6 +191,7 @@ class Categorie extends CommonObject 'knowledgemanagement' => 'KnowledgemanagementsCategoriesArea', 'fichinter' => 'FichintersCategoriesArea', 'order' => 'OrderCategoriesArea', + 'invoice' => 'InvoiceCategoriesArea' ); /** @@ -203,6 +209,7 @@ class Categorie extends CommonObject 'knowledgemanagement' => 'knowledgemanagement_knowledgerecord', 'fichinter' => 'fichinter', 'order' => 'commande', + 'invoice' => 'facture' ); /** @@ -268,6 +275,7 @@ class Categorie extends CommonObject * @see Categorie::TYPE_TICKET * @see Categorie::TYPE_FICHINTER * @see Categorie::TYPE_ORDER + * @see Categorie::TYPE_INVOICE */ public $type; diff --git a/htdocs/categories/viewcat.php b/htdocs/categories/viewcat.php index f3108ad6023..aeb42e48008 100644 --- a/htdocs/categories/viewcat.php +++ b/htdocs/categories/viewcat.php @@ -6,9 +6,10 @@ * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2020 Tobias Sekan * Copyright (C) 2020 Josep Lluís Amador + * Copyright (C) 2022-2023 Solution Libre SAS * Copyright (C) 2024 MDW * Copyright (C) 2024 Frédéric France - * Copyright (C) 2024 Alexandre Spangaro + * Copyright (C) 2024-2025 Alexandre Spangaro * Copyright (C) 2023-2024 Charlene Benke * * This program is free software; you can redistribute it and/or modify @@ -176,6 +177,11 @@ if ($id > 0 && $removeelem > 0 && $action == 'unlink') { // Test on permission n $tmpobject = new Commande($db); $result = $tmpobject->fetch($removeelem); $elementtype = 'order'; + } elseif ($type == Categorie::TYPE_INVOICE && $user->hasRight('facture', 'creer')) { + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + $tmpobject = new Facture($db); + $result = $tmpobject->fetch($removeelem); + $elementtype = 'invoice'; } else { dol_print_error(null, "Not supported value of type = ".$type); } @@ -247,6 +253,10 @@ if ($elemid && $action == 'addintocategory') { // Test on permission not require require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; $newobject = new Commande($db); $elementtype = 'order'; + } elseif ($type == Categorie::TYPE_INVOICE && $user->hasRight('facture', 'creer')) { + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + $newobject = new Facture($db); + $elementtype = 'invoice'; } else { dol_print_error(null, "Not supported value of type = ".$type); } @@ -1498,6 +1508,84 @@ if ($type == Categorie::TYPE_ORDER) { } } +// List of Invoices +if ($type == Categorie::TYPE_INVOICE) { + require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; + + $permission = $user->rights->facture->creer; + + $objects = $object->getObjectsInCateg($type, 0, $limit, $offset); + if ($objects < 0) { + dol_print_error($db, $object->error, $object->errors); + } else { + // Form to add record into a category + $showclassifyform = $user->hasRight('facture', 'write'); + if ($showclassifyform) { + print '
'; + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print $langs->trans("AddInvoiceIntoCategory").'  '; + $form->selectInvoice(-1, '', 'elemid', 24, 0, '1', 0, 0, 0, 'maxwidth500', '', ''); + print '
'; + print '
'; + } + + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + + print '
'; + $param = '&limit='.$limit.'&id='.$id.'&type='.$type; $num = count($objects); $nbtotalofrecords = ''; $newcardbutton = ''; + + // @phan-suppress-next-line PhanPluginSuspiciousParamOrder + print_barre_liste($langs->trans("BillsCustomers"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'bill', 0, $newcardbutton, '', $limit); + + print "\n"; + print ''."\n"; + + if (count($objects) > 0) { + $i = 0; + foreach ($objects as $key => $invoice) { + $i++; + if ($i > $limit) { + break; + } + + print "\t".''."\n"; + print '\n"; + print '\n"; + // Link to delete from category + print '\n"; + } + } else { + print ''; + } + print "
'.$langs->trans("Ref").'
'; + print $invoice->getNomUrl(1); + print "'.$invoice->ref."'; + if ($permission) { + print ""; + print $langs->trans("DeleteFromCat"); + print img_picto($langs->trans("DeleteFromCat"), 'unlink', '', 0, 0, 0, '', 'paddingleft'); + print ""; + } + print "
'.$langs->trans("ThisCategoryHasNoItems").'
\n"; + + print '
'."\n"; + } +} + // Note that $action and $object may have been modified by some hooks $parameters = array('type' => $type, 'id' => $id, 'label' => $label); $reshook = $hookmanager->executeHooks('addMoreCategoriesList', $parameters, $object, $action); diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index bb38c246127..dd5f369cd4e 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -307,7 +307,7 @@ class ActionComm extends CommonObject public $icalcolor; /** - * @var string Extraparam + * @var array|string Extra parameters. Try to store here the array of parameters. Old code is sometimes storing a string. */ public $extraparams; @@ -531,6 +531,9 @@ class ActionComm extends CommonObject return -1; } + $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null); + $extraparams = dol_trunc($extraparams, 250); + $this->db->begin(); $sql = "INSERT INTO ".MAIN_DB_PREFIX."actioncomm"; @@ -592,11 +595,11 @@ class ActionComm extends CommonObject $sql .= "'".$this->db->escape($this->fulldayevent)."', "; $sql .= "'".$this->db->escape($this->location)."', "; $sql .= "'".$this->db->escape($this->transparency)."', "; - $sql .= (!empty($this->fk_element) ? ((int) $this->fk_element) : "null").", "; + $sql .= (!empty($this->elementid) ? ((int) $this->elementid) : "null").", "; $sql .= (!empty($this->elementtype) ? "'".$this->db->escape($this->elementtype)."'" : "null").", "; $sql .= (!empty($this->fk_bookcal_calendar) ? "'".$this->db->escape($this->fk_bookcal_calendar)."'" : "null").", "; $sql .= ((int) $conf->entity).","; - $sql .= (!empty($this->extraparams) ? "'".$this->db->escape($this->extraparams)."'" : "null").", "; + $sql .= (!empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null").", "; // Fields emails $sql .= (!empty($this->email_msgid) ? "'".$this->db->escape($this->email_msgid)."'" : "null").", "; $sql .= (!empty($this->email_from) ? "'".$this->db->escape($this->email_from)."'" : "null").", "; @@ -1639,10 +1642,10 @@ class ActionComm extends CommonObject $datas['space'] = '
'; // $datas['email'] = '
'.img_picto('', 'email').' '.$langs->trans("Email").''; $datas['mailtopic'] = '
'.$langs->trans('MailTopic').': '.dol_escape_htmltag($this->email_subject); - $datas['mailfrom'] = '
'.$langs->trans('MailFrom').': '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_from); - $datas['mailto'] = '
'.$langs->trans('MailTo').': '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_to); + $datas['mailfrom'] = '
'.$langs->trans('MailFrom').': '.dol_htmlentities($this->email_from); + $datas['mailto'] = '
'.$langs->trans('MailTo').': '.dol_htmlentities($this->email_to); if (!empty($this->email_tocc)) { - $datas['mailcc'] = '
'.$langs->trans('MailCC').': '.str_replace(array('<', '>'), array('&lt', '&gt'), $this->email_tocc); + $datas['mailcc'] = '
'.$langs->trans('MailCC').': '.dol_htmlentities($this->email_tocc); } /* Disabled because bcc must remain by definition not visible if (!empty($this->email_tobcc)) { diff --git a/htdocs/comm/action/class/api_agendaevents.class.php b/htdocs/comm/action/class/api_agendaevents.class.php index 3f9b20893e8..c89e7b6cb20 100644 --- a/htdocs/comm/action/class/api_agendaevents.class.php +++ b/htdocs/comm/action/class/api_agendaevents.class.php @@ -37,7 +37,7 @@ class AgendaEvents extends DolibarrApi ); /** - * @var ActionComm {@type ActionComm} + * @var ActionComm {@type ActionActionCom} */ public $actioncomm; @@ -104,6 +104,8 @@ class AgendaEvents extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of order objects + * @phan-return ActionComm[]|array{data:ActionComm[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return ActionComm[]|array{data:ActionComm[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.id", $sortorder = 'ASC', $limit = 100, $page = 0, $user_ids = '', $sqlfilters = '', $properties = '', $pagination_data = false) { @@ -197,7 +199,7 @@ class AgendaEvents extends DolibarrApi $obj_ret['pagination'] = [ 'total' => (int) $total, 'page' => $page, //count starts from 0 - 'page_count' => ceil((int) $total / $limit), + 'page_count' => (int) ceil((int) $total / $limit), 'limit' => $limit ]; } @@ -272,7 +274,7 @@ class AgendaEvents extends DolibarrApi if ($result) { $this->actioncomm->fetch_optionals(); $this->actioncomm->fetch_userassigned(); - $this->actioncomm->oldcopy = clone $this->actioncomm; + $this->actioncomm->oldcopy = clone $this->actioncomm; // @phan-suppress-current-line PhanTypeMismatchProperty } if (!$result) { throw new RestException(404, 'actioncomm not found'); @@ -326,7 +328,7 @@ class AgendaEvents extends DolibarrApi if ($result) { $this->actioncomm->fetch_optionals(); $this->actioncomm->fetch_userassigned(); - $this->actioncomm->oldcopy = clone $this->actioncomm; + $this->actioncomm->oldcopy = clone $this->actioncomm; // @phan-suppress-current-line PhanTypeMismatchProperty } if (!DolibarrApiAccess::$user->hasRight('agenda', 'allactions', 'delete') && DolibarrApiAccess::$user->id != $this->actioncomm->userownerid) { diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php index 54a017d39b7..419e13369ab 100644 --- a/htdocs/comm/propal/class/api_proposals.class.php +++ b/htdocs/comm/propal/class/api_proposals.class.php @@ -35,7 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; class Proposals extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid' @@ -162,6 +162,8 @@ class Proposals extends DolibarrApi * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @param int $loadlinkedobjects Load also linked object * @return array Array of order objects + * @phan-return Propal[]|array{data:Propal[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Propal[]|array{data:Propal[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $properties = '', $pagination_data = false, $loadlinkedobjects = 0) { @@ -315,6 +317,8 @@ class Proposals extends DolibarrApi * @url GET {id}/lines * * @return array + * @phan-return PropaleLigne[] + * @phpstan-return PropaleLigne[] */ public function getLines($id, $sqlfilters = '') { @@ -620,6 +624,8 @@ class Proposals extends DolibarrApi * @param string $type Type of the external contact (BILLING, SHIPPING, CUSTOMER), internal contact (SALESREPFOLL) * @param string $source Source of the contact (internal, external) * @return array + * @phan-return array{success:array{code:int,message:string}} + * @phpstan-return array{success:array{code:int,message:string}} * * @url POST {id}/contact/{contactid}/{type}/{source} * diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 21f638a28a0..2015e1208c6 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -2669,11 +2669,11 @@ class Propal extends CommonObject if ($resql) { // Status self::STATUS_REFUSED by default $modelpdf = getDolGlobalString('PROPALE_ADDON_PDF_ODT_CLOSED', $this->model_pdf); - $trigger_name = 'PROPAL_CLOSE_REFUSED'; // used later in call_trigger() + $triggerName = 'PROPAL_CLOSE_REFUSED'; // used later in call_trigger() - if ($status == self::STATUS_SIGNED) { // Status self::STATUS_SIGNED - $trigger_name = 'PROPAL_CLOSE_SIGNED'; // used later in call_trigger() - $modelpdf = getDolGlobalString('PROPALE_ADDON_PDF_ODT_TOBILL') ? $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL : $this->model_pdf; + if ($status == self::STATUS_SIGNED) { // Status self::STATUS_SIGNED + $triggerName = 'PROPAL_CLOSE_SIGNED'; // used later in call_trigger() + $modelpdf = getDolGlobalString('PROPALE_ADDON_PDF_ODT_TOBILL', $this->model_pdf); // The connected company is classified as a client $soc = new Societe($this->db); @@ -2715,7 +2715,7 @@ class Propal extends CommonObject if (!$notrigger && empty($error)) { // Call trigger - $result = $this->call_trigger($trigger_name, $user); + $result = $this->call_trigger($triggerName, $user); if ($result < 0) { $error++; } diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index 79e32cc27d7..2241d832830 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -1853,11 +1853,11 @@ while ($i < $imaxinloop) { print ''; } } else { - print ''; + print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { - print ''; + print ''; if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->rowid, $arrayofselected)) { diff --git a/htdocs/commande/agenda.php b/htdocs/commande/agenda.php index aa4a1ff44ff..4d238daf252 100644 --- a/htdocs/commande/agenda.php +++ b/htdocs/commande/agenda.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 @@ -166,7 +167,7 @@ if ($object->id > 0) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index 913dc87d333..82569c9031a 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -15,7 +15,7 @@ * Copyright (C) 2018-2025 Frédéric France * Copyright (C) 2022 Gauthier VERDOL * Copyright (C) 2023-2024 Benjamin Falière - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2025 Lenin Rivas * * This program is free software; you can redistribute it and/or modify @@ -608,7 +608,7 @@ if (empty($reshook)) { } elseif ($action == 'setabsolutediscount' && $usercancreate) { if (GETPOST('remise_id')) { if ($object->id > 0) { - $object->insert_discount(GETPOST('remise_id')); + $object->insert_discount(GETPOSTINT('remise_id')); } else { dol_print_error($db, $object->error); } @@ -640,12 +640,12 @@ if (empty($reshook)) { // Multicurrency rate $result = $object->setMulticurrencyRate(GETPOSTFLOAT('multicurrency_tx'), GETPOSTINT('calculation_mode')); } elseif ($action == 'setavailability' && $usercancreate) { - $result = $object->availability(GETPOST('availability_id')); + $result = $object->availability(GETPOSTINT('availability_id')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } } elseif ($action == 'setdemandreason' && $usercancreate) { - $result = $object->demand_reason(GETPOST('demand_reason_id')); + $result = $object->demand_reason(GETPOSTINT('demand_reason_id')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -719,7 +719,7 @@ if (empty($reshook)) { $localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc); $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc); foreach ($object->lines as $line) { - $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $line->remise_percent, (float) $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); } } elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) { // Define remise_percent @@ -730,7 +730,7 @@ if (empty($reshook)) { if (!empty($line->vat_src_code)) { $tvatx .= ' ('.$line->vat_src_code.')'; } - $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $remise_percent, $tvatx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); + $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, (float) $remise_percent, $tvatx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->date_start, $line->date_end, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->fk_unit, $line->multicurrency_subprice); } } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && $usercancreate) { // Add a new line $langs->load('errors'); @@ -870,7 +870,7 @@ if (empty($reshook)) { $prodcustprice = new ProductCustomerPrice($db); - $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id); + $filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id); // If a price per customer exist $pricebycustomerexist = false; @@ -939,7 +939,7 @@ if (empty($reshook)) { $prodcustprice = new ProductCustomerPrice($db); - $filter = array('t.fk_product' => $prod->id, 't.fk_soc' => $object->thirdparty->id); + $filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id); $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); if ($result >= 0) { @@ -1136,7 +1136,7 @@ if (empty($reshook)) { $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty); // Margin - $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOST('fournprice'.$predef) : ''); + $fournprice = price2num(GETPOST('fournprice'.$predef) ? GETPOSTINT('fournprice'.$predef) : 0); $buyingprice = price2num(GETPOST('buying_price'.$predef) != '' ? GETPOST('buying_price'.$predef) : ''); // If buying_price is '0', we must keep this value // Prepare a price equivalent for minimum price check @@ -1182,7 +1182,7 @@ if (empty($reshook)) { if (!$error) { // Insert line - $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $info_bits, 0, $price_base_type, $pu_ttc, $date_start, $date_end, $type, min($rank, count($object->lines) + 1), 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_options, $fk_unit, '', 0, $pu_ht_devise); + $result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $info_bits, 0, $price_base_type, $pu_ttc, $date_start, $date_end, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), $fournprice, (float) $buyingprice, $label, $array_options, $fk_unit, '', 0, (float) $pu_ht_devise); if ($result > 0) { $ret = $object->fetch($object->id); // Reload to get new records @@ -1395,7 +1395,7 @@ if (empty($reshook)) { $price_base_type = 'TTC'; } - $result = $object->updateline(GETPOSTINT('lineid'), $description, $pu, $qty, $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $price_base_type, $info_bits, $date_start, $date_end, $type, GETPOST('fk_parent_line'), 0, $fournprice, $buyingprice, $label, $special_code, $array_options, GETPOST('units'), $pu_ht_devise); + $result = $object->updateline(GETPOSTINT('lineid'), $description, (float) $pu, (float) $qty, $remise_percent, (float) $vat_rate, $localtax1_rate, $localtax2_rate, $price_base_type, $info_bits, $date_start, $date_end, $type, GETPOSTINT('fk_parent_line'), 0, $fournprice, $buyingprice, $label, $special_code, $array_options, GETPOSTINT('units'), (float) $pu_ht_devise); if ($result >= 0) { if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) { @@ -1625,7 +1625,7 @@ if (empty($reshook)) { } if ($action == 'update_extras' && $usercancreate) { - $object->oldcopy = dol_clone($object, 2); + $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty $attribute_name = GETPOST('attribute', 'restricthtml'); // Fill array 'array_options' with data from update form @@ -1743,7 +1743,7 @@ if (empty($reshook)) { if (!$error && getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB') && $usercancreate) { if ($action == 'addcontact' && $usercancreate) { if ($object->id > 0) { - $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); + $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid')); $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); } @@ -2070,13 +2070,13 @@ if ($action == 'create' && $usercancreate) { // Terms of payment print ''.$langs->trans('PaymentConditionsShort').''; print img_picto('', 'payment', 'class="pictofixedwidth"'); - print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, 'maxwidth200 widthcentpercentminusx', $deposit_percent); + print $form->getSelectConditionsPaiements($cond_reglement_id, 'cond_reglement_id', 1, 1, 0, 'maxwidth200 widthcentpercentminusx', (float) $deposit_percent); print ''; // Payment mode print ''.$langs->trans('PaymentMode').''; print img_picto('', 'bank', 'class="pictofixedwidth"'); - print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1); + print $form->select_types_paiements((string) $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1); print ''; // Bank Account @@ -2125,7 +2125,7 @@ if ($action == 'create' && $usercancreate) { // Incoterms if (isModEnabled('incoterm')) { print ''; - print ''; + print ''; print ''; $incoterm_id = GETPOST('incoterm_id'); $location_incoterms = GETPOST('location_incoterms'); @@ -2176,7 +2176,7 @@ if ($action == 'create' && $usercancreate) { print ''; print ''.$form->editfieldkey("Currency", 'multicurrency_code', '', $object, 0).''; print ''; - print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', 0, 'maxwidth200 widthcentpercentminusx'); + print img_picto('', 'currency', 'class="pictofixedwidth"').$form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx'); print ''; } @@ -2194,7 +2194,7 @@ if ($action == 'create' && $usercancreate) { print ''.$langs->trans('NotePublic').''; print ''; - $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%'); + $doleditor = new DolEditor('note_public', (string) $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%'); print $doleditor->Create(1); // print ''; print ''; @@ -2205,7 +2205,7 @@ if ($action == 'create' && $usercancreate) { print ''.$langs->trans('NotePrivate').''; print ''; - $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%'); + $doleditor = new DolEditor('note_private', (string) $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%'); print $doleditor->Create(1); // print ''; print ''; @@ -2603,8 +2603,8 @@ if ($action == 'create' && $usercancreate) { $morehtmlref = '
'; // Ref customer - $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1); + $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, (int) $usercancreate, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, (int) $usercancreate, 'string'.(isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1); // Thirdparty $morehtmlref .= '
'.$soc->getNomUrl(1, 'customer'); if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) { @@ -2619,7 +2619,7 @@ if ($action == 'create' && $usercancreate) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); @@ -2689,7 +2689,7 @@ if ($action == 'create' && $usercancreate) { // Date print ''; $editenable = $usercancreate && $object->statut == Commande::STATUS_DRAFT; - print $form->editfieldkey("Date", 'date', '', $object, $editenable); + print $form->editfieldkey("Date", 'date', '', $object, (int) $editenable); print ''; if ($action == 'editdate') { print '
'; @@ -2711,7 +2711,7 @@ if ($action == 'create' && $usercancreate) { // Delivery date planned print ''; $editenable = $usercancreate; - print $form->editfieldkey("DateDeliveryPlanned", 'date_livraison', '', $object, $editenable); + print $form->editfieldkey("DateDeliveryPlanned", 'date_livraison', '', $object, (int) $editenable); print ''; if ($action == 'editdate_livraison') { print ''; @@ -2733,12 +2733,12 @@ if ($action == 'create' && $usercancreate) { // Delivery delay print ''; $editenable = $usercancreate; - print $form->editfieldkey("AvailabilityPeriod", 'availability', '', $object, $editenable); + print $form->editfieldkey("AvailabilityPeriod", 'availability', '', $object, (int) $editenable); print ''; if ($action == 'editavailability') { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'availability_id', 1); + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'availability_id', 1); } else { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, $object->availability_id, 'none', 1); + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->availability_id, 'none', 1); } print ''; @@ -2746,12 +2746,12 @@ if ($action == 'create' && $usercancreate) { if (isModEnabled('shipping')) { print ''; $editenable = $usercancreate; - print $form->editfieldkey("SendingMethod", 'shippingmethod', '', $object, $editenable); + print $form->editfieldkey("SendingMethod", 'shippingmethod', '', $object, (int) $editenable); print ''; if ($action == 'editshippingmethod') { - $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1); + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'shipping_method_id', 1); } else { - $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none'); + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->shipping_method_id, 'none'); } print ''; print ''; @@ -2764,7 +2764,7 @@ if ($action == 'create' && $usercancreate) { $formproduct = new FormProduct($db); print ''; $editenable = $usercancreate; - print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable); + print $form->editfieldkey("Warehouse", 'warehouse', '', $object, (int) $editenable); print ''; if ($action == 'editwarehouse') { $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1); @@ -2778,24 +2778,24 @@ if ($action == 'create' && $usercancreate) { // Source reason (why we have an order) print ''; $editenable = $usercancreate; - print $form->editfieldkey("Source", 'demandreason', '', $object, $editenable); + print $form->editfieldkey("Source", 'demandreason', '', $object, (int) $editenable); print ''; if ($action == 'editdemandreason') { - $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'demand_reason_id', 1); + $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'demand_reason_id', 1); } else { - $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, $object->demand_reason_id, 'none'); + $form->formInputReason($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->demand_reason_id, 'none'); } print ''; // Terms of payment print ''; $editenable = $usercancreate; - print $form->editfieldkey("PaymentConditionsShort", 'conditions', '', $object, $editenable); + print $form->editfieldkey("PaymentConditionsShort", 'conditions', '', $object, (int) $editenable); print ''; if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 1, '', 1, $object->deposit_percent); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id', 1, '', 1, $object->deposit_percent); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 1, '', 1, $object->deposit_percent); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'none', 1, '', 1, $object->deposit_percent); } print ''; @@ -2804,12 +2804,12 @@ if ($action == 'create' && $usercancreate) { // Mode of payment print ''; $editenable = $usercancreate; - print $form->editfieldkey("PaymentMode", 'mode', '', $object, $editenable); + print $form->editfieldkey("PaymentMode", 'mode', '', $object, (int) $editenable); print ''; if ($action == 'editmode') { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); } else { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none'); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'none'); } print ''; @@ -2849,7 +2849,7 @@ if ($action == 'create' && $usercancreate) { if (isModEnabled('incoterm')) { print ''; $editenable = $usercancreate; - print $form->editfieldkey("IncotermLabel", 'incoterm', '', $object, $editenable); + print $form->editfieldkey("IncotermLabel", 'incoterm', '', $object, (int) $editenable); print ''; print ''; if ($action != 'editincoterm') { @@ -2864,12 +2864,12 @@ if ($action == 'create' && $usercancreate) { if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_ORDER') && isModEnabled("bank")) { print ''; $editenable = $usercancreate; - print $form->editfieldkey("BankAccount", 'bankaccount', '', $object, $editenable); + print $form->editfieldkey("BankAccount", 'bankaccount', '', $object, (int) $editenable); print ''; if ($action == 'editbankaccount') { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1); } else { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none'); } print ''; print ''; @@ -2896,7 +2896,7 @@ if ($action == 'create' && $usercancreate) { print ''; $c = new Categorie($db); $cats = $c->containing($object->id, Categorie::TYPE_ORDER); - $arrayselected=[]; + $arrayselected = []; foreach ($cats as $cat) { $arrayselected[] = $cat->id; } @@ -3101,9 +3101,9 @@ if ($action == 'create' && $usercancreate) { // Valid if ($object->statut == Commande::STATUS_DRAFT && ($object->total_ttc >= 0 || getDolGlobalString('ORDER_ENABLE_NEGATIVE')) && $usercanvalidate) { if ($numlines > 0) { - print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=validate&token='.newToken().'&id='.$object->id, $object->id, 1); + print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=validate&token='.newToken().'&id='.$object->id, (string) $object->id, 1); } else { - print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=validate&token='.newToken().'&id='.$object->id, $object->id, 0); + print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans('Validate'), 'default', $_SERVER["PHP_SELF"].'?action=validate&token='.newToken().'&id='.$object->id, (string) $object->id, 0); } } // Edit @@ -3213,9 +3213,9 @@ if ($action == 'create' && $usercancreate) { ]; if ($numlines > 0) { - print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 1, $actionButtonsParameters); + print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 1, $actionButtonsParameters); } else { - print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, $object->id, 0, $actionButtonsParameters); + print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 0, $actionButtonsParameters); } // Set to shipped @@ -3273,7 +3273,7 @@ if ($action == 'create' && $usercancreate) { $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; $genallowed = $usercanread; $delallowed = $usercancreate; - print $formfile->showdocuments('commande', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang, '', $object); + print $formfile->showdocuments('commande', $objref, $filedir, $urlsource, $genallowed, (int) $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang, '', $object); // Show links to link elements diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php index 5ebaec4be86..69f467d2b51 100644 --- a/htdocs/commande/class/api_orders.class.php +++ b/htdocs/commande/class/api_orders.class.php @@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; class Orders extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid', @@ -164,6 +164,8 @@ class Orders extends DolibarrApi * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @param int $loadlinkedobjects Load also linked object * @return array Array of order objects + * @phan-return Commande[]|array{data:Commande[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Commande[]|array{data:Commande[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException 404 Not found * @throws RestException 503 Error @@ -336,6 +338,8 @@ class Orders extends DolibarrApi * @url GET {id}/lines * * @return array + * @phan-return OrderLine[] + * @phpstan-return OrderLine[] */ public function getLines($id) { @@ -1035,6 +1039,8 @@ class Orders extends DolibarrApi * @url GET {id}/shipment * * @return array + * @phan-return Expedition[] + * @phpstan-return Expedition[] * * @throws RestException 401 * @throws RestException 404 diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 3673db2be8c..f6f3ee64ce3 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -1019,14 +1019,14 @@ class Commande extends CommonOrder $sql .= " VALUES ('(PROV)', ".((int) $this->socid).", '".$this->db->idate($now)."', ".((int) $user->id); $sql .= ", ".($this->fk_project > 0 ? ((int) $this->fk_project) : "null"); $sql .= ", '".$this->db->idate($date)."'"; - $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null'); + $sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape((string) $this->source) : 'null'); $sql .= ", '".$this->db->escape($this->note_private)."'"; $sql .= ", '".$this->db->escape($this->note_public)."'"; $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null"); $sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null"); $sql .= ", '".$this->db->escape($this->model_pdf)."'"; $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null"); - $sql .= ", ".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null"); + $sql .= ", ".(!empty($this->deposit_percent) ? "'".$this->db->escape((string) $this->deposit_percent)."'" : "null"); $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null"); $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL'); $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null"); @@ -1114,7 +1114,7 @@ class Commande extends CommonOrder $line->label, $line->array_options, $line->fk_unit, - $origintype, + (string) $origintype, $originid, 0, $line->ref_ext, @@ -1535,19 +1535,19 @@ class Commande extends CommonOrder * @param float $pu_ttc Prix unitaire TTC * @param int|string $date_start Start date of the line - Added by Matelli (See http://matelli.fr/showcases/patchs-dolibarr/add-dates-in-order-lines.html) * @param int|string $date_end End date of the line - Added by Matelli (See http://matelli.fr/showcases/patchs-dolibarr/add-dates-in-order-lines.html) - * @param int $type Type of line (0=product, 1=service). Not used if fk_product is defined, the type of product is used. + * @param int<0,1> $type Type of line (0=product, 1=service). Not used if fk_product is defined, the type of product is used. * @param int $rang Position of line * @param int $special_code Special code (also used by externals modules!) * @param int $fk_parent_line Parent line * @param int $fk_fournprice Id supplier price - * @param int $pa_ht Buying price (without tax) + * @param float $pa_ht Buying price (without tax) * @param string $label Label - * @param array $array_options extrafields array. Example array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) + * @param array $array_options Extrafields array. Example array('options_codeforfield1'=>'valueforfield1', 'options_codeforfield2'=>'valueforfield2', ...) * @param ?int $fk_unit Code of the unit to use. Null to use the default one * @param string $origin Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be 'orderdet', 'propaldet'..., else 'order','propal,'.... * @param int $origin_id Depend on global conf MAIN_CREATEFROM_KEEP_LINE_ORIGIN_INFORMATION can be Id of origin object (aka line id), else object id * @param float $pu_ht_devise Unit price in currency - * @param string $ref_ext line external reference + * @param string $ref_ext Line external reference * @param int $noupdateafterinsertline No update after insert of line * @return int >0 if OK, <0 if KO * @@ -1680,7 +1680,7 @@ class Commande extends CommonOrder $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. } - $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise); + $tabprice = calcul_price_total($qty, (float) $pu, $remise_percent, $txtva, (float) $txlocaltax1, (float) $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_ht_devise); /*var_dump($txlocaltax1); var_dump($txlocaltax2); @@ -3142,7 +3142,7 @@ class Commande extends CommonOrder $txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate. } - $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, $pu_ht_devise); + $tabprice = calcul_price_total($qty, (float) $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, 100, $this->multicurrency_tx, (float) $pu_ht_devise); $total_ht = $tabprice[0]; $total_tva = $tabprice[1]; diff --git a/htdocs/commande/class/orderline.class.php b/htdocs/commande/class/orderline.class.php index ecec0f20fb8..28c5e9851f5 100644 --- a/htdocs/commande/class/orderline.class.php +++ b/htdocs/commande/class/orderline.class.php @@ -13,7 +13,7 @@ * Copyright (C) 2016-2022 Ferran Marcet * Copyright (C) 2021-2024 Frédéric France * Copyright (C) 2022 Gauthier VERDOL - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 William Mead * * This program is free software; you can redistribute it and/or modify @@ -427,7 +427,7 @@ class OrderLine extends CommonOrderLine $sql .= ' fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; $sql .= ')'; $sql .= " VALUES (".$this->fk_commande.","; - $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").","; + $sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape((string) $this->fk_parent_line)."'" : "null").","; $sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").","; $sql .= " '".$this->db->escape($this->desc)."',"; $sql .= " '".price2num($this->qty)."',"; @@ -439,7 +439,7 @@ class OrderLine extends CommonOrderLine $sql .= " '".$this->db->escape($this->localtax1_type)."',"; $sql .= " '".$this->db->escape($this->localtax2_type)."',"; $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").','; - $sql .= " '".$this->db->escape($this->product_type)."',"; + $sql .= " '".$this->db->escape((string) $this->product_type)."',"; $sql .= " '".price2num($this->remise_percent)."',"; $sql .= " ".(price2num($this->subprice) !== '' ? price2num($this->subprice) : "null").","; $sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").","; diff --git a/htdocs/commande/contact.php b/htdocs/commande/contact.php index 0f105e235cd..0c7a161e6ef 100644 --- a/htdocs/commande/contact.php +++ b/htdocs/commande/contact.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2011-2022 Philippe Grand * Copyright (C) 2021-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 @@ -66,7 +67,7 @@ $object = new Commande($db); * Actions */ -$parameters = array('id'=>$id); +$parameters = array('id' => $id); $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); if ($reshook < 0) { setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); @@ -161,7 +162,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/commande/document.php b/htdocs/commande/document.php index 82fb2fdbeb5..384b99daa39 100644 --- a/htdocs/commande/document.php +++ b/htdocs/commande/document.php @@ -6,6 +6,7 @@ * Copyright (C) 2013 Cédric Salvador * Copyright (C) 2017 Ferran Marcet * 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 @@ -154,7 +155,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index 10db3c8d9b1..529ac0ee9d3 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -12,7 +12,7 @@ * Copyright (C) 2016-2023 Ferran Marcet * Copyright (C) 2018-2023 Charlene Benke * Copyright (C) 2021-2024 Anthony Berton - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Noé Cendrier * Copyright (C) 2024 Benjamin Falière * Copyright (C) 2024 Alexandre Spangaro @@ -200,49 +200,49 @@ if (empty($user->socid)) { $checkedtypetiers = 0; $arrayfields = array( - 'c.rowid' => array('label' => "ID", 'checked' => 1, 'enabled' => getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID'), 'position' => 1), - 'c.ref' => array('label' => "Ref", 'checked' => 1, 'position' => 5, 'searchall' => 1), - 'c.ref_ext' => array('label' => "RefExt", 'checked' => 1, 'position' => 5, 'visible' => 0, 'searchall' => 1), - 'c.ref_client' => array('label' => "RefCustomerOrder", 'checked' => -1, 'position' => 10, 'searchall' => 1), - 'p.ref' => array('label' => "ProjectRef", 'checked' => -1, 'enabled' => (!isModEnabled('project') ? 0 : 1), 'position' => 20), - 'p.title' => array('label' => "ProjectLabel", 'checked' => 0, 'enabled' => (!isModEnabled('project') ? 0 : 1), 'position' => 25), - 's.nom' => array('label' => "ThirdParty", 'checked' => 1, 'position' => 30, 'searchall' => 1), - 's.name_alias' => array('label' => "AliasNameShort", 'checked' => -1, 'position' => 31, 'searchall' => 1), - 's2.nom' => array('label' => 'ParentCompany', 'position' => 32, 'checked' => 0), - 's.town' => array('label' => "Town", 'checked' => -1, 'position' => 35, 'searchall' => 1), - 's.zip' => array('label' => "Zip", 'checked' => -1, 'position' => 40, 'searchall' => 1), - 'state.nom' => array('label' => "StateShort", 'checked' => 0, 'position' => 45), - 'country.code_iso' => array('label' => "Country", 'checked' => 0, 'position' => 50), - 'typent.code' => array('label' => "ThirdPartyType", 'checked' => $checkedtypetiers, 'position' => 55), - 'c.date_commande' => array('label' => "OrderDateShort", 'checked' => 1, 'position' => 60, 'csslist' => 'nowraponall'), - 'c.delivery_date' => array('label' => "DateDeliveryPlanned", 'checked' => 1, 'enabled' => !getDolGlobalString('ORDER_DISABLE_DELIVERY_DATE'), 'position' => 65, 'csslist' => 'nowraponall'), - 'c.fk_shipping_method' => array('label' => "SendingMethod", 'checked' => -1, 'position' => 66 , 'enabled' => isModEnabled("shipping")), - 'c.fk_cond_reglement' => array('label' => "PaymentConditionsShort", 'checked' => -1, 'position' => 67), - 'c.fk_mode_reglement' => array('label' => "PaymentMode", 'checked' => -1, 'position' => 68), - 'c.fk_input_reason' => array('label' => "Origin", 'checked' => -1, 'position' => 69), - 'c.total_ht' => array('label' => "AmountHT", 'checked' => 1, 'position' => 75), - 'c.total_vat' => array('label' => "AmountVAT", 'checked' => 0, 'position' => 80), - 'c.total_ttc' => array('label' => "AmountTTC", 'checked' => 0, 'position' => 85), - 'c.multicurrency_code' => array('label' => 'Currency', 'checked' => 0, 'enabled' => (!isModEnabled("multicurrency") ? 0 : 1), 'position' => 90), - 'c.multicurrency_tx' => array('label' => 'CurrencyRate', 'checked' => 0, 'enabled' => (!isModEnabled("multicurrency") ? 0 : 1), 'position' => 95), - 'c.multicurrency_total_ht' => array('label' => 'MulticurrencyAmountHT', 'checked' => 0, 'enabled' => (!isModEnabled("multicurrency") ? 0 : 1), 'position' => 100), - 'c.multicurrency_total_vat' => array('label' => 'MulticurrencyAmountVAT', 'checked' => 0, 'enabled' => (!isModEnabled("multicurrency") ? 0 : 1), 'position' => 105), - 'c.multicurrency_total_ttc' => array('label' => 'MulticurrencyAmountTTC', 'checked' => 0, 'enabled' => (!isModEnabled("multicurrency") ? 0 : 1), 'position' => 110), - 'u.login' => array('label' => "Author", 'checked' => -1, 'position' => 115), - 'sale_representative' => array('label' => "SaleRepresentativesOfThirdParty", 'checked' => 0, 'position' => 116), - 'total_pa' => array('label' => (getDolGlobalString('MARGIN_TYPE') == '1' ? 'BuyingPrice' : 'CostPrice'), 'checked' => 0, 'position' => 300, 'enabled' => (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") ? 0 : 1)), - 'total_margin' => array('label' => 'Margin', 'checked' => 0, 'position' => 301, 'enabled' => (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") ? 0 : 1)), - 'total_margin_rate' => array('label' => 'MarginRate', 'checked' => 0, 'position' => 302, 'enabled' => (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") || !getDolGlobalString('DISPLAY_MARGIN_RATES') ? 0 : 1)), - 'total_mark_rate' => array('label' => 'MarkRate', 'checked' => 0, 'position' => 303, 'enabled' => (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") || !getDolGlobalString('DISPLAY_MARK_RATES') ? 0 : 1)), - 'c.datec' => array('label' => "DateCreation", 'checked' => 0, 'position' => 120), - 'c.tms' => array('label' => "DateModificationShort", 'checked' => 0, 'position' => 125), - 'c.date_cloture' => array('label' => "DateClosing", 'checked' => 0, 'position' => 130), - 'c.note_public' => array('label' => 'NotePublic', 'checked' => 0, 'enabled' => (!getDolGlobalInt('MAIN_LIST_HIDE_PUBLIC_NOTES')), 'position' => 135, 'searchall' => 1), - 'c.note_private' => array('label' => 'NotePrivate', 'checked' => 0, 'enabled' => (!getDolGlobalInt('MAIN_LIST_HIDE_PRIVATE_NOTES')), 'position' => 140), - 'shippable' => array('label' => "Shippable", 'checked' => 1,'enabled' => (isModEnabled("shipping")), 'position' => 990), - 'c.facture' => array('label' => "Billed", 'checked' => 1, 'enabled' => (!getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT')), 'position' => 995), - 'c.import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 999), - 'c.fk_statut' => array('label' => "Status", 'checked' => 1, 'position' => 1000) + 'c.rowid' => array('label' => "ID", 'checked' => '1', 'enabled' => (string) getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID'), 'position' => 1), + 'c.ref' => array('label' => "Ref", 'checked' => '1', 'position' => 5, 'searchall' => 1), + 'c.ref_ext' => array('label' => "RefExt", 'checked' => '1', 'position' => 5, 'visible' => 0, 'searchall' => 1), + 'c.ref_client' => array('label' => "RefCustomerOrder", 'checked' => '-1', 'position' => 10, 'searchall' => 1), + 'p.ref' => array('label' => "ProjectRef", 'checked' => '-1', 'enabled' => (!isModEnabled('project') ? '0' : '1'), 'position' => 20), + 'p.title' => array('label' => "ProjectLabel", 'checked' => '0', 'enabled' => (!isModEnabled('project') ? '0' : '1'), 'position' => 25), + 's.nom' => array('label' => "ThirdParty", 'checked' => '1', 'position' => 30, 'searchall' => 1), + 's.name_alias' => array('label' => "AliasNameShort", 'checked' => '-1', 'position' => 31, 'searchall' => 1), + 's2.nom' => array('label' => 'ParentCompany', 'position' => 32, 'checked' => '0'), + 's.town' => array('label' => "Town", 'checked' => '-1', 'position' => 35, 'searchall' => 1), + 's.zip' => array('label' => "Zip", 'checked' => '-1', 'position' => 40, 'searchall' => 1), + 'state.nom' => array('label' => "StateShort", 'checked' => '0', 'position' => 45), + 'country.code_iso' => array('label' => "Country", 'checked' => '0', 'position' => 50), + 'typent.code' => array('label' => "ThirdPartyType", 'checked' => (string) $checkedtypetiers, 'position' => 55), + 'c.date_commande' => array('label' => "OrderDateShort", 'checked' => '1', 'position' => 60, 'csslist' => 'nowraponall'), + 'c.delivery_date' => array('label' => "DateDeliveryPlanned", 'checked' => '1', 'enabled' => (string) (int) !getDolGlobalString('ORDER_DISABLE_DELIVERY_DATE'), 'position' => 65, 'csslist' => 'nowraponall'), + 'c.fk_shipping_method' => array('label' => "SendingMethod", 'checked' => '-1', 'position' => 66 , 'enabled' => (string) (int) isModEnabled("shipping")), + 'c.fk_cond_reglement' => array('label' => "PaymentConditionsShort", 'checked' => '-1', 'position' => 67), + 'c.fk_mode_reglement' => array('label' => "PaymentMode", 'checked' => '-1', 'position' => 68), + 'c.fk_input_reason' => array('label' => "Origin", 'checked' => '-1', 'position' => 69), + 'c.total_ht' => array('label' => "AmountHT", 'checked' => '1', 'position' => 75), + 'c.total_vat' => array('label' => "AmountVAT", 'checked' => '0', 'position' => 80), + 'c.total_ttc' => array('label' => "AmountTTC", 'checked' => '0', 'position' => 85), + 'c.multicurrency_code' => array('label' => 'Currency', 'checked' => '0', 'enabled' => (!isModEnabled("multicurrency") ? '0' : '1'), 'position' => 90), + 'c.multicurrency_tx' => array('label' => 'CurrencyRate', 'checked' => '0', 'enabled' => (!isModEnabled("multicurrency") ? '0' : '1'), 'position' => 95), + 'c.multicurrency_total_ht' => array('label' => 'MulticurrencyAmountHT', 'checked' => '0', 'enabled' => (!isModEnabled("multicurrency") ? '0' : '1'), 'position' => 100), + 'c.multicurrency_total_vat' => array('label' => 'MulticurrencyAmountVAT', 'checked' => '0', 'enabled' => (!isModEnabled("multicurrency") ? '0' : '1'), 'position' => 105), + 'c.multicurrency_total_ttc' => array('label' => 'MulticurrencyAmountTTC', 'checked' => '0', 'enabled' => (!isModEnabled("multicurrency") ? '0' : '1'), 'position' => 110), + 'u.login' => array('label' => "Author", 'checked' => '-1', 'position' => 115), + 'sale_representative' => array('label' => "SaleRepresentativesOfThirdParty", 'checked' => '0', 'position' => 116), + 'total_pa' => array('label' => (getDolGlobalString('MARGIN_TYPE') == '1' ? 'BuyingPrice' : 'CostPrice'), 'checked' => '0', 'position' => 300, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") ? 0 : 1)), + 'total_margin' => array('label' => 'Margin', 'checked' => '0', 'position' => 301, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") ? 0 : 1)), + 'total_margin_rate' => array('label' => 'MarginRate', 'checked' => '0', 'position' => 302, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") || !getDolGlobalString('DISPLAY_MARGIN_RATES') ? 0 : 1)), + 'total_mark_rate' => array('label' => 'MarkRate', 'checked' => '0', 'position' => 303, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight("margins", "liretous") || !getDolGlobalString('DISPLAY_MARK_RATES') ? 0 : 1)), + 'c.datec' => array('label' => "DateCreation", 'checked' => '0', 'position' => 120), + 'c.tms' => array('label' => "DateModificationShort", 'checked' => '0', 'position' => 125), + 'c.date_cloture' => array('label' => "DateClosing", 'checked' => '0', 'position' => 130), + 'c.note_public' => array('label' => 'NotePublic', 'checked' => '0', 'enabled' => (string) (int) (!getDolGlobalInt('MAIN_LIST_HIDE_PUBLIC_NOTES')), 'position' => 135, 'searchall' => 1), + 'c.note_private' => array('label' => 'NotePrivate', 'checked' => '0', 'enabled' => (string) (int) (!getDolGlobalInt('MAIN_LIST_HIDE_PRIVATE_NOTES')), 'position' => 140), + 'shippable' => array('label' => "Shippable", 'checked' => '1','enabled' => (string) (int) (isModEnabled("shipping")), 'position' => 990), + 'c.facture' => array('label' => "Billed", 'checked' => '1', 'enabled' => (string) (int) (!getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT')), 'position' => 995), + 'c.import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => '1', 'visible' => -2, 'position' => 999), + 'c.fk_statut' => array('label' => "Status", 'checked' => '1', 'position' => 1000) ); $parameters = array('fieldstosearchall' => $fieldstosearchall); @@ -259,7 +259,6 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; $object->fields = dol_sort_array($object->fields, 'position'); //$arrayfields['anotherfield'] = array('type'=>'integer', 'label'=>'AnotherField', 'checked'=>1, 'enabled'=>1, 'position'=>90, 'csslist'=>'right'); $arrayfields = dol_sort_array($arrayfields, 'position'); -'@phan-var-force array,position?:int,help?:string}> $arrayfields'; // dol_sort_array looses type for Phan // Security check @@ -1575,7 +1574,7 @@ if ($user->hasRight("user", "user", "lire")) { if ($user->hasRight("user", "user", "lire")) { $moreforfilter .= '
'; $tmptitle = $langs->trans('LinkedToSpecificUsers'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, null, 0, '', '', '0', 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
'; } @@ -1585,7 +1584,7 @@ if (isModEnabled('category') && $user->hasRight("categorie", "lire") && ($user-> $moreforfilter .= '
'; $tmptitle = $langs->trans('IncludingProductWithTag'); $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 0, array(), 1); - $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$form->selectarray('search_product_category', $cate_arbo, $search_product_category, $tmptitle, 0, 0, '', 0, 0, 0, 0, 'maxwidth300 widthcentpercentminusx', 1); + $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$form->selectarray('search_product_category', $cate_arbo, $search_product_category, $tmptitle, 0, 0, '', 0, 0, 0, '', 'maxwidth300 widthcentpercentminusx', 1); $moreforfilter .= '
'; } // If Categories are enabled & user has rights to see @@ -1685,7 +1684,7 @@ if (!empty($arrayfields['p.title']['checked'])) { // Thirpdarty if (!empty($arrayfields['s.nom']['checked'])) { print ''; - print 'socid) ? " disabled" : "").'>'; + print 'socid) ? " disabled" : "").'>'; print ''; } // Alias @@ -1756,7 +1755,7 @@ if (!empty($arrayfields['c.fk_shipping_method']['checked'])) { // Payment term if (!empty($arrayfields['c.fk_cond_reglement']['checked'])) { print ''; - print $form->getSelectConditionsPaiements($search_fk_cond_reglement, 'search_fk_cond_reglement', 1, 1, 1); + print $form->getSelectConditionsPaiements((int) $search_fk_cond_reglement, 'search_fk_cond_reglement', 1, 1, 1); print ''; } // Payment mode @@ -2210,6 +2209,7 @@ while ($i < $imaxinloop) { $generic_commande->id = $obj->rowid; $generic_commande->ref = $obj->ref; + $generic_commande->status = $obj->fk_statut; $generic_commande->statut = $obj->fk_statut; $generic_commande->billed = $obj->billed; $generic_commande->date = $db->jdate($obj->date_commande); @@ -2258,7 +2258,7 @@ while ($i < $imaxinloop) { } else { // Show line of result $j = 0; - print ''; + print ''; // Action column if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) { diff --git a/htdocs/commande/list_det.php b/htdocs/commande/list_det.php index f1e0d517f73..f5a41ddae21 100644 --- a/htdocs/commande/list_det.php +++ b/htdocs/commande/list_det.php @@ -12,7 +12,7 @@ * Copyright (C) 2016-2021 Ferran Marcet * Copyright (C) 2018-2023 Charlene Benke * Copyright (C) 2021-2023 Anthony Berton - * Copyright (C) 2024 MDW + * Copyright (C) 2024-2025 MDW * Copyright (C) 2024 Alexandre Spangaro * * This program is free software; you can redistribute it and/or modify @@ -191,51 +191,51 @@ if (empty($user->socid)) { $checkedtypetiers = 0; $arrayfields = array( // Détail commande - 'rowid' => array('label' => 'TechnicalID', 'checked' => 1, 'position' => 1, 'enabled' => (getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') ? 1 : 0)), - 'pr.ref' => array('label' => 'ProductRef', 'checked' => 1, 'position' => 1), - 'pr.desc' => array('label' => 'ProductDescription', 'checked' => -1, 'position' => 1), - 'cdet.qty' => array('label' => 'QtyOrdered', 'checked' => 1, 'position' => 1), - 'c.ref' => array('label' => "Ref", 'checked' => 1, 'position' => 5), - 'c.ref_client' => array('label' => "RefCustomerOrder", 'checked' => -1, 'position' => 10), - 'p.ref' => array('label' => "ProjectRef", 'checked' => -1, 'enabled' => (empty($conf->project->enabled) ? 0 : 1), 'position' => 20), - 'p.title' => array('label' => "ProjectLabel", 'checked' => 0, 'enabled' => (empty($conf->project->enabled) ? 0 : 1), 'position' => 25), - 's.nom' => array('label' => "ThirdParty", 'checked' => 1, 'position' => 30), - 's.name_alias' => array('label' => "AliasNameShort", 'checked' => -1, 'position' => 31), - 's.town' => array('label' => "Town", 'checked' => -1, 'position' => 35), - 's.zip' => array('label' => "Zip", 'checked' => -1, 'position' => 40), - 'state.nom' => array('label' => "StateShort", 'checked' => 0, 'position' => 45), - 'country.code_iso' => array('label' => "Country", 'checked' => 0, 'position' => 50), - 'typent.code' => array('label' => "ThirdPartyType", 'checked' => $checkedtypetiers, 'position' => 55), - 'c.date_commande' => array('label' => "OrderDateShort", 'checked' => 1, 'position' => 60), - 'c.delivery_date' => array('label' => "DateDeliveryPlanned", 'checked' => 1, 'enabled' => !getDolGlobalString('ORDER_DISABLE_DELIVERY_DATE'), 'position' => 65), - 'c.fk_shipping_method' => array('label' => "SendingMethod", 'checked' => -1, 'position' => 66 , 'enabled' => isModEnabled('shipping')), - 'c.fk_cond_reglement' => array('label' => "PaymentConditionsShort", 'checked' => -1, 'position' => 67), - 'c.fk_mode_reglement' => array('label' => "PaymentMode", 'checked' => -1, 'position' => 68), - 'c.fk_input_reason' => array('label' => "Channel", 'checked' => -1, 'position' => 69), - 'cdet.total_ht' => array('label' => "AmountHT", 'checked' => 1, 'position' => 75), - 'c.total_vat' => array('label' => "AmountVAT", 'checked' => 0, 'position' => 80), - 'cdet.total_ttc' => array('label' => "AmountTTC", 'checked' => 0, 'position' => 85), - 'c.multicurrency_code' => array('label' => 'Currency', 'checked' => 0, 'enabled' => (empty($conf->multicurrency->enabled) ? 0 : 1), 'position' => 90), - 'c.multicurrency_tx' => array('label' => 'CurrencyRate', 'checked' => 0, 'enabled' => (empty($conf->multicurrency->enabled) ? 0 : 1), 'position' => 95), - 'c.multicurrency_total_ht' => array('label' => 'MulticurrencyAmountHT', 'checked' => 0, 'enabled' => (empty($conf->multicurrency->enabled) ? 0 : 1), 'position' => 100), - 'c.multicurrency_total_vat' => array('label' => 'MulticurrencyAmountVAT', 'checked' => 0, 'enabled' => (empty($conf->multicurrency->enabled) ? 0 : 1), 'position' => 105), - 'c.multicurrency_total_ttc' => array('label' => 'MulticurrencyAmountTTC', 'checked' => 0, 'enabled' => (empty($conf->multicurrency->enabled) ? 0 : 1), 'position' => 110), - 'c.fk_warehouse' => array('label' => 'Warehouse', 'checked' => 0, 'enabled' => (!isModEnabled('stock') && !getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER') ? 0 : 1), 'position' => 110), - 'u.login' => array('label' => "Author", 'checked' => 1, 'position' => 115), - 'sale_representative' => array('label' => "SaleRepresentativesOfThirdParty", 'checked' => 0, 'position' => 116), - 'total_pa' => array('label' => (getDolGlobalString('MARGIN_TYPE') == '1' ? 'BuyingPrice' : 'CostPrice'), 'checked' => 0, 'position' => 300, 'enabled' => (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') ? 0 : 1)), - 'total_margin' => array('label' => 'Margin', 'checked' => 0, 'position' => 301, 'enabled' => (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') ? 0 : 1)), - 'total_margin_rate' => array('label' => 'MarginRate', 'checked' => 0, 'position' => 302, 'enabled' => (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') || !getDolGlobalString('DISPLAY_MARGIN_RATES') ? 0 : 1)), - 'total_mark_rate' => array('label' => 'MarkRate', 'checked' => 0, 'position' => 303, 'enabled' => (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') || !getDolGlobalString('DISPLAY_MARK_RATES') ? 0 : 1)), - 'c.datec' => array('label' => "DateCreation", 'checked' => 0, 'position' => 120), - 'c.tms' => array('label' => "DateModificationShort", 'checked' => 0, 'position' => 125), - 'c.date_cloture' => array('label' => "DateClosing", 'checked' => 0, 'position' => 130), - 'c.note_public' => array('label' => 'NotePublic', 'checked' => 0, 'enabled' => (!getDolGlobalString('MAIN_LIST_ALLOW_PUBLIC_NOTES')), 'position' => 135), - 'c.note_private' => array('label' => 'NotePrivate', 'checked' => 0, 'enabled' => (!getDolGlobalString('MAIN_LIST_ALLOW_PRIVATE_NOTES')), 'position' => 140), - 'shippable' => array('label' => "Shippable", 'checked' => 1,'enabled' => (isModEnabled('shipping')), 'position' => 990), - 'c.facture' => array('label' => "Billed", 'checked' => 1, 'enabled' => (!getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT')), 'position' => 995), - 'c.import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 999), - 'c.fk_statut' => array('label' => "Status", 'checked' => 1, 'position' => 1000) + 'rowid' => array('label' => 'TechnicalID', 'checked' => '1', 'position' => 1, 'enabled' => (getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') ? '1' : '0')), + 'pr.ref' => array('label' => 'ProductRef', 'checked' => '1', 'position' => 1), + 'pr.desc' => array('label' => 'ProductDescription', 'checked' => '-1', 'position' => 1), + 'cdet.qty' => array('label' => 'QtyOrdered', 'checked' => '1', 'position' => 1), + 'c.ref' => array('label' => "Ref", 'checked' => '1', 'position' => 5), + 'c.ref_client' => array('label' => "RefCustomerOrder", 'checked' => '-1', 'position' => 10), + 'p.ref' => array('label' => "ProjectRef", 'checked' => '-1', 'enabled' => (empty($conf->project->enabled) ? '0' : '1'), 'position' => 20), + 'p.title' => array('label' => "ProjectLabel", 'checked' => '0', 'enabled' => (empty($conf->project->enabled) ? '0' : '1'), 'position' => 25), + 's.nom' => array('label' => "ThirdParty", 'checked' => '1', 'position' => 30), + 's.name_alias' => array('label' => "AliasNameShort", 'checked' => '-1', 'position' => 31), + 's.town' => array('label' => "Town", 'checked' => '-1', 'position' => 35), + 's.zip' => array('label' => "Zip", 'checked' => '-1', 'position' => 40), + 'state.nom' => array('label' => "StateShort", 'checked' => '0', 'position' => 45), + 'country.code_iso' => array('label' => "Country", 'checked' => '0', 'position' => 50), + 'typent.code' => array('label' => "ThirdPartyType", 'checked' => (string) $checkedtypetiers, 'position' => 55), + 'c.date_commande' => array('label' => "OrderDateShort", 'checked' => '1', 'position' => 60), + 'c.delivery_date' => array('label' => "DateDeliveryPlanned", 'checked' => '1', 'enabled' => (string) (int) !getDolGlobalString('ORDER_DISABLE_DELIVERY_DATE'), 'position' => 65), + 'c.fk_shipping_method' => array('label' => "SendingMethod", 'checked' => '-1', 'position' => 66 , 'enabled' => (string) (int) isModEnabled('shipping')), + 'c.fk_cond_reglement' => array('label' => "PaymentConditionsShort", 'checked' => '-1', 'position' => 67), + 'c.fk_mode_reglement' => array('label' => "PaymentMode", 'checked' => '-1', 'position' => 68), + 'c.fk_input_reason' => array('label' => "Channel", 'checked' => '-1', 'position' => 69), + 'cdet.total_ht' => array('label' => "AmountHT", 'checked' => '1', 'position' => 75), + 'c.total_vat' => array('label' => "AmountVAT", 'checked' => '0', 'position' => 80), + 'cdet.total_ttc' => array('label' => "AmountTTC", 'checked' => '0', 'position' => 85), + 'c.multicurrency_code' => array('label' => 'Currency', 'checked' => '0', 'enabled' => (empty($conf->multicurrency->enabled) ? '0' : '1'), 'position' => 90), + 'c.multicurrency_tx' => array('label' => 'CurrencyRate', 'checked' => '0', 'enabled' => (empty($conf->multicurrency->enabled) ? '0' : '1'), 'position' => 95), + 'c.multicurrency_total_ht' => array('label' => 'MulticurrencyAmountHT', 'checked' => '0', 'enabled' => (empty($conf->multicurrency->enabled) ? '0' : '1'), 'position' => 100), + 'c.multicurrency_total_vat' => array('label' => 'MulticurrencyAmountVAT', 'checked' => '0', 'enabled' => (empty($conf->multicurrency->enabled) ? '0' : '1'), 'position' => 105), + 'c.multicurrency_total_ttc' => array('label' => 'MulticurrencyAmountTTC', 'checked' => '0', 'enabled' => (empty($conf->multicurrency->enabled) ? '0' : '1'), 'position' => 110), + 'c.fk_warehouse' => array('label' => 'Warehouse', 'checked' => '0', 'enabled' => (string) (int) (!isModEnabled('stock') && !getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER') ? '0' : '1'), 'position' => 110), + 'u.login' => array('label' => "Author", 'checked' => '1', 'position' => 115), + 'sale_representative' => array('label' => "SaleRepresentativesOfThirdParty", 'checked' => '0', 'position' => 116), + 'total_pa' => array('label' => (getDolGlobalString('MARGIN_TYPE') == '1' ? 'BuyingPrice' : 'CostPrice'), 'checked' => '0', 'position' => 300, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') ? '0' : '1')), + 'total_margin' => array('label' => 'Margin', 'checked' => '0', 'position' => 301, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') ? '0' : '1')), + 'total_margin_rate' => array('label' => 'MarginRate', 'checked' => '0', 'position' => 302, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') || !getDolGlobalString('DISPLAY_MARGIN_RATES') ? '0' : '1')), + 'total_mark_rate' => array('label' => 'MarkRate', 'checked' => '0', 'position' => 303, 'enabled' => (string) (int) (!isModEnabled('margin') || !$user->hasRight('margins', 'liretous') || !getDolGlobalString('DISPLAY_MARK_RATES') ? '0' : '1')), + 'c.datec' => array('label' => "DateCreation", 'checked' => '0', 'position' => 120), + 'c.tms' => array('label' => "DateModificationShort", 'checked' => '0', 'position' => 125), + 'c.date_cloture' => array('label' => "DateClosing", 'checked' => '0', 'position' => 130), + 'c.note_public' => array('label' => 'NotePublic', 'checked' => '0', 'enabled' => (string) (int) (!getDolGlobalString('MAIN_LIST_ALLOW_PUBLIC_NOTES')), 'position' => 135), + 'c.note_private' => array('label' => 'NotePrivate', 'checked' => '0', 'enabled' => (string) (int) (!getDolGlobalString('MAIN_LIST_ALLOW_PRIVATE_NOTES')), 'position' => 140), + 'shippable' => array('label' => "Shippable", 'checked' => '1','enabled' => (string) (int) (isModEnabled('shipping')), 'position' => 990), + 'c.facture' => array('label' => "Billed", 'checked' => '1', 'enabled' => (string) (int) (!getDolGlobalString('WORKFLOW_BILL_ON_SHIPMENT')), 'position' => 995), + 'c.import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => '1', 'visible' => -2, 'position' => 999), + 'c.fk_statut' => array('label' => "Status", 'checked' => '1', 'position' => 1000) ); // Extra fields @@ -243,7 +243,6 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; $object->fields = dol_sort_array($object->fields, 'position'); $arrayfields = dol_sort_array($arrayfields, 'position'); -'@phan-var-force array,position?:int,help?:string}> $arrayfields'; // dol_sort_array looses type for Phan if (!$user->hasRight('societe', 'client', 'voir')) { $search_sale = $user->id; @@ -946,7 +945,7 @@ if ($resql) { if ($user->hasRight('user', 'user', 'lire')) { $moreforfilter .= '
'; $tmptitle = $langs->trans('LinkedToSpecificUsers'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, null, 0, '', '', '0', 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
'; } // Filter on categories @@ -1057,7 +1056,7 @@ if ($resql) { // Thirpdarty if (!empty($arrayfields['s.nom']['checked'])) { print ''; - print ''; + print ''; print ''; } // Alias @@ -1782,7 +1781,7 @@ if ($resql) { } // Plannned date of delivery if (!empty($arrayfields['c.delivery_date']['checked'])) { - print ''; + print ''; print dol_print_date($db->jdate($obj->delivery_date), 'day'); print ''; if (!$i) { diff --git a/htdocs/commande/note.php b/htdocs/commande/note.php index 572e741348f..1423d7fc06a 100644 --- a/htdocs/commande/note.php +++ b/htdocs/commande/note.php @@ -5,6 +5,7 @@ * Copyright (C) 2013 Florian Henry * Copyright (C) 2017 Ferran Marcet * 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 @@ -123,7 +124,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/commande/stats/index.php b/htdocs/commande/stats/index.php index cc2aac53b02..a8dc9589ab9 100644 --- a/htdocs/commande/stats/index.php +++ b/htdocs/commande/stats/index.php @@ -5,7 +5,7 @@ * Copyright (C) 2012 Marcos García * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2020 Maxime DEMAREST - * 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 @@ -272,7 +272,7 @@ if (!$mesg) { $px3->SetLegend($legend); $px3->SetYLabel($langs->trans("AmountAverage")); $px3->SetMaxValue($px3->GetCeilMaxValue()); - $px3->SetMinValue($px3->GetFloorMinValue()); + $px3->SetMinValue((int) $px3->GetFloorMinValue()); $px3->SetWidth($WIDTH); $px3->SetHeight($HEIGHT); $px3->SetShading(3); @@ -363,7 +363,7 @@ print ''; // User print ''.$langs->trans("CreatedBy").''; print img_picto('', 'user', 'class="pictofixedwidth"'); -print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300'); +print $form->select_dolusers($userid, 'userid', 1, null, 0, '', '', '0', 0, 0, '', 0, '', 'widthcentpercentminusx maxwidth300'); // Status print ''.$langs->trans("Status").''; if ($mode == 'customer') { diff --git a/htdocs/compta/bank/class/api_bankaccounts.class.php b/htdocs/compta/bank/class/api_bankaccounts.class.php index e86deabfe43..125150dd63c 100644 --- a/htdocs/compta/bank/class/api_bankaccounts.class.php +++ b/htdocs/compta/bank/class/api_bankaccounts.class.php @@ -62,6 +62,8 @@ class BankAccounts extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.import_key:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array List of account objects + * @phan-return Account[] + * @phpstan-return Account[] * * @throws RestException */ @@ -271,14 +273,14 @@ class BankAccounts extends DolibarrApi */ if (!$error) { - $bank_line_id_from = $accountfrom->addline($date, $typefrom, $description, -1 * (float) price2num($amount), '', '', $user, $cheque_number); + $bank_line_id_from = $accountfrom->addline((int) $date, $typefrom, $description, -1 * (float) price2num($amount), '', 0, $user, $cheque_number); } if (!($bank_line_id_from > 0)) { $error++; } if (!$error) { - $bank_line_id_to = $accountto->addline($date, $typeto, $description, price2num($amount_to), '', '', $user, $cheque_number); + $bank_line_id_to = $accountto->addline((int) $date, $typeto, $description, (float) price2num($amount_to), '', 0, $user, $cheque_number); } if (!($bank_line_id_to > 0)) { $error++; @@ -446,6 +448,8 @@ class BankAccounts extends DolibarrApi * * @param int $id ID of account * @return array Array of AccountLine objects + * @phan-return AccountLine[] + * @phpstan-return AccountLine[] * * @throws RestException * @@ -538,7 +542,7 @@ class BankAccounts extends DolibarrApi $num_releve = sanitizeVal($num_releve); $result = $account->addline( - $date, + (int) $date, $type, $label, $amount, @@ -548,7 +552,7 @@ class BankAccounts extends DolibarrApi $cheque_writer, $cheque_bank, $accountancycode, - $datev, + (int) $datev, $num_releve ); if ($result < 0) { @@ -605,6 +609,8 @@ class BankAccounts extends DolibarrApi * @param int $id ID of account * @param int $line_id ID of account line * @return array Array of links + * @phan-return array + * @phpstan-return array * * @throws RestException * diff --git a/htdocs/compta/deplacement/class/deplacement.class.php b/htdocs/compta/deplacement/class/deplacement.class.php index d976c63c5f5..f9be0193da3 100644 --- a/htdocs/compta/deplacement/class/deplacement.class.php +++ b/htdocs/compta/deplacement/class/deplacement.class.php @@ -304,7 +304,7 @@ class Deplacement extends CommonObject $this->note_public = $obj->note_public; $this->fk_project = $obj->fk_project; - $this->extraparams = (array) json_decode($obj->extraparams, true); + $this->extraparams = !empty($obj->extraparams) ? (array) json_decode($obj->extraparams, true) : array(); return 1; } else { diff --git a/htdocs/compta/facture/agenda-rec.php b/htdocs/compta/facture/agenda-rec.php index 6cdbed1196e..86ce5589799 100644 --- a/htdocs/compta/facture/agenda-rec.php +++ b/htdocs/compta/facture/agenda-rec.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 @@ -171,7 +171,7 @@ if ($object->id > 0) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/compta/facture/agenda.php b/htdocs/compta/facture/agenda.php index 866a0c4edee..9f56337ccce 100644 --- a/htdocs/compta/facture/agenda.php +++ b/htdocs/compta/facture/agenda.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 @@ -165,7 +166,7 @@ if ($object->id > 0) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/compta/facture/card-rec.php b/htdocs/compta/facture/card-rec.php index b90c061e9f3..433d1ded085 100644 --- a/htdocs/compta/facture/card-rec.php +++ b/htdocs/compta/facture/card-rec.php @@ -10,7 +10,7 @@ * Copyright (C) 2016 Meziane Sof * Copyright (C) 2017-2025 Frédéric France * Copyright (C) 2023 Nick Fragoulis - * 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 @@ -473,7 +473,7 @@ if (empty($reshook)) { setEventMessages($line->error, $line->errors, 'errors'); } } elseif ($action == 'update_extras' && $usercancreate) { - $object->oldcopy = dol_clone($object, 2); + $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty // Fill array 'array_options' with data from update form $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml')); @@ -700,7 +700,7 @@ if (empty($reshook)) { $label = (GETPOST('product_label') ? GETPOST('product_label') : ''); $desc = $product_desc; $type = GETPOST('type'); - $fk_unit = GETPOST('units', 'alpha'); + $fk_unit = GETPOSTINT('units'); } $date_start_fill = GETPOSTINT('date_start_fill'); @@ -719,14 +719,14 @@ if (empty($reshook)) { $info_bits |= 0x01; } - $fk_parent_line = GETPOST('fk_parent_line', 'int'); + $fk_parent_line = GETPOSTINT('fk_parent_line'); if ($usercanproductignorepricemin && (!empty($price_min) && ((float) price2num($pu_ht) * (1 - (float) price2num($remise_percent) / 100) < (float) price2num($price_min)))) { $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency)); setEventMessages($mesg, null, 'errors'); } else { // Insert line - $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $info_bits, 0, $pu_ttc, $type, -1, $special_code, $label, $fk_unit, 0, $date_start_fill, $date_end_fill, $fournprice, $buyingprice, $fk_parent_line); + $result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $info_bits, 0, $pu_ttc, $type, -1, $special_code, $label, (int) $fk_unit, 0, $date_start_fill, $date_end_fill, (int) $fournprice, (int) $buyingprice, $fk_parent_line); if ($result > 0) { // Define output language and generate document @@ -919,9 +919,9 @@ if (empty($reshook)) { $result = $object->updateline( GETPOSTINT('lineid'), $description, - $pu_ht, - $qty, - $vat_rate, + (float) $pu_ht, + (float) $qty, + (float) $vat_rate, $localtax1_rate, $localtax1_rate, GETPOSTINT('productid'), @@ -934,14 +934,14 @@ if (empty($reshook)) { $position, $special_code, $label, - GETPOST('units'), - $pu_ht_devise, + GETPOSTINT('units'), + (float) $pu_ht_devise, 0, $date_start_fill, $date_end_fill, - $fournprice, - $buyingprice, - $fk_parent_line + (int) $fournprice, + (int) $buyingprice, + (int) $fk_parent_line ); if ($result >= 0) { @@ -1116,7 +1116,7 @@ if ($action == 'create') { // Payment mode print "".$langs->trans("PaymentMode").""; print img_picto('', 'payment', 'class="pictofixedwidth"'); - print $form->select_types_paiements(GETPOSTISSET('mode_reglement_id') ? GETPOSTINT('mode_reglement_id') : $object->mode_reglement_id, 'mode_reglement_id', '', 0, 1, 0, 0, 1, '', 1); + print $form->select_types_paiements((string) (GETPOSTISSET('mode_reglement_id') ? GETPOSTINT('mode_reglement_id') : $object->mode_reglement_id), 'mode_reglement_id', '', 0, 1, 0, 0, 1, '', 1); //$form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', '', 1); print ""; @@ -1155,7 +1155,7 @@ if ($action == 'create') { // Bank account if ($object->fk_account > 0) { print "".$langs->trans('BankAccount').""; - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none'); print ""; } @@ -1368,7 +1368,7 @@ if ($action == 'create') { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); @@ -1442,9 +1442,9 @@ if ($action == 'create') { print ''; print ''; if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id'); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'none'); } print ''; @@ -1459,9 +1459,9 @@ if ($action == 'create') { print ''; print ''; if ($action == 'editmode') { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); } else { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'none'); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'none'); } print ''; @@ -1480,9 +1480,9 @@ if ($action == 'create') { print ''; if ($action == 'editbankaccountcustomer') { - $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_societe_rib, 'accountcustomerid', 'fk_soc='.$object->socid, 1, 1); + $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_societe_rib, 'accountcustomerid', 'fk_soc='.$object->socid, 1, 1); } else { - $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->fk_societe_rib, 'none', '', 0, 1); + $form->formRib($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_societe_rib, 'none', '', 0, 1); } print ""; print ''; @@ -1499,9 +1499,9 @@ if ($action == 'create') { print ''; print ''; if ($action == 'editbankaccount') { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1); } else { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none'); } print ""; print ''; @@ -1614,7 +1614,7 @@ if ($action == 'create') { // Max period / Rest period print ''; if ($action == 'nb_gen_max' || $object->frequency > 0) { - print $form->editfieldkey($langs->trans("MaxPeriodNumber"), 'nb_gen_max', $object->nb_gen_max, $object, $user->hasRight('facture', 'creer')); + print $form->editfieldkey($langs->trans("MaxPeriodNumber"), 'nb_gen_max', (string) $object->nb_gen_max, $object, $user->hasRight('facture', 'creer')); } else { print $langs->trans("MaxPeriodNumber"); } @@ -1630,7 +1630,7 @@ if ($action == 'create') { // Status of auto generated invoices print ''; if ($action == 'auto_validate' || $object->frequency > 0) { - print $form->editfieldkey($langs->trans("StatusOfAutoGeneratedInvoices"), 'auto_validate', $object->auto_validate, $object, $user->hasRight('facture', 'creer')); + print $form->editfieldkey($langs->trans("StatusOfAutoGeneratedInvoices"), 'auto_validate', (string) $object->auto_validate, $object, $user->hasRight('facture', 'creer')); } else { print $langs->trans("StatusOfAutoGeneratedInvoices"); } @@ -1645,7 +1645,7 @@ if ($action == 'create') { print ''; print ''; if ($action == 'generate_pdf' || $object->frequency > 0) { - print $form->editfieldkey($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', $object->generate_pdf, $object, $user->hasRight('facture', 'creer')); + print $form->editfieldkey($langs->trans("StatusOfGeneratedDocuments"), 'generate_pdf', (string) $object->generate_pdf, $object, $user->hasRight('facture', 'creer')); } else { print $langs->trans("StatusOfGeneratedDocuments"); } diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 0d3db095797..f37a548d3af 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -1,24 +1,24 @@ - * Copyright (C) 2004 Eric Seigne - * Copyright (C) 2004-2020 Laurent Destailleur - * Copyright (C) 2005 Marc Barilley / Ocebo - * Copyright (C) 2005-2015 Regis Houssin - * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2010-2015 Juanjo Menent - * Copyright (C) 2012-2023 Christophe Battarel - * Copyright (C) 2012-2013 Cédric Salvador - * Copyright (C) 2012-2014 Raphaël Doursenaud - * Copyright (C) 2013 Jean-Francois FERRY - * Copyright (C) 2013-2014 Florian Henry - * Copyright (C) 2013 Cédric Salvador - * Copyright (C) 2014-2024 Ferran Marcet - * Copyright (C) 2015-2016 Marcos García - * Copyright (C) 2018-2025 Frédéric France - * Copyright (C) 2022 Gauthier VERDOL - * Copyright (C) 2023 Nick Fragoulis - * Copyright (C) 2024-2025 MDW - * Copyright (C) 2024 Alexandre Spangaro +/* Copyright (C) 2002-2006 Rodolphe Quiedeville + * Copyright (C) 2004 Eric Seigne + * Copyright (C) 2004-2020 Laurent Destailleur + * Copyright (C) 2005 Marc Barilley / Ocebo + * Copyright (C) 2005-2015 Regis Houssin + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2010-2015 Juanjo Menent + * Copyright (C) 2012-2023 Christophe Battarel + * Copyright (C) 2012-2013 Cédric Salvador + * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2013 Jean-Francois FERRY + * Copyright (C) 2013-2014 Florian Henry + * Copyright (C) 2014-2024 Ferran Marcet + * Copyright (C) 2015-2016 Marcos García + * Copyright (C) 2018-2025 Frédéric France + * Copyright (C) 2022 Gauthier VERDOL + * Copyright (C) 2022-2023 Solution Libre SAS + * Copyright (C) 2023 Nick Fragoulis + * Copyright (C) 2024-2025 MDW + * Copyright (C) 2024-2025 Alexandre Spangaro * * 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 @@ -42,6 +42,7 @@ // Libraries require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; @@ -304,7 +305,7 @@ if (empty($reshook)) { if (($usercandelete && $isErasable > 0) || ($usercancreate && $isErasable == 1)) { - $result = $object->delete($user, 0, $idwarehouse); + $result = $object->delete($user, 0, (int) $idwarehouse); if ($result > 0) { header('Location: '.DOL_URL_ROOT.'/compta/facture/list.php?restore_lastsearch_values=1'); exit(); @@ -426,7 +427,7 @@ if (empty($reshook)) { if ($tmpvatratetoshow[0] != 0) { $langs->load("errors"); - setEventMessages($langs->trans("ErrorLinesCantBeNegativeForOneVATRate", $tmpvatratetoshow[0]), null, 'errors'); + setEventMessages($langs->trans("ErrorLinesCantBeNegativeForOneVATRate", (string) $tmpvatratetoshow[0]), null, 'errors'); $error++; $action = ''; } @@ -471,7 +472,7 @@ if (empty($reshook)) { } } elseif ($action == 'setretainedwarrantydatelimit' && $usercancreate) { $object->fetch($id); - $result = $object->setRetainedWarrantyDateLimit(GETPOSTFLOAT('retained_warranty_date_limit')); + $result = $object->setRetainedWarrantyDateLimit(GETPOSTINT('retained_warranty_date_limit')); if ($result < 0) { dol_print_error($db, $object->error); } @@ -600,11 +601,13 @@ if (empty($reshook)) { } } elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) { // Set incoterm $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms')); + } elseif ($action == 'settags' && isModEnabled('category')) { // Set tags + $result = $object->setCategories(GETPOST('categories', 'array')); } elseif ($action == 'setbankaccount' && $usercancreate) { // bank account $result = $object->setBankAccount(GETPOSTINT('fk_account')); } elseif ($action == 'setremisepercent' && $usercancreate) { $object->fetch($id); - $result = $object->setDiscount($user, price2num(GETPOST('remise_percent'), '', 2)); + $result = $object->setDiscount($user, (float) price2num(GETPOST('remise_percent'), '', 2)); } elseif ($action == "setabsolutediscount" && $usercancreate) { // We have POST[remise_id] or POST[remise_id_for_payment] $db->begin(); @@ -1688,7 +1691,7 @@ if (empty($reshook)) { $descline .= ' - '.$srcobject->ref; $result = $object->addline( $descline, - $amount, // subprice + (float) $amount, // subprice 1, // quantity $tva, // vat rate 0, // localtax1_tx @@ -1746,7 +1749,7 @@ if (empty($reshook)) { if (is_array($lines)) { foreach ($lines as $line) { // We keep ->subprice and ->pa_ht, but we change the qty - $line->qty = price2num((float) $line->qty * (float) $valuestandardinvoice / 100, 'MS'); + $line->qty = (float) price2num((float) $line->qty * (float) $valuestandardinvoice / 100, 'MS'); } } } @@ -1755,7 +1758,7 @@ if (empty($reshook)) { if (is_array($lines)) { foreach ($lines as $line) { // We keep ->subprice and ->pa_ht, but we change the qty - $line->qty = price2num((float) $line->qty * (float) $valuedeposit / 100, 'MS'); + $line->qty = (float) price2num((float) $line->qty * (float) $valuedeposit / 100, 'MS'); } } } @@ -1968,7 +1971,7 @@ if (empty($reshook)) { $product->fetch(GETPOSTINT('idprod'.$i)); $startday = dol_mktime(12, 0, 0, GETPOSTINT('date_start'.$i.'month'), GETPOSTINT('date_start'.$i.'day'), GETPOSTINT('date_start'.$i.'year')); $endday = dol_mktime(12, 0, 0, GETPOSTINT('date_end'.$i.'month'), GETPOSTINT('date_end'.$i.'day'), GETPOSTINT('date_end'.$i.'year')); - $result = $object->addline($product->description, $product->price, price2num(GETPOST('qty'.$i), 'MS'), $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, GETPOSTINT('idprod'.$i), price2num(GETPOST('remise_percent'.$i), '', 2), $startday, $endday, 0, 0, 0, $product->price_base_type, $product->price_ttc, $product->type, -1, 0, '', 0, 0, 0, 0, '', array(), 100, 0, $product->fk_unit, 0, '', 1); + $result = $object->addline($product->description, $product->price, (float) price2num(GETPOST('qty'.$i), 'MS'), $product->tva_tx, $product->localtax1_tx, $product->localtax2_tx, GETPOSTINT('idprod'.$i), (float) price2num(GETPOST('remise_percent'.$i), '', 2), $startday, $endday, 0, 0, 0, $product->price_base_type, $product->price_ttc, $product->type, -1, 0, '', 0, 0, 0, 0, '', array(), 100, 0, $product->fk_unit, 0, '', 1); } } @@ -2109,6 +2112,13 @@ if (empty($reshook)) { // End of object creation, we show it if ($id > 0 && !$error) { + if (isModEnabled('category')) { + $categories = GETPOST('categories', 'array'); + if (method_exists($object, 'setCategories')) { + $object->setCategories($categories); + } + } + $db->commit(); // Define output language @@ -2171,7 +2181,7 @@ if (empty($reshook)) { if (!empty($line->vat_src_code)) { $tvatx .= ' ('.$line->vat_src_code.')'; } - $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, $remise_percent, $line->date_start, $line->date_end, $tvatx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice); + $result = $object->updateline($line->id, $line->desc, $line->subprice, $line->qty, (float) $remise_percent, $line->date_start, $line->date_end, $tvatx, $line->localtax1_tx, $line->localtax2_tx, 'HT', $line->info_bits, $line->product_type, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->special_code, $line->array_options, $line->situation_percent, $line->fk_unit, $line->multicurrency_subprice); } } elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && $usercancreate) { // Add a new line $langs->load('errors'); @@ -2554,7 +2564,7 @@ if (empty($reshook)) { } // Insert line - $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $date_start, $date_end, 0, $info_bits, 0, $price_base_type, $pu_ttc, $type, min($rank, count($object->lines) + 1), $special_code, '', 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_options, GETPOST('progress'), 0, $fk_unit, $pu_ht_devise); + $result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $date_start, $date_end, 0, $info_bits, 0, $price_base_type, $pu_ttc, $type, min($rank, count($object->lines) + 1), $special_code, '', 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $array_options, GETPOSTINT('progress'), 0, $fk_unit, (float) $pu_ht_devise); if ($result > 0) { // Define output language and generate document @@ -2833,9 +2843,9 @@ if (empty($reshook)) { $result = $object->updateline( GETPOSTINT('lineid'), $description, - $pu, - $qty, - $remise_percent, + (float) $pu, + (float) $qty, + (float) $remise_percent, $date_start, $date_end, $vat_rate, @@ -2852,8 +2862,8 @@ if (empty($reshook)) { $special_code, $array_options, $addprogress, - GETPOST('units', 'alpha'), - $pu_ht_devise + GETPOSTINT('units'), + (float) $pu_ht_devise ); if ($result >= 0) { @@ -2930,7 +2940,7 @@ if (empty($reshook)) { setEventMessages($mesg, null, 'warnings'); $result = -1; } else { - $object->update_percent($line, GETPOST('all_progress'), false); + $object->update_percent($line, GETPOSTINT('all_progress'), false); } } $object->update_price(1); @@ -3145,7 +3155,7 @@ if (empty($reshook)) { if ($action == 'update_extras' && $usercancreate) { - $object->oldcopy = dol_clone($object, 2); + $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty $attribute_name = GETPOST('attribute', 'restricthtml'); // Fill array 'array_options' with data from add form @@ -3173,7 +3183,7 @@ if (empty($reshook)) { $result = $object->fetch($id); if ($result > 0 && $id > 0) { - $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); + $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid')); $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); } @@ -3724,7 +3734,7 @@ if ($action == 'create') { print '
'; // Next situation invoice - $opt = $form->selectSituationInvoices(GETPOSTINT('originid'), $socid); + $opt = $form->selectSituationInvoices((string) GETPOSTINT('originid'), $socid); print '
'; $tmp = ''.$langs->trans('InvoiceSubtype').''; - print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, ''); + print $form->getSelectInvoiceSubtype(GETPOSTINT('subtype'), 'subtype', 1, 0, ''); print ''; } @@ -4058,7 +4068,7 @@ if ($action == 'create') { // Payment mode print ''.$langs->trans('PaymentMode').''; print img_picto('', 'bank', 'class="pictofixedwidth"'); - print $form->select_types_paiements($mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth250 widthcentpercentminusx', 1); + print $form->select_types_paiements((string) $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth250 widthcentpercentminusx', 1); print ''; // Bank Account @@ -4096,6 +4106,16 @@ if ($action == 'create') { print ''; } + // Category + if (isModEnabled('category')) { + // Categories + print ''.$langs->trans("Categories").''; + $cate_arbo = $form->select_all_categories(Categorie::TYPE_INVOICE, '', 'parent', 64, 0, 1); + $arrayselected = GETPOST('categories', 'array'); + print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, 'quatrevingtpercent widthcentpercentminusx', 0, '0'); + print ""; + } + // Other attributes $parameters = array('objectsrc' => !empty($objectsrc) ? $objectsrc : 0, 'colspan' => ' colspan="2"', 'cols' => '2', 'socid' => $socid); $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook @@ -4174,7 +4194,7 @@ if ($action == 'create') { print $form->textwithpicto($langs->trans('NotePublic'), $htmltext); print ''; print ''; - $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%'); + $doleditor = new DolEditor('note_public', (string) $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%'); print $doleditor->Create(1); // Private note @@ -4184,7 +4204,7 @@ if ($action == 'create') { print $form->textwithpicto($langs->trans('NotePrivate'), $htmltext); print ''; print ''; - $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%'); + $doleditor = new DolEditor('note_private', (string) $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%'); print $doleditor->Create(1); // print ' print ''; @@ -4701,13 +4721,13 @@ if ($action == 'create') { $morehtmlref = '
'; // Ref invoice if ($object->status == $object::STATUS_DRAFT && !$mysoc->isInEEC() && getDolGlobalString('INVOICE_ALLOW_FREE_REF')) { - $morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', null, null, '', 1); + $morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, (int) $usercancreate, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, (int) $usercancreate, 'string', '', null, null, '', 1); $morehtmlref .= '
'; } // Ref customer - $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_customer, $object, $usercancreate, 'string', '', 0, 1); - $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_customer, $object, $usercancreate, 'string'.(getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1); + $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_customer, $object, (int) $usercancreate, 'string', '', 0, 1); + $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_customer, $object, (int) $usercancreate, 'string'.(getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1); // Thirdparty $morehtmlref .= '
'.$object->thirdparty->getNomUrl(1, 'customer'); if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) { @@ -4722,7 +4742,7 @@ if ($action == 'create') { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); @@ -4883,9 +4903,9 @@ if ($action == 'create') { print ''; if ($object->type != Facture::TYPE_CREDIT_NOTE) { if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id'); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->cond_reglement_id, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->cond_reglement_id, 'none'); } } else { print ' '; @@ -4927,9 +4947,9 @@ if ($action == 'create') { print ''; print ''; if ($action == 'editmode') { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1); } else { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->mode_reglement_id, 'none', 'CRDT'); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->mode_reglement_id, 'none', 'CRDT'); } print ''; @@ -4945,9 +4965,9 @@ if ($action == 'create') { print ''; print ''; if ($action == 'editbankaccount') { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1); } else { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none'); } print ""; print ''; @@ -4975,7 +4995,39 @@ if ($action == 'create') { print ''; } - + // Categories + if (isModEnabled('category')) { + print ''; + print '
'; + print $langs->trans("Categories"); + print ''; + if ($usercancreate) { + print ''.img_edit().''; + } else { + print ' '; + } + print '
'; + print ''; + print ''; + $cate_arbo = $form->select_all_categories(Categorie::TYPE_INVOICE, '', 'parent', 64, 0, 1); + if ($action == 'edittags') { + print ''; + print ''; + print ''; + $c = new Categorie($db); + $cats = $c->containing($object->id, Categorie::TYPE_INVOICE); + $arrayselected = []; + foreach ($cats as $cat) { + $arrayselected[] = $cat->id; + } + print img_picto('', 'category').$form->multiselectarray('categories', $cate_arbo, $arrayselected, 0, 0, 'quatrevingtpercent widthcentpercentminusx', 0, '0'); + print ''; + print ''; + } else { + print $form->showCategories($object->id, Categorie::TYPE_INVOICE, 1); + } + print ""; + } $displayWarranty = false; @@ -5039,7 +5091,7 @@ if ($action == 'create') { print ''; print ''; } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, $object->retained_warranty_fk_cond_reglement, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?facid='.$object->id, (string) $object->retained_warranty_fk_cond_reglement, 'none'); if (!$displayWarranty) { print img_picto($langs->trans('RetainedWarrantyNeed100Percent'), 'warning.png', 'class="pictowarning valignmiddle" '); } @@ -6138,7 +6190,7 @@ if ($action == 'create') { $filedir, $urlsource, $genallowed, - $delallowed, + (int) $delallowed, $object->model_pdf, 1, 0, diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php index 4da9526ebb2..bc10b732054 100644 --- a/htdocs/compta/facture/class/api_invoices.class.php +++ b/htdocs/compta/facture/class/api_invoices.class.php @@ -34,7 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; class Invoices extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid', @@ -184,6 +184,8 @@ class Invoices extends DolibarrApi * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0 * @param int $loadlinkedobjects Load also linked object * @return array Array of invoice objects + * @phan-return Facture[]|array{data:Facture[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Facture[]|array{data:Facture[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException 404 Not found * @throws RestException 503 Error @@ -446,6 +448,8 @@ class Invoices extends DolibarrApi * * @param int $id Id of invoice * @return array Array of lines + * @phan-return CommonInvoiceLine[] + * @phpstan-return CommonInvoiceLine[] * * @url GET {id}/lines */ @@ -1446,6 +1450,8 @@ class Invoices extends DolibarrApi * * @param int $id Id of invoice * @return array + * @phan-return array + * @phpstan-return array * * @url GET {id}/payments * @@ -1473,7 +1479,7 @@ class Invoices extends DolibarrApi } $result = $this->invoice->getListOfPayments(); - if ($result < 0) { + if (!is_array($result) && $result < 0) { throw new RestException(405, $this->invoice->error); } @@ -1660,7 +1666,7 @@ class Invoices extends DolibarrApi // Loop on each invoice to pay foreach ($arrayofamounts as $id => $amountarray) { - $result = $this->invoice->fetch($id); + $result = $this->invoice->fetch((int) $id); if (!$result) { $this->db->rollback(); throw new RestException(404, 'Invoice ID '.$id.' not found'); diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index b7e1b046a26..c34962bc25f 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -373,7 +373,7 @@ class FactureRec extends CommonInvoice $sql .= ") VALUES ("; $sql .= "'".$this->db->escape($this->titre ? $this->titre : $this->title)."'"; $sql .= ", ".((int) $this->socid); - $sql .= ", ".($this->subtype ? "'".$this->db->escape($this->subtype)."'" : "null"); + $sql .= ", ".($this->subtype ? "'".$this->db->escape((string) $this->subtype)."'" : "null"); $sql .= ", ".((int) $conf->entity); $sql .= ", '".$this->db->idate($now)."'"; $sql .= ", ".(!empty($facsrc->total_ttc) ? ((float) $facsrc->total_ttc) : '0'); @@ -554,9 +554,9 @@ class FactureRec extends CommonInvoice /** * Update a line invoice_rec. * - * @param User $user User - * @param int $notrigger No trigger - * @return int Return integer <0 if KO, Id of line if OK + * @param User $user User + * @param int<0,1> $notrigger No trigger + * @return int Return integer <0 if KO, Id of line if OK */ public function update(User $user, $notrigger = 0) { @@ -611,12 +611,12 @@ class FactureRec extends CommonInvoice /** * Load object and lines * - * @param int $rowid Id of object to load - * @param string $ref Reference of recurring invoice - * @param string $ref_ext External reference of invoice - * @param int $noextrafields 0=Default to load extrafields, 1=No extrafields - * @param int $nolines 0=Default to load lines, 1=No lines - * @return int >0 if OK, <0 if KO, 0 if not found + * @param int $rowid Id of object to load + * @param string $ref Reference of recurring invoice + * @param string $ref_ext External reference of invoice + * @param int<0,1> $noextrafields 0=Default to load extrafields, 1=No extrafields + * @param int<0,1> $nolines 0=Default to load lines, 1=No lines + * @return int If OK >0, <0 if KO, 0 if not found */ public function fetch($rowid, $ref = '', $ref_ext = '', $noextrafields = 0, $nolines = 0) { @@ -861,10 +861,10 @@ class FactureRec extends CommonInvoice /** * Delete template invoice * - * @param User $user User that delete. - * @param int $notrigger 1=Does not execute triggers, 0= execute triggers - * @param int $idwarehouse Id warehouse to use for stock change. - * @return int Return integer <0 if KO, >0 if OK + * @param User $user User that delete. + * @param int<0,1> $notrigger 1=Does not execute triggers, 0= execute triggers + * @param int $idwarehouse Id warehouse to use for stock change. + * @return int Return integer <0 if KO, >0 if OK */ public function delete(User $user, $notrigger = 0, $idwarehouse = -1) { @@ -925,27 +925,27 @@ class FactureRec extends CommonInvoice * Add a line to invoice * * @param string $desc Description de la ligne - * @param double $pu_ht Prix unitaire HT (> 0 even for credit note) - * @param double $qty Quantite - * @param double $txtva Taux de tva force, sinon -1 - * @param double $txlocaltax1 Local tax 1 rate (deprecated) - * @param double $txlocaltax2 Local tax 2 rate (deprecated) + * @param float $pu_ht Prix unitaire HT (> 0 even for credit note) + * @param float $qty Quantite + * @param float $txtva Taux de tva force, sinon -1 + * @param float $txlocaltax1 Local tax 1 rate (deprecated) + * @param float $txlocaltax2 Local tax 2 rate (deprecated) * @param int $fk_product Product/Service ID predefined - * @param double $remise_percent Percentage discount of the line + * @param float $remise_percent Percentage discount of the line * @param string $price_base_type HT or TTC * @param int $info_bits VAT npr or not ? * @param int $fk_remise_except Id remise - * @param double $pu_ttc Prix unitaire TTC (> 0 even for credit note) + * @param float $pu_ttc Prix unitaire TTC (> 0 even for credit note) * @param int $type Type of line (0=product, 1=service) * @param int $rang Position of line * @param int $special_code Special code * @param string $label Label of the line - * @param string $fk_unit Unit - * @param double $pu_ht_devise Unit price in currency + * @param ?int $fk_unit Unit + * @param float $pu_ht_devise Unit price in currency * @param int $date_start_fill 1=Flag to fill start date when generating invoice * @param int $date_end_fill 1=Flag to fill end date when generating invoice - * @param int $fk_fournprice Supplier price id (to calculate margin) or '' - * @param int $pa_ht Buying price of line (to calculate margin) or '' + * @param ?int $fk_fournprice Supplier price id (to calculate margin) or '' + * @param float $pa_ht Buying price of line (to calculate margin) or '' * @param int $fk_parent_line Id of parent line * @return int Return integer <0 if KO, Id of line if OK */ @@ -963,7 +963,7 @@ class FactureRec extends CommonInvoice return -1; } - $localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc); + $localtaxes_type = getLocalTaxesFromRate((float) $txtva, 0, $this->thirdparty, $mysoc); // Clean vat code $reg = array(); @@ -1088,7 +1088,7 @@ class FactureRec extends CommonInvoice $sql .= ", '".$this->db->escape(isset($localtaxes_type[0]) ? $localtaxes_type[0] : '')."'"; $sql .= ", ".price2num($txlocaltax2); $sql .= ", '".$this->db->escape(isset($localtaxes_type[2]) ? $localtaxes_type[2] : '')."'"; - $sql .= ", ".(!empty($fk_product) ? "'".$this->db->escape($fk_product)."'" : "null"); + $sql .= ", ".(!empty($fk_product) ? "'".$this->db->escape((string) $fk_product)."'" : "null"); $sql .= ", ".((int) $product_type); $sql .= ", ".price2num($remise_percent); $sql .= ", ".price2num($pu_ht); @@ -1131,28 +1131,28 @@ class FactureRec extends CommonInvoice * * @param int $rowid Id of line to update * @param string $desc Description de la ligne - * @param double $pu_ht Prix unitaire HT (> 0 even for credit note) - * @param double $qty Quantite - * @param double $txtva Taux de tva force, sinon -1 - * @param double $txlocaltax1 Local tax 1 rate (deprecated) - * @param double $txlocaltax2 Local tax 2 rate (deprecated) + * @param float $pu_ht Prix unitaire HT (> 0 even for credit note) + * @param float $qty Quantite + * @param float $txtva Taux de tva force, sinon -1 + * @param float $txlocaltax1 Local tax 1 rate (deprecated) + * @param float $txlocaltax2 Local tax 2 rate (deprecated) * @param int $fk_product Product/Service ID predefined - * @param double $remise_percent Percentage discount of the line + * @param float $remise_percent Percentage discount of the line * @param string $price_base_type HT or TTC * @param int $info_bits Bits of type of lines * @param int $fk_remise_except Id remise - * @param double $pu_ttc Prix unitaire TTC (> 0 even for credit note) + * @param float $pu_ttc Prix unitaire TTC (> 0 even for credit note) * @param int $type Type of line (0=product, 1=service) * @param int $rang Position of line * @param int $special_code Special code * @param string $label Label of the line - * @param string $fk_unit Unit - * @param double $pu_ht_devise Unit price in currency - * @param int $notrigger disable line update trigger + * @param ?int $fk_unit Unit + * @param float $pu_ht_devise Unit price in currency + * @param int<0,1> $notrigger disable line update trigger * @param int $date_start_fill 1=Flag to fill start date when generating invoice * @param int $date_end_fill 1=Flag to fill end date when generating invoice - * @param int $fk_fournprice Id of origin supplier price - * @param int $pa_ht Price (without tax) of product for margin calculation + * @param ?int $fk_fournprice Id of origin supplier price + * @param float $pa_ht Price (without tax) of product for margin calculation * @param int $fk_parent_line Id of parent line * @return int Return integer <0 if KO, Id of line if OK */ @@ -1270,7 +1270,7 @@ class FactureRec extends CommonInvoice $sql .= ", localtax1_type='".$this->db->escape($localtaxes_type[0])."'"; $sql .= ", localtax2_tx=".((float) $txlocaltax2); $sql .= ", localtax2_type='".$this->db->escape($localtaxes_type[2])."'"; - $sql .= ", fk_product=".(!empty($fk_product) ? "'".$this->db->escape($fk_product)."'" : "null"); + $sql .= ", fk_product=".(!empty($fk_product) ? "'".$this->db->escape((string) $fk_product)."'" : "null"); $sql .= ", product_type=".((int) $product_type); $sql .= ", remise_percent='".price2num($remise_percent)."'"; $sql .= ", subprice='".price2num($pu_ht)."'"; @@ -1286,7 +1286,7 @@ class FactureRec extends CommonInvoice $sql .= ", info_bits=".((int) $info_bits); $sql .= ", rang=".((int) $rang); $sql .= ", special_code=".((int) $special_code); - $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape($fk_unit)."'" : "null"); + $sql .= ", fk_unit=".($fk_unit ? "'".$this->db->escape((string) $fk_unit)."'" : "null"); $sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise); $sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht); $sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva); @@ -1321,7 +1321,7 @@ class FactureRec extends CommonInvoice /** * Return if maximum number of generation is reached * - * @return boolean False by default, True if maximum number of generation is reached + * @return bool False by default, True if maximum number of generation is reached */ public function isMaxNbGenReached() { @@ -1333,7 +1333,7 @@ class FactureRec extends CommonInvoice } /** - * Format string to output with by striking the string if max number of generation was reached + * Format string to output with by striking the string if max number of generations was reached * * @param string $ret Default value to output * @return string html formatted string @@ -1349,10 +1349,10 @@ class FactureRec extends CommonInvoice * * WARNING: This method change temporarily context $conf->entity to be in correct context for each recurring invoice found. * - * @param int $restrictioninvoiceid 0=All qualified template invoices found. > 0 = restrict action on invoice ID - * @param int $forcevalidation 1=Force validation of invoice whatever is template auto_validate flag. - * @param int $notrigger Disable the trigger - * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) + * @param int<0,max> $restrictioninvoiceid 0=All qualified template invoices found. > 0 = restrict action on invoice ID + * @param int<0,1> $forcevalidation 1=Force validation of invoice whatever is template auto_validate flag. + * @param int<0,1> $notrigger Disable the trigger + * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ public function createRecurringInvoices($restrictioninvoiceid = 0, $forcevalidation = 0, $notrigger = 0) { @@ -1513,13 +1513,13 @@ class FactureRec extends CommonInvoice /** * Return clickable name (with picto eventually) * - * @param int $withpicto Add picto into link - * @param string $option Where point the link - * @param int $max Maxlength of ref - * @param int $short 1=Return just URL - * @param string $moretitle Add more text to title tooltip - * @param int $notooltip 1=Disable tooltip - * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @param int $withpicto Add picto into link + * @param string $option Where point the link + * @param int $max Maxlength of ref + * @param int<0,1> $short 1=Return just URL + * @param string $moretitle Add more text to title tooltip + * @param int<0,1> $notooltip 1=Disable tooltip + * @param int<-1,1> $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking * @return string String with URL */ public function getNomUrl($withpicto = 0, $option = '', $max = 0, $short = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1) @@ -1591,9 +1591,9 @@ class FactureRec extends CommonInvoice /** * Return label of object status * - * @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 integer $alreadypaid Not used on recurring invoices - * @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, 6=Long label + picto + * @param int<-1,1> $alreadypaid Not used on recurring invoices + * @return string Label of status */ public function getLibStatut($mode = 0, $alreadypaid = -1) { @@ -1604,10 +1604,10 @@ class FactureRec extends CommonInvoice /** * Return label of a status * - * @param int $recur Is it a recurring invoice ? + * @param int<0,1> $recur Is it a recurring invoice ? * @param int $status Id status (suspended or not) * @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 $alreadypaid Not used for recurring invoices + * @param int<-1,1> $alreadypaid Not used for recurring invoices * @param int $type Type invoice * @param int $nbofopendirectdebitorcredittransfer @unused-param Nb of open direct debit or credit transfer * @return string Label of status @@ -1739,9 +1739,9 @@ class FactureRec extends CommonInvoice /** * Return next reference of invoice not already used (or last reference) * - * @param Societe $soc Thirdparty object - * @param string $mode 'next' for next value or 'last' for last value - * @return string free ref or last ref + * @param Societe $soc Thirdparty object + * @param 'next'|'last' $mode 'next' for next value or 'last' for last value + * @return string free ref or last ref */ public function getNextNumRef($soc, $mode = 'next') { @@ -1967,7 +1967,7 @@ class FactureRec extends CommonInvoice } $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; - $sql .= ' SET frequency = '.($frequency ? $this->db->escape($frequency) : 'null'); + $sql .= ' SET frequency = '.($frequency ? $this->db->escape((string) $frequency) : 'null'); if (!empty($unit)) { $sql .= ', unit_frequency = \''.$this->db->escape($unit).'\''; } @@ -2053,9 +2053,9 @@ class FactureRec extends CommonInvoice /** * Update the maximum period * - * @param int $nb number of maximum period - * @param int $notrigger Disable the trigger - * @return int Return integer <0 if KO, >0 if OK + * @param int $nb number of maximum period + * @param int<0,1> $notrigger Disable the trigger + * @return int Return integer <0 if KO, >0 if OK */ public function setMaxPeriod($nb, $notrigger = 0) { @@ -2097,9 +2097,9 @@ class FactureRec extends CommonInvoice /** * Update the auto validate flag of invoice * - * @param int $validate 0 to create in draft, 1 to create and validate invoice - * @param int $notrigger Disable the trigger - * @return int Return integer <0 if KO, >0 if OK + * @param int<0,1> $validate 0 to create in draft, 1 to create and validate invoice + * @param int<0,1> $notrigger Disable the trigger + * @return int Return integer <0 if KO, >0 if OK */ public function setAutoValidate($validate, $notrigger = 0) { @@ -2137,9 +2137,9 @@ class FactureRec extends CommonInvoice /** * Update the auto generate documents * - * @param int $validate 0 no document, 1 to generate document - * @param int $notrigger Disable the trigger - * @return int Return integer <0 if KO, >0 if OK + * @param int<0,1> $validate 0 no document, 1 to generate document + * @param int<0,1> $notrigger Disable the trigger + * @return int Return integer <0 if KO, >0 if OK */ public function setGeneratePdf($validate, $notrigger = 0) { @@ -2178,7 +2178,7 @@ class FactureRec extends CommonInvoice * Update the model for documents * * @param string $model model of document generator - * @param int $notrigger Disable the trigger + * @param int<0,1> $notrigger Disable the trigger * @return int Return integer <0 if KO, >0 if OK */ public function setModelPdf($model, $notrigger = 0) @@ -2431,8 +2431,8 @@ class FactureLigneRec extends CommonInvoiceLine /** * Update a line to invoice_rec. * - * @param User $user User - * @param int $notrigger No trigger + * @param User $user User + * @param int<0,1> $notrigger No trigger * @return int Return integer <0 if KO, Id of line if OK */ public function update(User $user, $notrigger = 0) @@ -2458,9 +2458,9 @@ class FactureLigneRec extends CommonInvoiceLine $sql .= ", tva_tx=".price2num($this->tva_tx); $sql .= ", vat_src_code='".$this->db->escape($this->vat_src_code)."'"; $sql .= ", localtax1_tx=".price2num($this->localtax1_tx); - $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'"; + $sql .= ", localtax1_type='".$this->db->escape((string) $this->localtax1_type)."'"; $sql .= ", localtax2_tx=".price2num($this->localtax2_tx); - $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'"; + $sql .= ", localtax2_type='".$this->db->escape((string) $this->localtax2_type)."'"; $sql .= ", fk_product=".($this->fk_product > 0 ? $this->fk_product : "null"); $sql .= ", product_type=".((int) $this->product_type); $sql .= ", remise_percent=".price2num($this->remise_percent); @@ -2477,7 +2477,7 @@ class FactureLigneRec extends CommonInvoiceLine } $sql .= ", rang=".((int) $this->rang); $sql .= ", special_code=".((int) $this->special_code); - $sql .= ", fk_unit=".($this->fk_unit ? "'".$this->db->escape($this->fk_unit)."'" : "null"); + $sql .= ", fk_unit=".($this->fk_unit ? "'".$this->db->escape((string) $this->fk_unit)."'" : "null"); $sql .= ", fk_contract_line=".($this->fk_contract_line ? $this->fk_contract_line : "null"); $sql .= " WHERE rowid = ".((int) $this->id); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 339848b0269..680477653a1 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -15,9 +15,10 @@ * Copyright (C) 2013 Cedric Gross * Copyright (C) 2013 Florian Henry * Copyright (C) 2016-2025 Ferran Marcet - * Copyright (C) 2018-2024 Alexandre Spangaro + * Copyright (C) 2018-2025 Alexandre Spangaro * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2022 Sylvain Legrand + * Copyright (C) 2022-2023 Solution Libre SAS * Copyright (C) 2023 Gauthier VERDOL * Copyright (C) 2023 Nick Fragoulis * Copyright (C) 2024-2025 MDW @@ -2538,10 +2539,10 @@ class Facture extends CommonInvoice if (isset($this->retained_warranty)) { $this->retained_warranty = (float) $this->retained_warranty; } - if (!isset($this->user_creation_id) && isset($this->fk_user_author) ) { + if (!isset($this->user_creation_id) && isset($this->fk_user_author)) { $this->user_creation_id = $this->fk_user_author; } - if (!isset($this->user_validation_id) && isset($this->fk_user_valid) ) { + if (!isset($this->user_validation_id) && isset($this->fk_user_valid)) { $this->user_validation_id = $this->fk_user_valid; } @@ -2823,6 +2824,18 @@ class Facture extends CommonInvoice // End call triggers } + // Remove linked categories. + if (!$error) { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_invoice"; + $sql .= " WHERE fk_invoice = ".((int) $this->id); + + $result = $this->db->query($sql); + if (!$result) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + // Removed extrafields if (!$error) { $result = $this->deleteExtraFields(); @@ -4175,7 +4188,7 @@ class Facture extends CommonInvoice * @param string $label Label of the line (deprecated, do not use) * @param int $special_code Special code (also used by externals modules!) * @param array $array_options extrafields array - * @param int $situation_percent Situation advance percentage + * @param float $situation_percent Situation advance percentage * @param ?int $fk_unit Code of the unit to use. Null to use the default one * @param float $pu_ht_devise Unit price in currency * @param int<0,1> $notrigger disable line update trigger @@ -4694,6 +4707,22 @@ class Facture extends CommonInvoice } */ + /** + * Sets object to given categories. + * + * Adds it to non existing supplied categories. + * Existing categories are left untouch. + * + * @param int[]|int $categories Category or categories IDs + * + * @return int Return integer <0 if KO, >0 if OK + */ + public function setCategories($categories) + { + require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; + return parent::setCategoriesCommon($categories, Categorie::TYPE_INVOICE); + } + /** * Return next reference of customer invoice not already used (or last reference) * according to numbering module defined into constant FACTURE_ADDON @@ -6017,6 +6046,7 @@ class Facture extends CommonInvoice $actioncomm->errors_to = $errors_to; $actioncomm->elementtype = 'invoice'; + $actioncomm->elementid = $tmpinvoice->id; $actioncomm->fk_element = $tmpinvoice->id; //$actioncomm->extraparams = $extraparams; diff --git a/htdocs/compta/facture/class/factureligne.class.php b/htdocs/compta/facture/class/factureligne.class.php index 8de79169b17..d88fdbd2436 100644 --- a/htdocs/compta/facture/class/factureligne.class.php +++ b/htdocs/compta/facture/class/factureligne.class.php @@ -20,7 +20,7 @@ * Copyright (C) 2022 Sylvain Legrand * Copyright (C) 2023 Gauthier VERDOL * Copyright (C) 2023 Nick Fragoulis - * 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 @@ -432,8 +432,8 @@ class FactureLigne extends CommonInvoiceLine $sql .= " ".price2num($this->tva_tx).","; $sql .= " ".price2num($this->localtax1_tx).","; $sql .= " ".price2num($this->localtax2_tx).","; - $sql .= " '".$this->db->escape($this->localtax1_type)."',"; - $sql .= " '".$this->db->escape($this->localtax2_type)."',"; + $sql .= " '".$this->db->escape((string) $this->localtax1_type)."',"; + $sql .= " '".$this->db->escape((string) $this->localtax2_type)."',"; $sql .= ' '.((!empty($this->fk_product) && $this->fk_product > 0) ? $this->fk_product : "null").','; $sql .= " ".((int) $this->product_type).","; $sql .= " ".price2num($this->remise_percent).","; @@ -447,7 +447,7 @@ class FactureLigne extends CommonInvoiceLine $sql .= ' '.((int) $this->special_code).','; $sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").','; $sql .= ' '.price2num($this->pa_ht).','; - $sql .= " '".$this->db->escape($this->info_bits)."',"; + $sql .= " '".$this->db->escape((string) $this->info_bits)."',"; $sql .= " ".price2num($this->total_ht).","; $sql .= " ".price2num($this->total_tva).","; $sql .= " ".price2num($this->total_ttc).","; @@ -649,13 +649,13 @@ class FactureLigne extends CommonInvoiceLine $sql .= ", tva_tx=".price2num($this->tva_tx); $sql .= ", localtax1_tx=".price2num($this->localtax1_tx); $sql .= ", localtax2_tx=".price2num($this->localtax2_tx); - $sql .= ", localtax1_type='".$this->db->escape($this->localtax1_type)."'"; - $sql .= ", localtax2_type='".$this->db->escape($this->localtax2_type)."'"; + $sql .= ", localtax1_type='".$this->db->escape((string) $this->localtax1_type)."'"; + $sql .= ", localtax2_type='".$this->db->escape((string) $this->localtax2_type)."'"; $sql .= ", qty=".price2num($this->qty); $sql .= ", date_start=".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null"); $sql .= ", date_end=".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null"); $sql .= ", product_type=".$this->product_type; - $sql .= ", info_bits='".$this->db->escape($this->info_bits)."'"; + $sql .= ", info_bits='".$this->db->escape((string) $this->info_bits)."'"; $sql .= ", special_code=" . (int) $this->special_code; if (empty($this->skip_update_total)) { $sql .= ", total_ht=".price2num($this->total_ht); @@ -664,7 +664,7 @@ class FactureLigne extends CommonInvoiceLine $sql .= ", total_localtax1=".price2num($this->total_localtax1); $sql .= ", total_localtax2=".price2num($this->total_localtax2); } - $sql .= ", fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? "'".$this->db->escape($this->fk_fournprice)."'" : "null"); + $sql .= ", fk_product_fournisseur_price=".(!empty($this->fk_fournprice) ? "'".$this->db->escape((string) $this->fk_fournprice)."'" : "null"); $sql .= ", buy_price_ht=".(($this->pa_ht || (string) $this->pa_ht === '0') ? price2num($this->pa_ht) : "null"); // $this->pa_ht should always be defined (set to 0 or to sell price depending on option) $sql .= ", fk_parent_line=".($this->fk_parent_line > 0 ? $this->fk_parent_line : "null"); if (!empty($this->rang)) { diff --git a/htdocs/compta/facture/class/paymentterm.class.php b/htdocs/compta/facture/class/paymentterm.class.php index 7cd3648e771..89116d35ae3 100644 --- a/htdocs/compta/facture/class/paymentterm.class.php +++ b/htdocs/compta/facture/class/paymentterm.class.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 @@ -164,7 +164,7 @@ class PaymentTerm // extends CommonObject $sql .= "nbjour,"; $sql .= "decalage"; $sql .= ") VALUES ("; - $sql .= " ".(!isset($this->entity) ? getEntity('c_payment_term') : "'".$this->db->escape($this->entity)."'").","; + $sql .= " ".(!isset($this->entity) ? getEntity('c_payment_term') : "'".$this->db->escape((string) $this->entity)."'").","; $sql .= " ".(!isset($this->code) ? 'NULL' : "'".$this->db->escape($this->code)."'").","; $sql .= " ".(!isset($this->sortorder) ? 'NULL' : "'".$this->db->escape($this->sortorder)."'").","; $sql .= " ".(!isset($this->active) ? 'NULL' : "'".$this->db->escape($this->active)."'").","; diff --git a/htdocs/compta/facture/contact.php b/htdocs/compta/facture/contact.php index 884a954e758..38f886ee9f5 100644 --- a/htdocs/compta/facture/contact.php +++ b/htdocs/compta/facture/contact.php @@ -6,7 +6,7 @@ * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2023 Christian Foellmann * 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 @@ -64,7 +64,7 @@ if ($user->socid) { $object = new Facture($db); // Load object if ($id > 0 || !empty($ref)) { - $ret = $object->fetch($id, $ref, '', 0, getDolGlobalInt('INVOICE_USE_SITUATION')); + $ret = $object->fetch($id, $ref, '', 0, getDolGlobalBool('INVOICE_USE_SITUATION')); } // Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context $hookmanager->initHooks(array('invoicecontactcard', 'globalcard')); @@ -169,7 +169,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/compta/facture/document.php b/htdocs/compta/facture/document.php index 9155185c460..e362cec8b55 100644 --- a/htdocs/compta/facture/document.php +++ b/htdocs/compta/facture/document.php @@ -7,6 +7,7 @@ * Copyright (C) 2017 Ferran Marcet * Copyright (C) 2017-2024 Frédéric France * Copyright (C) 2025 Alexandre Spangaro + * 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 @@ -169,7 +170,7 @@ if ($id > 0 || !empty($ref)) { if ($action != 'classify') { $morehtmlref .= ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 0d0cf80fc5d..2e4920cd379 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -868,7 +868,7 @@ if ($search_status != '-1' && $search_status != '') { $sql .= " AND f.fk_statut = 3"; // abandoned } } else { - $sql .= " AND f.fk_statut IN (".$db->sanitize($db->escape($search_status)).")"; // When search_status is '1,2' for example + $sql .= " AND f.fk_statut IN (".$db->sanitize($search_status).")"; // When search_status is '1,2' for example } } @@ -2169,7 +2169,7 @@ if ($num > 0) { } else { // Show line of result $j = 0; - print ''.img_edit($langs->transnoentitiesnoconv('SetProject')).' '; } - $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300'); } else { if (!empty($object->fk_project)) { $proj = new Project($db); @@ -529,9 +529,9 @@ if ($object->id > 0) { print ''; if ($object->type != $object::TYPE_CREDIT_NOTE) { if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, $type); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'cond_reglement_id', 0, $type); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->cond_reglement_id, 'none'); } } else { print ' '; @@ -582,9 +582,9 @@ if ($object->id > 0) { $filtertype = 'DBIT'; } if ($action == 'editmode') { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'mode_reglement_id', $filtertype, 1, 0, $type); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', $filtertype, 1, 0, $type); } else { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->mode_reglement_id, 'none'); + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->mode_reglement_id, 'none'); } print ''; @@ -599,9 +599,9 @@ if ($object->id > 0) { print ''; print ''; if ($action == 'editbankaccount') { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'fk_account', 1); } else { - $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, (string) $object->fk_account, 'none'); } print ''; print ''; diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index d502c49d1c2..c1fd906ff66 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -1514,13 +1514,13 @@ class BonPrelevement extends CommonObject } if (!$error && !$notrigger) { - $triggername = 'DIRECT_DEBIT_ORDER_CREATE'; + $triggerName = 'DIRECT_DEBIT_ORDER_CREATE'; if ($type != 'bank-transfer') { - $triggername = 'CREDIT_TRANSFER_ORDER_CREATE'; + $triggerName = 'CREDIT_TRANSFER_ORDER_CREATE'; } // Call trigger - $result = $this->call_trigger($triggername, $user); + $result = $this->call_trigger($triggerName, $user); if ($result < 0) { $error++; } diff --git a/htdocs/contrat/class/api_contracts.class.php b/htdocs/contrat/class/api_contracts.class.php index 55771f352bf..674cb399081 100644 --- a/htdocs/contrat/class/api_contracts.class.php +++ b/htdocs/contrat/class/api_contracts.class.php @@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php'; class Contracts extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid', @@ -97,6 +97,8 @@ class Contracts extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of order objects + * @phan-return Contrat[]|array{data:Contrat[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Contrat[]|array{data:Contrat[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException 404 Not found * @throws RestException 503 Error @@ -242,6 +244,8 @@ class Contracts extends DolibarrApi * @url GET {id}/lines * * @return array + * @phan-return ContratLigne[] + * @phpstan-return ContratLigne[] */ public function getLines($id) { @@ -415,7 +419,7 @@ class Contracts extends DolibarrApi throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - $updateRes = $this->contract->active_line(DolibarrApiAccess::$user, $lineid, $datestart, $dateend, $comment); + $updateRes = $this->contract->active_line(DolibarrApiAccess::$user, $lineid, (int) $datestart, $dateend, $comment); if ($updateRes > 0) { $result = $this->get($id); @@ -453,7 +457,7 @@ class Contracts extends DolibarrApi throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - $updateRes = $this->contract->close_line(DolibarrApiAccess::$user, $lineid, $datestart, $comment); + $updateRes = $this->contract->close_line(DolibarrApiAccess::$user, $lineid, (int) $datestart, $comment); if ($updateRes > 0) { $result = $this->get($id); diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 61110da9071..21b4b9fc85a 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -1390,7 +1390,9 @@ class Contrat extends CommonObject if (isset($this->import_key)) { $this->import_key = trim($this->import_key); } - //if (isset($this->extraparams)) $this->extraparams=trim($this->extraparams); + + $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null); + $extraparams = dol_trunc($extraparams, 250); // $this->oldcopy must have been set by the caller of update @@ -1410,7 +1412,7 @@ class Contrat extends CommonObject $sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").","; $sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").","; $sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null"); - //$sql.= " extraparams=".(isset($this->extraparams)?"'".$this->db->escape($this->extraparams)."'":"null"); + $sql .= " extraparams=".(isset($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null"); $sql .= " WHERE rowid=".((int) $this->id); $this->db->begin(); diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php index 6492494039c..61d0e6752d0 100644 --- a/htdocs/core/actions_sendmails.inc.php +++ b/htdocs/core/actions_sendmails.inc.php @@ -24,24 +24,25 @@ * \brief Code for actions on sending mails from object page */ -// $mysoc must be defined -// $id must be defined -// $paramname may be defined -// $autocopy may be defined (used to know the automatic BCC to add) -// $triggersendname must be set (can be '') -// $actiontypecode can be set -// $object and $subject may be defined /** + * @var Societe $mysoc * @var CommonObject $object * @var Conf $conf * @var DoliDB $db * @var HookManager $hookmanager * @var Societe $mysoc * @var Translate $langs + * @var User $user * - * @var string $dolibarr_main_url_root - * @var string $action + * @var int $id + * @var string $dolibarr_main_url_root + * @var string $action * @var ?string $subject + * @var ?string $triggersendname (can be '') + * @var ?string $sendcontext + * @var ?string $autocopy (used to know the automatic BCC to add) + * @var ?string $actiontypecode + * @var ?string $paramname */ ' @phan-var-force Societe $mysoc @@ -306,6 +307,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $reg = array(); $fromtype = GETPOST('fromtype', 'alpha'); + $emailsendersignature = ''; if ($fromtype === 'robot') { $from = dol_string_nospecial($conf->global->MAIN_MAIL_EMAIL_FROM, ' ', array(",")).' <' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM').'>'; } elseif ($fromtype === 'user') { @@ -319,12 +321,13 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $tmp = explode(',', getDolGlobalString('MAIN_INFO_SOCIETE_MAIL_ALIASES')); $from = trim($tmp[((int) $reg[1] - 1)]); } elseif (preg_match('/senderprofile_(\d+)_(\d+)/', $fromtype, $reg)) { - $sql = 'SELECT rowid, label, email FROM '.MAIN_DB_PREFIX.'c_email_senderprofile'; + $sql = 'SELECT rowid, label, email, signature FROM '.MAIN_DB_PREFIX.'c_email_senderprofile'; $sql .= ' WHERE rowid = '.(int) $reg[1]; $resql = $db->query($sql); $obj = $db->fetch_object($resql); if ($obj) { $from = dol_string_nospecial($obj->label, ' ', array(",")).' <'.$obj->email.'>'; + $emailsendersignature = $obj->signature; } } elseif (preg_match('/from_template_(\d+)/', $fromtype, $reg)) { $sql = 'SELECT rowid, email_from FROM '.MAIN_DB_PREFIX.'c_email_templates'; @@ -384,6 +387,8 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO // Make substitution in email content $substitutionarray = getCommonSubstitutionArray($langs, 0, null, $object); + + $substitutionarray['__SENDEREMAIL_SIGNATURE__'] = (empty($emailsendersignature) ? $user->signature : $emailsendersignature); $substitutionarray['__EMAIL__'] = $sendto; $substitutionarray['__CHECK_READ__'] = (is_object($object) && is_object($object->thirdparty)) ? '' : ''; @@ -442,9 +447,9 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $object->email_tocc = $sendtocc; $object->email_tobcc = $sendtobcc; - // Call of triggers (you should have set $triggersendname to execute trigger. $trigger_name is deprecated) - if (!empty($triggersendname) || !empty($trigger_name)) { - $result = $object->call_trigger(empty($triggersendname) ? $trigger_name : $triggersendname, $user); // @phan-suppress-current-line PhanPossiblyUndeclaredGlobalVariable + // Call of triggers (you should have set $triggersendname to execute trigger. + if (!empty($triggersendname)) { + $result = $object->call_trigger($triggersendname, $user); // @phan-suppress-current-line PhanPossiblyUndeclaredGlobalVariable if ($result < 0) { $error++; } @@ -460,12 +465,7 @@ if (($action == 'send' || $action == 'relance') && !GETPOST('addfile') && !GETPO $mesg = $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($sendto, 2)); setEventMessages($mesg, null, 'mesgs'); - $moreparam = ''; - if (isset($paramval2)) { // @phan-var-suppress-current-line PhanPluginUndeclaredVariableIsset - // @phan-var-suppress-next-line PhanUndeclaredGlobalVariable - $moreparam .= '&'.($paramname2 ? $paramname2 : 'mid').'='.$paramval2; - } - header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname ?? 'id').'='.(is_object($object) ? $object->id : '').$moreparam); + header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname ?? 'id').'='.(is_object($object) ? $object->id : '')); exit; } else { $langs->load("other"); diff --git a/htdocs/core/ajax/saveinplace.php b/htdocs/core/ajax/saveinplace.php index 9d94c28aac1..cabbe1a6e05 100644 --- a/htdocs/core/ajax/saveinplace.php +++ b/htdocs/core/ajax/saveinplace.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 @@ -164,7 +164,7 @@ if (!empty($field) && !empty($element) && !empty($table_element) && !empty($fk_e } //var_dump(GETPOST('action','aZ09')); //var_dump($newelement.'-'.$subelement."-".$feature."-".$object_id); - $check_access = restrictedArea($user, $feature, $object_id, '', $feature2); + $check_access = restrictedArea($user, $feature, $object_id, '', (string) $feature2); //var_dump($user->rights); /* if (!empty($user->rights->$newelement->creer) || !empty($user->rights->$newelement->create) || !empty($user->rights->$newelement->write) diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index a2a431b00db..40157e16ed7 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -1617,7 +1617,7 @@ abstract class CommonInvoice extends CommonObject $extraparams .= (($extraparams && $stripefailuredeclinecode) ? ' - ' : '') . $stripefailuredeclinecode; } else { $actioncode = 'PAYMENT_STRIPE_OK'; - $extraparams = ''; + $extraparams = array(); } } else { $error++; @@ -1635,7 +1635,7 @@ abstract class CommonInvoice extends CommonObject $object = $this; $actioncode = 'PAYMENT_STRIPE_KO'; - $extraparams = ''; + $extraparams = array(); } } else { // If error because payment was canceled for a logical reason, we do nothing (no event added) @@ -1646,7 +1646,7 @@ abstract class CommonInvoice extends CommonObject $object = $this; $actioncode = ''; - $extraparams = ''; + $extraparams = array(); } } else { // Else of the if ($resultthirdparty > 0 && ! empty($customer)) { if ($resultthirdparty <= 0) { @@ -1669,7 +1669,7 @@ abstract class CommonInvoice extends CommonObject $object = $this; $actioncode = 'PAYMENT_STRIPE_KO'; - $extraparams = ''; + $extraparams = array(); } if ($description) { @@ -1701,8 +1701,9 @@ abstract class CommonInvoice extends CommonObject $actioncomm->email_subject = $object->email_subject; $actioncomm->errors_to = $object->errors_to;*/ $actioncomm->fk_element = $this->id; + $actioncomm->elementid = $this->id; $actioncomm->elementtype = $this->element; - $actioncomm->extraparams = dol_trunc($extraparams, 250); + $actioncomm->extraparams = $extraparams; // Can be null, empty string or array() $actioncomm->create($user); } diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 354062cdd59..35d777bcef0 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -823,7 +823,7 @@ abstract class CommonObject public $output; /** - * @var array|string extra parameters. Try to store here the array of parameters. Old code is sometimes storing a string. + * @var array|string Extra parameters. Try to store here the array of parameters. Old code is sometimes storing a string. */ public $extraparams = array(); @@ -2906,6 +2906,7 @@ abstract class CommonObject $line->product_type, $line->array_options, $line->ref_fourn, + (int) $line->fk_unit, $line->multicurrency_subprice ); break; @@ -3013,7 +3014,7 @@ abstract class CommonObject $sql = 'UPDATE '.$this->db->prefix().$this->table_element; $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL'); if (in_array($this->table_element, array('propal', 'commande', 'societe'))) { - $sql .= " , deposit_percent = " . (empty($deposit_percent) ? 'NULL' : "'".$this->db->escape($deposit_percent)."'"); + $sql .= " , deposit_percent = " . (empty($deposit_percent) ? 'NULL' : "'".$this->db->escape((string) $deposit_percent)."'"); } $sql .= ' WHERE rowid='.((int) $this->id); @@ -5190,6 +5191,7 @@ abstract class CommonObject $this->db->begin(); $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null); + $extraparams = dol_trunc($extraparams, 250); $sql = "UPDATE ".$this->db->prefix().$this->table_element; $sql .= " SET extraparams = ".(!empty($extraparams) ? "'".$this->db->escape($extraparams)."'" : "null"); @@ -5344,7 +5346,7 @@ abstract class CommonObject $reshook = $hookmanager->executeHooks('printObjectSubLine', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks } } - if (empty($reshook)) { + if (empty($reshook) && $buyer !== null) { $this->printObjectLine($action, $line, '', $num, $i, $dateSelector, $seller, $buyer, $selected, $extrafields, $defaulttpldir); } @@ -5394,6 +5396,7 @@ abstract class CommonObject // Define output language and label if (getDolGlobalInt('MAIN_MULTILANGS')) { + // @phan-suppress-next-line PhanUndeclaredProperty if (property_exists($this, 'socid') && !empty($this->socid) && !is_object($this->thirdparty)) { dol_print_error(null, 'Error: Method printObjectLine was called on an object and object->fetch_thirdparty was not done before'); return; @@ -5719,10 +5722,10 @@ abstract class CommonObject $sql .= ") VALUES ("; $sql .= ((int) $resource_id); $sql .= ", '".$this->db->escape($resource_type)."'"; - $sql .= ", '".$this->db->escape($this->id)."'"; + $sql .= ", '".$this->db->escape((string) $this->id)."'"; $sql .= ", '".$this->db->escape($this->element)."'"; - $sql .= ", '".$this->db->escape($busy)."'"; - $sql .= ", '".$this->db->escape($mandatory)."'"; + $sql .= ", '".$this->db->escape((string) $busy)."'"; + $sql .= ", '".$this->db->escape((string) $mandatory)."'"; $sql .= ")"; dol_syslog(get_class($this)."::add_element_resource", LOG_DEBUG); @@ -5959,10 +5962,23 @@ abstract class CommonObject $this->model_pdf = $saved_model; if ($obj instanceof ModelePDFMember) { - $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards'); + if ($this instanceof Adherent) { + $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, 'member', 1, 'tmp_cards'); + } else { + $resultwritefile = -1; + dol_syslog("Error generating document - Provided ".get_class($this)." to ".get_class($obj)."::write_file()", LOG_ERR); + } + } elseif ($obj instanceof ModeleDon) { + // Only 3 arguments + if ($this instanceof Don) { + $resultwritefile = $obj->write_file($this, $outputlangs /*, $currency */); + } else { + $resultwritefile = -1; + dol_syslog("Error generating document - Provided ".get_class($this)." to Don::write_file()", LOG_ERR); + } } else { // TODO: Try to set type above again - '@phan-var-force ModeleBarCode|ModeleDon|ModeleExports|ModeleImports|ModelePDFAsset|ModelePDFContract|ModelePDFDeliveryOrder|ModelePDFEvaluation|ModelePDFFactures|ModelePDFFicheinter|ModelePDFMo|ModelePDFMovement|ModelePDFProduct|ModelePDFProjects|ModelePDFPropales|ModelePDFRecruitmentJobPosition|ModelePDFStock|ModelePDFStockTransfer|ModelePDFSupplierProposal|ModelePDFSuppliersInvoices|ModelePDFSuppliersOrders|ModelePDFSuppliersPayments|ModelePDFTask|ModelePDFTicket|ModelePDFUser|ModelePDFUserGroup|ModelePdfExpedition|ModelePdfReception|ModeleThirdPartyDoc $obj'; + '@phan-var-force ModeleBarCode|ModeleExports|ModeleImports|ModelePDFAsset|ModelePDFContract|ModelePDFDeliveryOrder|ModelePDFEvaluation|ModelePDFFactures|ModelePDFFicheinter|ModelePDFMo|ModelePDFMovement|ModelePDFProduct|ModelePDFProjects|ModelePDFPropales|ModelePDFRecruitmentJobPosition|ModelePDFStock|ModelePDFStockTransfer|ModelePDFSupplierProposal|ModelePDFSuppliersInvoices|ModelePDFSuppliersOrders|ModelePDFSuppliersPayments|ModelePDFTask|ModelePDFTicket|ModelePDFUser|ModelePDFUserGroup|ModelePdfExpedition|ModelePdfReception|ModeleThirdPartyDoc $obj'; $resultwritefile = $obj->write_file($this, $outputlangs, $srctemplatepath, $hidedetails, $hidedesc, $hideref, $moreparams); } // After call of write_file $obj->result['fullpath'] is set with generated file. It will be used to update the ECM database index. @@ -8304,7 +8320,8 @@ abstract class CommonObject //$objectfield = $valparent; $objectfield = $val; // Is better than using old method $valparent - $out = $form->selectForForms($param_list_array[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', $morecss, $moreparam, 0, (empty($val['disabled']) ? 0 : 1), '', $objectfield); + // @phan-suppress-next-line PhanTypeMismatchArgumentNullable + $out = $form->selectForForms($param_list_array[0], $keyprefix.$key.$keysuffix, (int) $value, $showempty, '', '', $morecss, $moreparam, 0, (empty($val['disabled']) ? 0 : 1), '', $objectfield); if (!empty($param_list_array[2])) { // If the entry into $fields is set, we must add a create button if ((!GETPOSTISSET('backtopage') || strpos(GETPOST('backtopage'), $_SERVER['PHP_SELF']) === 0) // // To avoid to open several times the 'Plus' button (we accept only one level) @@ -8544,15 +8561,15 @@ abstract class CommonObject $value = yn($value ? 1 : 0); } } elseif ($type == 'mail' || $type == 'email') { - $value = dol_print_email($value, 0, 0, 0, 64, 1, 1); + $value = dol_print_email((string) $value, 0, 0, 0, 64, 1, 1); } elseif ($type == 'url') { - $value = dol_print_url($value, '_blank', 32, 1); + $value = dol_print_url((string) $value, '_blank', 32, 1); } elseif ($type == 'phone') { - $value = dol_print_phone($value, '', 0, 0, '', ' ', 'phone'); + $value = dol_print_phone((string) $value, '', 0, 0, '', ' ', 'phone'); } elseif ($type == 'ip') { - $value = dol_print_ip($value, 0); + $value = dol_print_ip((string) $value, 0); } elseif ($type == 'stars') { - $value = ''; + $value = ''; $value .= '
'; $i = 1; while ($i <= $size) { @@ -8653,7 +8670,7 @@ abstract class CommonObject } elseif ($selectkey == 'rowid') { $sql .= " WHERE ".$selectkey." = ".((int) $value); } else { - $sql .= " WHERE ".$selectkey." = '".$this->db->escape($value)."'"; + $sql .= " WHERE ".$selectkey." = '".$this->db->escape((string) $value)."'"; } //$sql.= ' AND entity = '.$conf->entity; @@ -8858,7 +8875,7 @@ abstract class CommonObject '@phan-var-force CommonObject $object'; if ($object->element === 'product') { // Special case for product because default valut of fetch are wrong '@phan-var-force Product $object'; - $result = $object->fetch($value, '', '', '', 0, 1, 1); + $result = $object->fetch((int) $value, '', '', '', 0, 1, 1); } else { $result = $object->fetch($value); } @@ -8911,7 +8928,7 @@ abstract class CommonObject if (!empty($value) && preg_match('/^text/', (string) $type) && !preg_match('/search_/', $keyprefix) && !empty($param['options'])) { $value = str_replace(',', "\n", $value); } - $value = dol_htmlentitiesbr($value); + $value = dol_htmlentitiesbr((string) $value); } //print $type.'-'.$size.'-'.$value; @@ -9009,7 +9026,7 @@ abstract class CommonObject // Convert var to be able to share same code than showOutputField of extrafields if (preg_match('/varchar\((\d+)\)/', $type, $reg)) { $type = 'varchar'; // convert varchar(xx) int varchar - $maxSize = $reg[1]; + $maxSize = (int) $reg[1]; } elseif (preg_match('/varchar/', $type)) { $type = 'varchar'; // convert varchar(xx) int varchar } @@ -9156,11 +9173,11 @@ abstract class CommonObject $InfoFieldList = explode(":", $param_list[0]); $classname = $InfoFieldList[0]; $classpath = $InfoFieldList[1]; - if (!$validate->isFetchable($fieldValue, $classname, $classpath)) { + if (!$validate->isFetchable((int) $fieldValue, $classname, $classpath)) { $lastIsFetchableError = $validate->error; // from V19 of Dolibarr, In some cases link use element instead of class, example project_task - if ($validate->isFetchableElement($fieldValue, $classname)) { + if ($validate->isFetchableElement((int) $fieldValue, $classname)) { return true; } @@ -9481,7 +9498,7 @@ abstract class CommonObject $out .= getPictoForType($extrafields->attributes[$this->table_element]['type'][$key], ($extrafields->attributes[$this->table_element]['type'][$key] == 'text' ? 'tdtop' : '')); } //$out .= ''; - $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', 0, $this, $this->table_element); + $out .= $extrafields->showInputField($key, $value, '', $keysuffix, '', '', $this, $this->table_element); break; case "edit": $listoftypestoshowpicto = explode(',', getDolGlobalString('MAIN_TYPES_TO_SHOW_PICTO', 'email,phone,ip,password')); @@ -10721,6 +10738,7 @@ abstract class CommonObject if (array_key_exists('user_modification_id', $fieldvalues) && !($fieldvalues['user_modification_id'] > 0)) { $fieldvalues['user_modification_id'] = $user->id; } + // @phan-suppress-next-line PhanUndeclaredProperty if (array_key_exists('pass_crypted', $fieldvalues) && property_exists($this, 'pass') && !empty($this->pass)) { // @phan-suppress-next-line PhanUndeclaredProperty $tmparray = dol_hash($this->pass, '0', 0, 1); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 6655346de96..f820a8467d5 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6278,7 +6278,7 @@ class Form * Show a form + html select a date * * @param string $page Page - * @param string $selected Date preselected + * @param int|'' $selected Date preselected * @param string $htmlname Html name of date input fields or 'none' * @param int $displayhour Display hour selector * @param int $displaymin Display minutes selector @@ -7215,10 +7215,10 @@ class Form * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) * - * @param integer|string $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). + * @param int|'' $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). * @param integer|string $set_time_end Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). * @param string $prefix Prefix for fields name - * @param int $empty 0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only + * @param int<0,2> $empty 0=Fields required, 1=Empty inputs are allowed, 2=Empty inputs are allowed for hours only * @param int $forcenewline Force new line between the 2 dates. * @return string Html for selectDate * @see form_date(), select_month(), select_year(), select_dayofweek() @@ -7242,7 +7242,7 @@ class Form * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) * - * @param integer|string $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). + * @param int|'' $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date with 00:00 hour (Parameter 'empty' must be 0 or 2). Using a "string date" is deprecated and excluded from the param type. * @param string $prefix Prefix for fields name * @param int $h 1 or 2=Show also hours (2=hours on a new line), -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 or 4 (4=hours on a new line)=Show hour always empty * @param int $m 1=Show also minutes, -1 has same effect but hour and minutes are prefilled with 23:59 if date is empty, 3 show minutes always empty @@ -7311,7 +7311,7 @@ class Form $shour = ''; $smin = ''; $ssec = ''; - if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', $set_time, $reg)) { // deprecated usage + if (!empty($set_time) && preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/', (string) $set_time, $reg)) { // deprecated usage // Date format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS' $syear = (!empty($reg[1]) ? $reg[1] : ''); $smonth = (!empty($reg[2]) ? $reg[2] : ''); diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php index 31370af5c2b..b1a7491d11e 100644 --- a/htdocs/core/class/html.formsetup.class.php +++ b/htdocs/core/class/html.formsetup.class.php @@ -1274,7 +1274,7 @@ class FormSetupItem $product = new Product($this->db); $resprod = $product->fetch((int) $this->fieldValue); if ($resprod > 0) { - $out .= $product->ref; + $out .= $product->getNomUrl(1, '', 0, -1, 0, '', 1); } elseif ($resprod < 0) { $this->setErrors($product->errors); } diff --git a/htdocs/core/class/timespent.class.php b/htdocs/core/class/timespent.class.php index fb79053c145..f863f849ddb 100644 --- a/htdocs/core/class/timespent.class.php +++ b/htdocs/core/class/timespent.class.php @@ -281,7 +281,8 @@ class TimeSpent extends CommonObject */ public function createFromClone(User $user, $fromid) { - global $langs, $extrafields; + global $extrafields; + $error = 0; dol_syslog(__METHOD__, LOG_DEBUG); @@ -296,16 +297,13 @@ class TimeSpent extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - // @phan-suppress-next-line PhanUndeclaredProperty - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/core/class/validate.class.php b/htdocs/core/class/validate.class.php index b0c986797a5..7854b3ee672 100644 --- a/htdocs/core/class/validate.class.php +++ b/htdocs/core/class/validate.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 @@ -34,7 +34,7 @@ class Validate public $db; /** - * @var Translate $outputLang + * @var Translate */ public $outputLang; @@ -247,8 +247,8 @@ class Validate /** * Check for boolean validity * - * @param boolean $bool Boolean to validate - * @return boolean Validity is ok or not + * @param mixed $bool Value to validate, may not be bool + * @return bool Validity is ok or not */ public function isBool($bool) { @@ -342,9 +342,9 @@ class Validate * Check for all values in db for an element * @see self::isFetchable() * - * @param integer $id of element - * @param string $element_type the element type - * @return boolean Validity is ok or not + * @param int $id Element Id + * @param string $element_type The element type + * @return bool Validity is ok or not * @throws Exception */ public function isFetchableElement($id, $element_type) diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php index 63847079776..1caa8d6dcdf 100644 --- a/htdocs/core/db/DoliDB.class.php +++ b/htdocs/core/db/DoliDB.class.php @@ -177,7 +177,8 @@ abstract class DoliDB implements Database * Sanitize a string for SQL forging * * @param string $stringtosanitize String to sanitize - * @param int $allowsimplequote 1=Allow simple quotes in string. When string is used as a list of SQL string ('aa', 'bb', ...) + * @param int $allowsimplequote 1=Allow simple quotes in string around val separated by "," but only when string is used as a list of SQL string "'aa', 'bb', 'cc', ..."). Can be used for IN ... + * 2=Allow all simple quotes. If you use this value, the return MUST be escaped to forge SQL strings. * @param int $allowsequals 1=Allow equals sign * @param int $allowsspace 1=Allow space char * @param int $allowschars 1=Allow a-z chars @@ -185,7 +186,25 @@ abstract class DoliDB implements Database */ public function sanitize($stringtosanitize, $allowsimplequote = 0, $allowsequals = 0, $allowsspace = 0, $allowschars = 1) { - return preg_replace('/[^0-9_\-\.,'.($allowschars ? 'a-z' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/i', '', $stringtosanitize); + $result = preg_replace('/[^0-9_\-\.,'.($allowschars ? '\p{L}' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/ui', '', $stringtosanitize); + //$result = preg_replace('/[^0-9_\-\.,'.($allowschars ? 'a-z' : '').($allowsequals ? '=' : '').($allowsimplequote ? "\'" : '').($allowsspace ? ' ' : '').']/i', '', $stringtosanitize); + + if ($allowsimplequote == 1) { + // Remove all quotes that are inside a string and not around + $tmpchars = explode(',', $result); + $newstringarray = array(); + foreach ($tmpchars as $tmpchar) { + $reg = array(); + if (preg_match('/^\'(.*)\'$/', $tmpchar, $reg)) { + $newstringarray[] = "'".str_replace("'", "", $reg[1])."'"; + } else { + $newstringarray[] = str_replace("'", "", $tmpchar); + } + } + $result = join(',', $newstringarray); + } + + return $result; } /** diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 371b4646ff2..25beda1136f 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -7380,10 +7380,10 @@ function get_localtax_by_third($local) * Get tax (VAT) main information from Id. * You can also call getLocalTaxesFromRate() after to get only localtax fields. * - * @param int|string $vatrate VAT ID or Rate. Value can be value or the string with code into parenthesis or rowid if $firstparamisid is 1. Example: '8.5' or '8.5 (8.5NPR)' or 123. - * @param Societe $buyer Company object - * @param Societe $seller Company object - * @param int<0,1> $firstparamisid 1 if first param is id into table (use this if you can) + * @param float|string $vatrate VAT ID or Rate. Value can be value or the string with code into parenthesis or rowid if $firstparamisid is 1. Example: '8.5' or '8.5 (8.5NPR)' or 123. + * @param ?Societe $buyer Company object + * @param ?Societe $seller Company object + * @param int<0,1> $firstparamisid 1 if first param is id into table (use this if you can) * @return array{}|array{rowid:int,code:string,rate:float,localtax1:float,localtax1_type:string,localtax2:float,localtax2_type:string,npr:float,accountancy_code_sell:string,accountancy_code_buy:string} array('rowid'=> , 'code'=> ...) * @see getLocalTaxesFromRate() */ @@ -7458,7 +7458,7 @@ function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid * Instead this function must be called when adding a line to get the array of possible values for localtax and type, and then * provide the selected value to the function calcul_price_total. * - * @param int|string $vatrate VAT ID or Rate+Code. Value can be value or the string with code into parenthesis or rowid if $firstparamisid is 1. Example: '8.5' or '8.5 (8.5NPR)' or 123. + * @param float|string $vatrate VAT ID or Rate+Code. Value can be value or the string with code into parenthesis or rowid if $firstparamisid is 1. Example: '8.5' or '8.5 (8.5NPR)' or 123. * @param int<0,2> $local Number of localtax (1 or 2, or 0 to return 1 & 2) * @param ?Societe $buyer Company object * @param ?Societe $seller Company object @@ -14424,7 +14424,7 @@ function dolForgeSQLCriteriaCallback($matches) $reg = array(); $tmpelem = trim($tmpelem); if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) { - $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1, 1))."'"; + $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 2, 1, 1, 1))."'"; } elseif (ctype_digit((string) $tmpelem)) { // if only 0-9 chars, no . $tmpelemarray[$tmpkey] = (int) $tmpelem; } elseif (is_numeric((string) $tmpelem)) { // it can be a float with a . diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 473f1a9511d..83809e1f850 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -7,8 +7,9 @@ * Copyright (C) 2018 Ferran Marcet * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2021 Gauthier VERDOL + * Copyright (C) 2022-2023 Solution Libre SAS * Copyright (C) 2024-2025 MDW - * Copyright (C) 2024 Alexandre Spangaro + * Copyright (C) 2024-2025 Alexandre Spangaro * * 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 @@ -1526,6 +1527,12 @@ function get_left_menu_billing($mainmenu, &$newmenu, $usemenuhider = 1, $leftmen } $newmenu->add("/compta/facture/stats/index.php?leftmenu=customers_bills_stats", $langs->trans("Statistics"), 1, $user->hasRight('facture', 'lire'), '', $mainmenu, 'customers_bills_stats'); + + // Categories + if (isModEnabled('category')) { + $langs->load("categories"); + $newmenu->add("/categories/index.php?leftmenu=cat&type=14", $langs->trans("Categories"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat'); + } } // Suppliers invoices diff --git a/htdocs/core/modules/commande/mod_commande_saphir.php b/htdocs/core/modules/commande/mod_commande_saphir.php index bb0603ef0f0..d408b1093f5 100644 --- a/htdocs/core/modules/commande/mod_commande_saphir.php +++ b/htdocs/core/modules/commande/mod_commande_saphir.php @@ -4,7 +4,7 @@ * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2008 Raphael Bertrand (Resultic) * 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 @@ -150,7 +150,7 @@ class mod_commande_saphir extends ModeleNumRefCommandes $date = dol_now(); } - $numFinal = get_next_value($db, $mask, 'commande', 'ref', '', $objsoc, $date, 'next', false, null, $entity); + $numFinal = get_next_value($db, $mask, 'commande', 'ref', '', $objsoc, (int) $date, 'next', false, null, $entity); return $numFinal; } diff --git a/htdocs/core/modules/expedition/doc/pdf_merou.modules.php b/htdocs/core/modules/expedition/doc/pdf_merou.modules.php index bdc5dacba98..9557bd9c403 100644 --- a/htdocs/core/modules/expedition/doc/pdf_merou.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_merou.modules.php @@ -633,7 +633,7 @@ class pdf_merou extends ModelePdfExpedition $label .= $object->tracking_url; } $pdf->SetFont('', 'B', $default_font_size - 3); - $pdf->writeHTMLCell(50, 8, '', '', $label, 0, 1, false, true, 'L'); + $pdf->writeHTMLCell(50, 8, null, null, $label, 0, 1, false, true, 'L'); } } } else { diff --git a/htdocs/core/modules/export/export_excel2007.modules.php b/htdocs/core/modules/export/export_excel2007.modules.php index bcfc547fd4f..583dd670a74 100644 --- a/htdocs/core/modules/export/export_excel2007.modules.php +++ b/htdocs/core/modules/export/export_excel2007.modules.php @@ -336,7 +336,7 @@ class ExportExcel2007 extends ModeleExports continue; } - $newvalue = !empty($objp->$alias) ? $objp->$alias : ''; + $newvalue = (!empty($objp->$alias) || (is_numeric($objp->$alias))) ? $objp->$alias : ''; $newvalue = $this->excel_clean($newvalue); $typefield = isset($array_types[$code]) ? $array_types[$code] : ''; diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index bdf3cd1c060..dee5ed32a72 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -1156,7 +1156,7 @@ class pdf_crabe extends ModelePDFFactures * @param Facture $object Object to show * @param float $posy Y * @param Translate $outputlangs Langs object - * @param Translate $outputlangsbis Object lang for output bis + * @param ?Translate $outputlangsbis Object lang for output bis * @return float Pos y */ protected function _tableau_info(&$pdf, $object, $posy, $outputlangs, $outputlangsbis) @@ -1336,7 +1336,7 @@ class pdf_crabe extends ModelePDFFactures if ($this->emetteur->country_code == 'FR') { if (getDolGlobalInt('TAX_MODE') == 1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); + $pdf->writeHTMLCell(80, 5, null, null, $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); $posy = $pdf->GetY() + 1; } @@ -1364,7 +1364,7 @@ class pdf_crabe extends ModelePDFFactures $linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' '.$outputlangs->transnoentities("ClickHere").''; $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell(80, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); + $pdf->writeHTMLCell(80, 5, null, null, dol_htmlentitiesbr($linktopay), 0, 1); $posy = $pdf->GetY() + 1; } @@ -1449,7 +1449,7 @@ class pdf_crabe extends ModelePDFFactures * @param float $deja_regle Amount already paid (in the currency of invoice) * @param float $posy Position depart * @param Translate $outputlangs Object langs - * @param Translate $outputlangsbis Object lang for output bis + * @param ?Translate $outputlangsbis Object lang for output bis * @return float Position pour suite */ protected function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs, $outputlangsbis) @@ -1642,13 +1642,13 @@ class pdf_crabe extends ModelePDFFactures $totalvat = $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code).(is_object($outputlangsbis) ? ' / '.$outputlangsbis->transcountrynoentities("TotalVAT", $mysoc->country_code) : ''); $totalvat .= ' '; if (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'rateonly') { - $totalvat .= vatrate($tvaval['vatrate'], true).$tvacompl; + $totalvat .= vatrate((string) $tvaval['vatrate'], true).$tvacompl; } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'codeonly') { $totalvat .= $tvaval['vatcode'].$tvacompl; } elseif (getDolGlobalString('PDF_VAT_LABEL_IS_CODE_OR_RATE') == 'nocodenorate') { $totalvat .= $tvacompl; } else { - $totalvat .= vatrate($tvaval['vatrate'], true).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl; + $totalvat .= vatrate((string) $tvaval['vatrate'], true).($tvaval['vatcode'] ? ' ('.$tvaval['vatcode'].')' : '').$tvacompl; } $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', true); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); diff --git a/htdocs/core/modules/facture/doc/pdf_octopus.modules.php b/htdocs/core/modules/facture/doc/pdf_octopus.modules.php index cf5e3aa55f2..115abe3d4f5 100644 --- a/htdocs/core/modules/facture/doc/pdf_octopus.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_octopus.modules.php @@ -1508,7 +1508,7 @@ class pdf_octopus extends ModelePDFFactures if ($this->emetteur->country_code == 'FR') { if (getDolGlobalInt('TAX_MODE') == 1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); + $pdf->writeHTMLCell(80, 5, null, null, $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); $posy = $pdf->GetY() + 1; } @@ -1548,7 +1548,7 @@ class pdf_octopus extends ModelePDFFactures $linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' '.$outputlangs->transnoentities("ClickHere").''; $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell($posxend - $this->marge_gauche, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); + $pdf->writeHTMLCell($posxend - $this->marge_gauche, 5, null, null, dol_htmlentitiesbr($linktopay), 0, 1); $posy = $pdf->GetY() + 1; } diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index c93c91d4ae9..31d8089f63e 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -1438,7 +1438,7 @@ class pdf_sponge extends ModelePDFFactures if ($this->emetteur->country_code == 'FR') { if (getDolGlobalInt('TAX_MODE') == 1) { $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell(80, 5, '', '', $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); + $pdf->writeHTMLCell(80, 5, null, null, $outputlangs->transnoentities("MentionVATDebitOptionIsOn"), 0, 1); $posy = $pdf->GetY() + 1; } @@ -1466,7 +1466,7 @@ class pdf_sponge extends ModelePDFFactures $linktopay = $langs->trans("ToOfferALinkForOnlinePayment", $servicename).' '.$outputlangs->transnoentities("ClickHere").''; $pdf->SetXY($this->marge_gauche, $posy); - $pdf->writeHTMLCell($posxend - $this->marge_gauche, 5, '', '', dol_htmlentitiesbr($linktopay), 0, 1); + $pdf->writeHTMLCell($posxend - $this->marge_gauche, 5, null, null, dol_htmlentitiesbr($linktopay), 0, 1); $posy = $pdf->GetY() + 1; } diff --git a/htdocs/core/modules/modCategorie.class.php b/htdocs/core/modules/modCategorie.class.php index 767e37c6b26..6a431545860 100644 --- a/htdocs/core/modules/modCategorie.class.php +++ b/htdocs/core/modules/modCategorie.class.php @@ -1,11 +1,11 @@ - * Copyright (C) 2005-2014 Laurent Destailleur - * Copyright (C) 2012-2016 Juanjo Menent - * Copyright (C) 2020 Stéphane Lesage - * Copyright (C) 2024 MDW - * Copyright (C) 2025 Frédéric France - * Copyright (C) 2022-2023 Solution Libre SAS +/* Copyright (C) 2005 Matthieu Valleton + * Copyright (C) 2005-2014 Laurent Destailleur + * Copyright (C) 2012-2016 Juanjo Menent + * Copyright (C) 2020 Stéphane Lesage + * Copyright (C) 2022-2023 Solution Libre SAS + * Copyright (C) 2024 MDW + * Copyright (C) 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 @@ -170,6 +170,9 @@ class modCategorie extends DolibarrModules if (isModEnabled('order')) { $typeexample .= ($typeexample ? " / " : "")."16=Order"; } + if (isModEnabled('invoice')) { + $typeexample .= ($typeexample ? " / " : "")."17=Invoice"; + } // Definition of vars $this->export_fields_array[$r] = array('cat.rowid' => "CategId", 'cat.label' => "Label", 'cat.type' => "Type", 'cat.description' => "Description", 'cat.fk_parent' => "ParentCategoryID", 'pcat.label' => "ParentCategoryLabel", 'cat.color' => "Color", 'cat.date_creation' => "DateCreation", 'cat.tms' => "DateLastModification"); @@ -492,6 +495,24 @@ class modCategorie extends DolibarrModules ); } + // 17 Invoice + if (isModEnabled("invoice")) { + ++$r; + $this->exportTagLinks( + $r, + 'invoice', + 'Facture', + 'isModEnabled("invoice")', + ['facture', 'facture', 'export'], + [ + 'rowid' => [ + 'name' => 'InvoiceID', + 'type' => 'Numeric' + ] + ] + ); + } + // Imports //-------- @@ -509,7 +530,7 @@ class modCategorie extends DolibarrModules 'ca.label' => "Label*", 'ca.type' => "Type*", 'ca.description' => "Description", 'ca.fk_parent' => 'ParentCategory' ); - $this->import_regex_array[$r] = array('ca.type' => '^(0|1|2|3|4|5|6|7|8|9|10|11|16)$'); + $this->import_regex_array[$r] = array('ca.type' => '^(0|1|2|3|4|5|6|7|8|9|10|11|16|17)$'); $this->import_convertvalue_array[$r] = array( 'ca.fk_parent' => array( 'rule' => 'fetchidfromcodeandlabel', @@ -691,6 +712,18 @@ class modCategorie extends DolibarrModules 'Commande' ); } + + // 17 Invoice + if (isModEnabled("invoice")) { + ++$r; + $this->importTagLinks( + $r, + 'invoice', + '/compta/facture/class/facture.class.php', + 'Facture', + 'Facture' + ); + } } /** diff --git a/htdocs/core/modules/modSociete.class.php b/htdocs/core/modules/modSociete.class.php index 47652e94d1d..45799c1ff6e 100644 --- a/htdocs/core/modules/modSociete.class.php +++ b/htdocs/core/modules/modSociete.class.php @@ -6,7 +6,7 @@ * Copyright (C) 2005-2013 Regis Houssin * Copyright (C) 2012-2014 Juanjo Menent * Copyright (C) 2022 Ferran Marcet - * 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 @@ -983,7 +983,7 @@ class modSociete extends DolibarrModules 'sr.datec' => 'date used for creating direct debit UMR formatted as '.dol_print_date( dol_now(), '%Y-%m-%d' - ), + ), 'sr.bank' => 'bank name eg: "ING-Direct"', 'sr.code_banque' => 'account sort code (GB)/Routing number (US) eg. "8456"', 'sr.code_guichet' => "bank code for office/branch", diff --git a/htdocs/don/class/api_donations.class.php b/htdocs/don/class/api_donations.class.php index 4570fda0bf5..6b7ad5b0444 100644 --- a/htdocs/don/class/api_donations.class.php +++ b/htdocs/don/class/api_donations.class.php @@ -30,7 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php'; class Donations extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'amount' @@ -96,6 +96,8 @@ class Donations extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of order objects + * @phan-return Don[]|array{data:Don[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Don[]|array{data:Don[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException */ diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index 0bd44eceb31..97af81682a9 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -118,7 +118,7 @@ class EcmFiles extends CommonObject public $gen_or_uploaded; /** - * @var string extraparams + * @var array|string Extra parameters. Try to store here the array of parameters. Old code is sometimes storing a string. */ public $extraparams; @@ -250,9 +250,6 @@ class EcmFiles extends CommonObject if (isset($this->gen_or_uploaded)) { $this->gen_or_uploaded = trim($this->gen_or_uploaded); } - if (isset($this->extraparams)) { - $this->extraparams = trim($this->extraparams); - } if (isset($this->fk_user_c)) { $this->fk_user_c = (int) $this->fk_user_c; } @@ -305,6 +302,10 @@ class EcmFiles extends CommonObject if (!isset($this->entity)) { $this->entity = $conf->entity; } + + $extraparams = (!empty($this->extraparams) ? json_encode($this->extraparams) : null); + $extraparams = dol_trunc($extraparams, 250); + // Put here code to add control on parameters values // Insert request @@ -348,7 +349,7 @@ class EcmFiles extends CommonObject $sql .= ' '.(!isset($this->cover) ? 'NULL' : "'".$this->db->escape($this->cover)."'").','; $sql .= ' '.((int) $maxposition).','; $sql .= ' '.(!isset($this->gen_or_uploaded) ? 'NULL' : "'".$this->db->escape($this->gen_or_uploaded)."'").','; - $sql .= ' '.(!isset($this->extraparams) ? 'NULL' : "'".$this->db->escape($this->extraparams)."'").','; + $sql .= ' '.(!isset($extraparams) ? 'NULL' : "'".$this->db->escape($extraparams)."'").','; $sql .= " '".$this->db->idate($this->date_c)."',"; $sql .= ' '.(!isset($this->date_m) || dol_strlen((string) $this->date_m) == 0 ? 'NULL' : "'".$this->db->idate($this->date_m)."'").','; $sql .= ' '.(!isset($this->fk_user_c) ? $user->id : $this->fk_user_c).','; diff --git a/htdocs/eventorganization/class/conferenceorboothattendee.class.php b/htdocs/eventorganization/class/conferenceorboothattendee.class.php index 77357da66d6..f83e2bd845b 100644 --- a/htdocs/eventorganization/class/conferenceorboothattendee.class.php +++ b/htdocs/eventorganization/class/conferenceorboothattendee.class.php @@ -352,6 +352,7 @@ class ConferenceOrBoothAttendee extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields @@ -359,9 +360,6 @@ class ConferenceOrBoothAttendee extends CommonObject // @phan-suppress-next-line PhanTypeInvalidDimOffset $object->ref = empty($this->fields['ref']['default']) ? "(PROV)" : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/fourn/class/api_supplier_invoices.class.php b/htdocs/fourn/class/api_supplier_invoices.class.php index 4dbb43115be..080805676cc 100644 --- a/htdocs/fourn/class/api_supplier_invoices.class.php +++ b/htdocs/fourn/class/api_supplier_invoices.class.php @@ -103,6 +103,8 @@ class SupplierInvoices extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of invoice objects + * @phan-return FactureFournisseur[]|array{data:FactureFournisseur[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return FactureFournisseur[]|array{data:FactureFournisseur[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException */ @@ -406,6 +408,8 @@ class SupplierInvoices extends DolibarrApi * @url GET {id}/payments * * @return array + * @phan-return array + * @phpstan-return array * @throws RestException 400 * @throws RestException 403 * @throws RestException 404 @@ -548,6 +552,8 @@ class SupplierInvoices extends DolibarrApi * @url GET {id}/lines * * @return array + * @phan-return CommonInvoiceLine[] + * @phpstan-return CommonInvoiceLine[] * * @throws RestException 403 * @throws RestException 404 @@ -629,7 +635,7 @@ class SupplierInvoices extends DolibarrApi $request_data->price_base_type ? $request_data->price_base_type : 'HT', $request_data->product_type, $request_data->rang, - false, + 0, $request_data->array_options, $request_data->fk_unit, $request_data->origin_id, @@ -695,7 +701,7 @@ class SupplierInvoices extends DolibarrApi $request_data->info_bits, $request_data->product_type, $request_data->remise_percent, - false, + 0, $request_data->date_start, $request_data->date_end, $request_data->array_options, diff --git a/htdocs/fourn/class/api_supplier_orders.class.php b/htdocs/fourn/class/api_supplier_orders.class.php index 06bf957bf1f..b77c5c28e7c 100644 --- a/htdocs/fourn/class/api_supplier_orders.class.php +++ b/htdocs/fourn/class/api_supplier_orders.class.php @@ -30,7 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; class SupplierOrders extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid' diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 2e80ecacfc7..62e28a0e3ec 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -3682,6 +3682,7 @@ class FactureFournisseur extends CommonInvoice $actioncomm->errors_to = $errors_to; $actioncomm->elementtype = 'invoice_supplier'; + $actioncomm->elementid = $tmpinvoice->id; $actioncomm->fk_element = $tmpinvoice->id; //$actioncomm->extraparams = $extraparams; diff --git a/htdocs/hrm/class/evaluationdet.class.php b/htdocs/hrm/class/evaluationdet.class.php index 10e55284fba..ad3ab437bdb 100644 --- a/htdocs/hrm/class/evaluationdet.class.php +++ b/htdocs/hrm/class/evaluationdet.class.php @@ -276,15 +276,13 @@ class EvaluationLine extends CommonObjectLine // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/hrm/class/position.class.php b/htdocs/hrm/class/position.class.php index 427f47f2e26..194b836f2a2 100644 --- a/htdocs/hrm/class/position.class.php +++ b/htdocs/hrm/class/position.class.php @@ -293,15 +293,13 @@ class Position extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_ceation_id); unset($object->import_key); // Clear fields if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_" . $object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf") . " " . $object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/hrm/class/skill.class.php b/htdocs/hrm/class/skill.class.php index f4adc185f7b..bec9e3b5999 100644 --- a/htdocs/hrm/class/skill.class.php +++ b/htdocs/hrm/class/skill.class.php @@ -344,6 +344,7 @@ class Skill extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields diff --git a/htdocs/hrm/class/skilldet.class.php b/htdocs/hrm/class/skilldet.class.php index c5d9f1dc155..f42001024b5 100644 --- a/htdocs/hrm/class/skilldet.class.php +++ b/htdocs/hrm/class/skilldet.class.php @@ -265,15 +265,13 @@ class Skilldet extends CommonObjectLine // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/hrm/class/skillrank.class.php b/htdocs/hrm/class/skillrank.class.php index 34fb53116c6..e70775cd7ca 100644 --- a/htdocs/hrm/class/skillrank.class.php +++ b/htdocs/hrm/class/skillrank.class.php @@ -279,6 +279,7 @@ class SkillRank extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); if (!empty($fk_object) && $fk_object > 0) { unset($object->fk_object); @@ -289,9 +290,6 @@ class SkillRank extends CommonObject if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/install/mysql/migration/20.0.0-21.0.0.sql b/htdocs/install/mysql/migration/20.0.0-21.0.0.sql index c78ea491447..92278188bd7 100644 --- a/htdocs/install/mysql/migration/20.0.0-21.0.0.sql +++ b/htdocs/install/mysql/migration/20.0.0-21.0.0.sql @@ -260,15 +260,8 @@ LEFT JOIN llx_categorie WHERE llx_categorie.rowid IS NULL; -- Update llx_category_bankline with the new rowid from llx_categorie -UPDATE llx_category_bankline AS bl -INNER JOIN llx_category_bank AS b - ON bl.fk_categ = b.rowid -INNER JOIN llx_categorie AS c - ON b.label = c.label - AND b.entity = c.entity - AND c.type = 8 -SET bl.fk_categ = c.rowid -WHERE c.rowid IS NOT NULL; +-- VMYSQL4.3 UPDATE llx_category_bankline AS bl INNER JOIN llx_category_bank AS b ON bl.fk_categ = b.rowid INNER JOIN llx_categorie AS c ON b.label = c.label AND b.entity = c.entity AND c.type = 8 SET bl.fk_categ = c.rowid WHERE c.rowid IS NOT NULL; +-- VPGSQL8.2 UPDATE llx_category_bankline AS bl SET fk_categ = c.rowid FROM llx_category_bank AS b INNER JOIN llx_categorie AS c ON b.label = c.label AND b.entity IS NOT NULL AND c.type = 8 WHERE bl.fk_categ = b.rowid AND c.rowid IS NOT NULL; INSERT INTO llx_categorie (entity, fk_parent, label, type, description, color, position, visible, date_creation) SELECT @@ -289,15 +282,9 @@ LEFT JOIN llx_categorie WHERE llx_categorie.rowid IS NULL; -- Update llx_category_bankline with the new rowid from llx_categorie -UPDATE llx_category_bankline AS bl -INNER JOIN llx_bank_categ AS b - ON bl.fk_categ = b.rowid -INNER JOIN llx_categorie AS c - ON b.label = c.label - AND b.entity = c.entity - AND c.type = 8 -SET bl.fk_categ = c.rowid -WHERE c.rowid IS NOT NULL; +-- VMYSQL4.3 UPDATE llx_category_bankline AS bl INNER JOIN llx_bank_categ AS b ON bl.fk_categ = b.rowid INNER JOIN llx_categorie AS c ON b.label = c.label AND b.entity = c.entity AND c.type = 8 SET bl.fk_categ = c.rowid WHERE c.rowid IS NOT NULL; +-- VPGSQL8.2 UPDATE llx_category_bankline AS bl SET fk_categ = c.rowid FROM llx_bank_categ AS b INNER JOIN llx_categorie AS c ON b.label = c.label AND b.entity IS NOT NULL AND c.type = 8 WHERE bl.fk_categ = b.rowid AND c.rowid IS NOT NULL; + -- Accounting - Add personalized multi-report create table llx_c_accounting_report diff --git a/htdocs/knowledgemanagement/class/api_knowledgemanagement.class.php b/htdocs/knowledgemanagement/class/api_knowledgemanagement.class.php index a46e075634b..1f789d19b54 100644 --- a/htdocs/knowledgemanagement/class/api_knowledgemanagement.class.php +++ b/htdocs/knowledgemanagement/class/api_knowledgemanagement.class.php @@ -130,6 +130,8 @@ class KnowledgeManagement extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of order objects + * @phan-return KnowledgeRecord[]|array{data:KnowledgeRecord[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return KnowledgeRecord[]|array{data:KnowledgeRecord[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException * @@ -328,7 +330,7 @@ class KnowledgeManagement extends DolibarrApi // Clean data // $this->knowledgerecord->abc = sanitizeVal($this->knowledgerecord->abc, 'alphanohtml'); - if ($this->knowledgerecord->update(DolibarrApiAccess::$user, false) > 0) { + if ($this->knowledgerecord->update(DolibarrApiAccess::$user, 0) > 0) { return $this->get($id); } else { throw new RestException(500, $this->knowledgerecord->error); diff --git a/htdocs/langs/en_US/categories.lang b/htdocs/langs/en_US/categories.lang index bb369a1dea8..d5a1d27cf16 100644 --- a/htdocs/langs/en_US/categories.lang +++ b/htdocs/langs/en_US/categories.lang @@ -79,6 +79,7 @@ CatContactList=List of contacts tags/categories CatProjectsList=List of projects tags/categories CatUsersList=List of users tags/categories CatOrdersLinks=Links between orders and tags/categories +CatInvoicesLinks=Links between invoices and tags/categories CatSupLinks=Links between vendors and tags/categories CatCusLinks=Links between customers/prospects and tags/categories CatContactsLinks=Links between contacts/addresses and tags/categories @@ -96,6 +97,7 @@ AddCustomerIntoCategory=Assign the category to the customer AddSupplierIntoCategory=Assign the category to the supplier AddFichinterIntoCategory=Assign the category to the intervention AddOrderIntoCategory=Assign the category to the order +AddInvoiceIntoCategory=Assign the category to the invoice AssignCategoryTo=Assign the category to ShowCategory=Show tag/category ByDefaultInList=By default in list diff --git a/htdocs/multicurrency/class/api_multicurrencies.class.php b/htdocs/multicurrency/class/api_multicurrencies.class.php index c9437431d10..03c1df80d15 100644 --- a/htdocs/multicurrency/class/api_multicurrencies.class.php +++ b/htdocs/multicurrency/class/api_multicurrencies.class.php @@ -51,6 +51,8 @@ class MultiCurrencies extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.product_id:=:1) and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of warehouse objects + * @phan-return MultiCurrency[] + * @phpstan-return MultiCurrency[] * * @throws RestException */ @@ -234,7 +236,7 @@ class MultiCurrencies extends DolibarrApi // Add default rate if defined if (isset($request_data['rate']) && $request_data['rate'] > 0) { - if ($multicurrency->addRate($request_data['rate']) < 0) { + if ($multicurrency->addRate((float) $request_data['rate']) < 0) { throw new RestException(500, "Error adding currency rate", array_merge(array($multicurrency->error), $multicurrency->errors)); } @@ -349,7 +351,7 @@ class MultiCurrencies extends DolibarrApi } // Add rate - if ($multicurrency->addRate($request_data['rate']) < 0) { + if ($multicurrency->addRate((float) $request_data['rate']) < 0) { throw new RestException(500, "Error updating currency rate", array_merge(array($multicurrency->error), $multicurrency->errors)); } diff --git a/htdocs/partnership/class/api_partnerships.class.php b/htdocs/partnership/class/api_partnerships.class.php index 6be059f25f9..34078bf00a6 100644 --- a/htdocs/partnership/class/api_partnerships.class.php +++ b/htdocs/partnership/class/api_partnerships.class.php @@ -97,6 +97,8 @@ class Partnerships extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of order objects + * @phan-return Partnership[] + * @phpstan-return Partnership[] * * @throws RestException * @@ -266,7 +268,7 @@ class Partnerships extends DolibarrApi // Clean data // $this->partnership->abc = sanitizeVal($this->partnership->abc, 'alphanohtml'); - if ($this->partnership->update(DolibarrApiAccess::$user, false) > 0) { + if ($this->partnership->update(DolibarrApiAccess::$user, 0) > 0) { return $this->get($id); } else { throw new RestException(500, $this->partnership->error); diff --git a/htdocs/partnership/class/partnership.class.php b/htdocs/partnership/class/partnership.class.php index 6593b6e40b2..666cda46456 100644 --- a/htdocs/partnership/class/partnership.class.php +++ b/htdocs/partnership/class/partnership.class.php @@ -307,6 +307,7 @@ class Partnership extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields @@ -314,9 +315,6 @@ class Partnership extends CommonObject // @phan-suppress-next-line PhanTypeMismatchProperty $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index ce9d7803292..746ad2d6a24 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -37,7 +37,7 @@ require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination2ValuePair.cla class Products extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'ref', @@ -177,6 +177,8 @@ class Products extends DolibarrApi * @param int $includestockdata Load also information about stock (slower) * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of product objects + * @phan-return Product[]|array{data:Product[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Product[]|array{data:Product[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.ref", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false, $includestockdata = 0, $properties = '') { @@ -564,6 +566,8 @@ class Products extends DolibarrApi * * @param int $id Id of parent product/service * @return array + * @phan-return array + * @phpstan-return array * * @throws RestException * @throws RestException 401 @@ -764,9 +768,9 @@ class Products extends DolibarrApi require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php'; $prodcustprice = new ProductCustomerPrice($this->db); $filter = array(); - $filter['t.fk_product'] = $id; + $filter['t.fk_product'] = (string) $id; if ($thirdparty_id) { - $filter['t.fk_soc'] = $thirdparty_id; + $filter['t.fk_soc'] = (string) $thirdparty_id; } $result = $prodcustprice->fetchAll('', '', 0, 0, $filter); } @@ -940,6 +944,8 @@ class Products extends DolibarrApi * @param int $supplier Use this param to filter list by supplier * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.tobuy:=:0) and (t.tosell:=:1)" * @return array Array of product objects + * @phan-return array + * @phpstan-return array * * @url GET purchase_prices */ @@ -1043,7 +1049,9 @@ class Products extends DolibarrApi * @param string $ref Ref of element * @param string $ref_ext Ref ext of element * @param string $barcode Barcode of element - * @return array|mixed Data without useless information + * @return array Data without useless information + * @phan-return ProductFournisseur[] + * @phpstan-return ProductFournisseur[] * * @url GET {id}/purchase_prices * @@ -1098,6 +1106,8 @@ class Products extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:color)" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array + * @phan-return ProductAttribute[] + * @phpstan-return ProductAttribute[] * * @throws RestException 401 * @throws RestException 404 @@ -1204,6 +1214,8 @@ class Products extends DolibarrApi * * @param string $ref Reference of Attribute * @return array + * @phan-return array{id:int,ref:string,ref_ext:string,label:string,rang:int,position:int,entity:string,is_used_by_products:int} + * @phpstan-return array{id:int,ref:string,ref_ext:string,label:string,rang:int,position:int,entity:string,is_used_by_products:int} * * @throws RestException 401 * @throws RestException 404 @@ -1229,13 +1241,13 @@ class Products extends DolibarrApi $result = $this->db->fetch_object($query); $attr = array(); - $attr['id'] = $result->rowid; - $attr['ref'] = $result->ref; - $attr['ref_ext'] = $result->ref_ext; - $attr['label'] = $result->label; - $attr['rang'] = $result->position; - $attr['position'] = $result->position; - $attr['entity'] = $result->entity; + $attr['id'] = (int) $result->rowid; + $attr['ref'] = (string) $result->ref; + $attr['ref_ext'] = (string) $result->ref_ext; + $attr['label'] = (string) $result->label; + $attr['rang'] = (int) $result->position; + $attr['position'] = (int) $result->position; + $attr['entity'] = (string) $result->entity; $sql = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."product_attribute_combination2val as pac2v"; $sql .= " JOIN ".$this->db->prefix()."product_attribute_combination as pac ON pac2v.fk_prod_combination = pac.rowid"; @@ -1254,6 +1266,8 @@ class Products extends DolibarrApi * * @param string $ref_ext External reference of Attribute * @return array + * @phan-return array{id:int,ref:string,ref_ext:string,label:string,rang:int,position:int,entity:string,is_used_by_products:int} + * @phpstan-return array{id:int,ref:string,ref_ext:string,label:string,rang:int,position:int,entity:string,is_used_by_products:int} * * @throws RestException 500 System error * @throws RestException 401 @@ -1279,13 +1293,13 @@ class Products extends DolibarrApi $result = $this->db->fetch_object($query); $attr = array(); - $attr['id'] = $result->rowid; - $attr['ref'] = $result->ref; - $attr['ref_ext'] = $result->ref_ext; - $attr['label'] = $result->label; - $attr['rang'] = $result->position; - $attr['position'] = $result->position; - $attr['entity'] = $result->entity; + $attr['id'] = (int) $result->rowid; + $attr['ref'] = (string) $result->ref; + $attr['ref_ext'] = (string) $result->ref_ext; + $attr['label'] = (string) $result->label; + $attr['rang'] = (int) $result->position; + $attr['position'] = (int) $result->position; + $attr['entity'] = (string) $result->entity; $sql = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."product_attribute_combination2val as pac2v"; $sql .= " JOIN ".$this->db->prefix()."product_attribute_combination as pac ON pac2v.fk_prod_combination = pac.rowid"; @@ -1420,6 +1434,8 @@ class Products extends DolibarrApi * * @param int $id ID of Attribute value * @return array + * @phan-return array{id:int,fk_product_attribute:int,ref:string,value:string} + * @phpstan-return array{id:int,fk_product_attribute:int,ref:string,value:string} * * @throws RestException 500 System error * @throws RestException 401 @@ -1447,8 +1463,8 @@ class Products extends DolibarrApi $result = $this->db->fetch_object($query); $attrval = array(); - $attrval['id'] = $result->rowid; - $attrval['fk_product_attribute'] = $result->fk_product_attribute; + $attrval['id'] = (int) $result->rowid; + $attrval['fk_product_attribute'] = (int) $result->fk_product_attribute; $attrval['ref'] = $result->ref; $attrval['value'] = $result->value; @@ -1461,6 +1477,8 @@ class Products extends DolibarrApi * @param int $id ID of Attribute value * @param string $ref Ref of Attribute value * @return array + * @phan-return array{id:int,fk_product_attribute:int,ref:string,value:string} + * @phpstan-return array{id:int,fk_product_attribute:int,ref:string,value:string} * * @throws RestException 500 System error * @throws RestException 401 @@ -1491,11 +1509,10 @@ class Products extends DolibarrApi $result = $this->db->fetch_object($query); $attrval = array(); - $attrval['id'] = $result->rowid; - $attrval['fk_product_attribute'] = $result->fk_product_attribute; + $attrval['id'] = (int) $result->rowid; + $attrval['fk_product_attribute'] = (int) $result->fk_product_attribute; $attrval['ref'] = $result->ref; $attrval['value'] = $result->value; - return $attrval; } @@ -1547,6 +1564,8 @@ class Products extends DolibarrApi * * @param int $id ID of an Attribute * @return array + * @phan-return ProductAttributeValue[] + * @phpstan-return ProductAttributeValue[] * * @throws RestException 401 * @throws RestException 500 System error @@ -1579,6 +1598,8 @@ class Products extends DolibarrApi * * @param string $ref Ref of an Attribute * @return array + * @phan-return ProductAttributeValue[] + * @phpstan-return ProductAttributeValue[] * * @throws RestException 401 * @@ -1734,6 +1755,8 @@ class Products extends DolibarrApi * @param int $id ID of Product * @param int $includestock Default value 0. If parameter is set to 1 the response will contain stock data of each variant * @return array + * @phan-return ProductCombination[] + * @phpstan-return ProductCombination[] * * @throws RestException 500 System error * @throws RestException 401 @@ -1757,7 +1780,7 @@ class Products extends DolibarrApi if (!empty($includestock) && DolibarrApiAccess::$user->hasRight('stock', 'lire')) { $productModel = new Product($this->db); $productModel->fetch((int) $combination->fk_product_child); - $productModel->load_stock($includestock); + $productModel->load_stock((string) $includestock); $combinations[$key]->stock_warehouse = $this->_cleanObjectDatas($productModel)->stock_warehouse; } } @@ -1770,6 +1793,8 @@ class Products extends DolibarrApi * * @param string $ref Ref of Product * @return array + * @phan-return ProductCombination[] + * @phpstan-return ProductCombination[] * * @throws RestException 500 System error * @throws RestException 401 @@ -1840,6 +1865,7 @@ class Products extends DolibarrApi $prodattr = new ProductAttribute($this->db); $prodattr_val = new ProductAttributeValue($this->db); + $cleanedFeatures = array(); foreach ($features as $id_attr => $id_value) { if ($prodattr->fetch((int) $id_attr) < 0) { throw new RestException(400, 'Invalid attribute ID: '.$id_attr); @@ -1847,6 +1873,7 @@ class Products extends DolibarrApi if ($prodattr_val->fetch((int) $id_value) < 0) { throw new RestException(400, 'Invalid attribute value ID: '.$id_value); } + $cleanedFeatures[(int) $id_attr] = (int) $id_value; } $result = $this->product->fetch((int) $id); @@ -1856,7 +1883,7 @@ class Products extends DolibarrApi $prodcomb = new ProductCombination($this->db); - $result = $prodcomb->createProductCombination(DolibarrApiAccess::$user, $this->product, $features, array(), $price_impact_is_percent, $price_impact, $weight_impact, $reference, $ref_ext); + $result = $prodcomb->createProductCombination(DolibarrApiAccess::$user, $this->product, $cleanedFeatures, array(), $price_impact_is_percent, (is_numeric($price_impact) ? (float) $price_impact : false), (is_numeric($weight_impact) ? (float) $weight_impact : false), $reference, $ref_ext); if ($result > 0) { return $result; } else { @@ -1899,6 +1926,7 @@ class Products extends DolibarrApi $prodattr = new ProductAttribute($this->db); $prodattr_val = new ProductAttributeValue($this->db); + $cleanedFeatures = []; foreach ($features as $id_attr => $id_value) { if ($prodattr->fetch((int) $id_attr) < 0) { throw new RestException(404); @@ -1906,6 +1934,7 @@ class Products extends DolibarrApi if ($prodattr_val->fetch((int) $id_value) < 0) { throw new RestException(404); } + $cleanedFeatures[(int) $id_attr] = (int) $id_value; } $result = $this->product->fetch(0, trim($ref)); @@ -1914,8 +1943,8 @@ class Products extends DolibarrApi } $prodcomb = new ProductCombination($this->db); - if (!$prodcomb->fetchByProductCombination2ValuePairs($this->product->id, $features)) { - $result = $prodcomb->createProductCombination(DolibarrApiAccess::$user, $this->product, $features, array(), $price_impact_is_percent, $price_impact, $weight_impact); + if (!$prodcomb->fetchByProductCombination2ValuePairs($this->product->id, $cleanedFeatures)) { + $result = $prodcomb->createProductCombination(DolibarrApiAccess::$user, $this->product, $cleanedFeatures, array(), $price_impact_is_percent, (is_numeric($price_impact) ? (float) $price_impact : false), (is_numeric($weight_impact) ? (float) $weight_impact : false)); if ($result > 0) { return $result; } else { @@ -2040,10 +2069,14 @@ class Products extends DolibarrApi // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** - * Clean sensible object datas + * Clean sensitive object data + * @phpstan-template T of Object * * @param Object $object Object to clean * @return Object Object with cleaned properties + * + * @phpstan-param T $object + * @phpstan-return T */ protected function _cleanObjectDatas($object) { @@ -2168,7 +2201,7 @@ class Products extends DolibarrApi } if (!empty($includestockdata) && DolibarrApiAccess::$user->hasRight('stock', 'lire')) { - $this->product->load_stock($includestockdata); + $this->product->load_stock((string) $includestockdata); if (is_array($this->product->stock_warehouse)) { foreach ($this->product->stock_warehouse as $keytmp => $valtmp) { diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 88ab82da615..cf3bf8360e2 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1121,6 +1121,7 @@ class Product extends CommonObject $sql .= ", batch_mask"; $sql .= ", fk_unit"; $sql .= ", mandatory_period"; + if (!empty($this->default_vat_code)) $sql.=", default_vat_code"; $sql .= ") VALUES ("; $sql .= "'".$this->db->idate($this->date_creation)."'"; $sql .= ", ".(!empty($this->entity) ? (int) $this->entity : (int) $conf->entity); @@ -1152,8 +1153,8 @@ class Product extends CommonObject $sql .= ", '".$this->db->escape($this->batch_mask)."'"; $sql .= ", ".($this->fk_unit > 0 ? ((int) $this->fk_unit) : 'NULL'); $sql .= ", '".$this->db->escape((string) $this->mandatory_period)."'"; + if (!empty($this->default_vat_code)) $sql.=", '".$this->db->escape($this->default_vat_code)."'"; $sql .= ")"; - dol_syslog(get_class($this)."::Create", LOG_DEBUG); $result = $this->db->query($sql); diff --git a/htdocs/product/class/productfournisseurprice.class.php b/htdocs/product/class/productfournisseurprice.class.php index 5f8372f6c83..a2f627acd75 100644 --- a/htdocs/product/class/productfournisseurprice.class.php +++ b/htdocs/product/class/productfournisseurprice.class.php @@ -328,15 +328,16 @@ class ProductFournisseurPrice extends CommonObject // Reset some properties unset($object->id); unset($object->fk_user_creat); + unset($object->user_creation_id); unset($object->import_key); // Clear fields if (property_exists($object, 'ref')) { $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { + /*if (property_exists($object, 'label')) { $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } + }*/ if (property_exists($object, 'status')) { $object->status = self::STATUS_DRAFT; } diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 1e9c33b7bc9..c41ffb416d8 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -660,7 +660,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; $parameters = array(); $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $object, $action); // Note that $action and $object may have been modified by hook $sql .= $hookmanager->resPrint; -$sql .= " GROUP BY p.rowid, p.ref, p.description, p.label, p.barcode, p.price, p.tva_tx, p.price_ttc, p.price_base_type,"; +$sql .= " GROUP BY p.rowid, p.ref, p.ref_ext, p.description, p.label, p.barcode, p.price, p.tva_tx, p.price_ttc, p.price_base_type,"; $sql .= " p.fk_product_type, p.duration, p.finished, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,"; $sql .= ' p.datec, p.tms, p.entity, p.tobatch, p.pmp, p.cost_price, p.stock,'; if (!getDolGlobalString('MAIN_PRODUCT_PERENTITY_SHARED')) { diff --git a/htdocs/product/stock/class/api_stockmovements.class.php b/htdocs/product/stock/class/api_stockmovements.class.php index 2a51192218b..7d611017be6 100644 --- a/htdocs/product/stock/class/api_stockmovements.class.php +++ b/htdocs/product/stock/class/api_stockmovements.class.php @@ -30,7 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; class StockMovements extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'product_id', @@ -92,6 +92,8 @@ class StockMovements extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.product_id:=:1) and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of warehouse objects + * @phan-return MouvementStock[] + * @phpstan-return MouvementStock[] * * @throws RestException */ @@ -198,7 +200,7 @@ class StockMovements extends DolibarrApi $dateMvt = empty($datem) ? '' : dol_stringtotime($datem); $this->stockmovement->setOrigin($origin_type, $origin_id); - if ($this->stockmovement->_create(DolibarrApiAccess::$user, $product_id, $warehouse_id, $qty, $type, $price, $movementlabel, $movementcode, $dateMvt, $eatBy, $sellBy, $lot) <= 0) { + if ($this->stockmovement->_create(DolibarrApiAccess::$user, $product_id, $warehouse_id, $qty, $type, (float) $price, $movementlabel, $movementcode, $dateMvt, $eatBy, $sellBy, $lot) <= 0) { $errormessage = $this->stockmovement->error; if (empty($errormessage)) { $errormessage = implode(',', $this->stockmovement->errors); diff --git a/htdocs/product/stock/class/api_warehouses.class.php b/htdocs/product/stock/class/api_warehouses.class.php index c4fd8472e5f..6c7c8011298 100644 --- a/htdocs/product/stock/class/api_warehouses.class.php +++ b/htdocs/product/stock/class/api_warehouses.class.php @@ -30,7 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; class Warehouses extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'label', @@ -92,6 +92,8 @@ class Warehouses extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.label:like:'WH-%') and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of warehouse objects + * @phan-return Entrepot[] + * @phpstan-return Entrepot[] * * @throws RestException */ diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php index 774cebd33d4..85710483550 100644 --- a/htdocs/projet/class/api_tasks.class.php +++ b/htdocs/projet/class/api_tasks.class.php @@ -33,7 +33,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; class Tasks extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'ref', @@ -106,6 +106,8 @@ class Tasks extends DolibarrApi * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @return array Array of project objects + * @phan-return Task[] + * @phpstan-return Task[] */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '') { @@ -132,7 +134,7 @@ class Tasks extends DolibarrApi $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet AS p ON p.rowid = t.fk_projet"; $sql .= ' WHERE t.entity IN ('.getEntity('project').')'; if ($socids) { - $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")"; + $sql .= " AND t.fk_soc IN (".$this->db->sanitize((string) $socids).")"; } // Search on sale representative if ($search_sale && $search_sale != '-1') { @@ -270,6 +272,8 @@ class Tasks extends DolibarrApi * @param int $id Id of task * @param int $userid Id of user (0 = connected user) * @return array Array of roles + * @phan-return array + * @phpstan-return array * * @url GET {id}/roles */ @@ -295,7 +299,7 @@ class Tasks extends DolibarrApi $usert = new User($this->db); $usert->fetch($userid); } - $this->task->roles = $this->task->getUserRolesForProjectsOrTasks(null, $usert, 0, $id); + $this->task->roles = $this->task->getUserRolesForProjectsOrTasks(null, $usert, '0', $id); $result = array(); foreach ($this->task->roles as $line) { array_push($result, $this->_cleanObjectDatas($line)); @@ -531,6 +535,7 @@ class Tasks extends DolibarrApi * * @param int $id Task ID * @param datetime $date Date (YYYY-MM-DD HH:MI:SS in GMT) + * @phan-param string $date * @param int $duration Duration in seconds (3600 = 1h) * @param int $user_id User (Use 0 for connected user) * @param string $note Note @@ -593,6 +598,7 @@ class Tasks extends DolibarrApi * @param int $id Task ID * @param int $timespent_id Time spent ID (llx_element_time.rowid) * @param datetime $date Date (YYYY-MM-DD HH:MI:SS in GMT) + * @phan-param string $date * @param int $duration Duration in seconds (3600 = 1h) * @param int $user_id User (Use 0 for connected user) * @param string $note Note @@ -696,10 +702,14 @@ class Tasks extends DolibarrApi // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore /** - * Clean sensible object datas + * Clean sensitive object data + * @phpstan-template T of Object * * @param Object $object Object to clean * @return Object Object with cleaned properties + * + * @phpstan-param T $object + * @phpstan-return T */ protected function _cleanObjectDatas($object) { diff --git a/htdocs/projet/class/taskstats.class.php b/htdocs/projet/class/taskstats.class.php index 99a176c9470..f2f3ee3311e 100644 --- a/htdocs/projet/class/taskstats.class.php +++ b/htdocs/projet/class/taskstats.class.php @@ -162,7 +162,7 @@ class TaskStats extends Stats $sqlwhere[] = " t.datec BETWEEN '".$this->db->idate(dol_get_first_day($this->year, $this->month))."' AND '".$this->db->idate(dol_get_last_day($this->year, $this->month))."'"; } if (!empty($this->priority)) { - $sqlwhere[] = " t.priority IN (".$this->db->sanitize((string) $this->priority, 1).")"; + $sqlwhere[] = " t.priority = ".((int) $this->priority); } if (count($sqlwhere) > 0) { diff --git a/htdocs/public/payment/paymentko.php b/htdocs/public/payment/paymentko.php index 88de37b4b11..1336cec30f2 100644 --- a/htdocs/public/payment/paymentko.php +++ b/htdocs/public/payment/paymentko.php @@ -70,6 +70,7 @@ if (isModEnabled('paypal')) { * @var HookManager $hookmanager * @var Societe $mysoc * @var Translate $langs + * @var User $user User object is initialized but empty as it is a public page * * @var string $dolibarr_main_url_root */ @@ -198,6 +199,7 @@ if (!empty($_SESSION['ipaddress'])) { // To avoid to make action twice $ipaddress = $_SESSION['ipaddress']; $errormessage = $_SESSION['errormessage']; + // @phpstan-ignore-next-line if (is_object($object) && method_exists($object, 'call_trigger')) { // Call trigger @phan-suppress-next-line PhanUndeclaredMethod $result = $object->call_trigger('PAYMENTONLINE_PAYMENT_KO', $user); diff --git a/htdocs/reception/class/api_receptions.class.php b/htdocs/reception/class/api_receptions.class.php index e536919e8aa..f860207193a 100644 --- a/htdocs/reception/class/api_receptions.class.php +++ b/htdocs/reception/class/api_receptions.class.php @@ -98,8 +98,8 @@ class Receptions extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of reception objects - * @phan-return array> - * @phpstan-return array> + * @phan-return Reception[]|array{data:Reception[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Reception[]|array{data:Reception[],pagination:array{total:int,page:int,page_count:int,limit:int}} * * @throws RestException */ @@ -765,12 +765,15 @@ class Receptions extends DolibarrApi /** * Validate fields before create or update object * - * @param array $data Array with data to verify + * @param ?array $data Array with data to verify * @return array * @throws RestException */ private function _validate($data) { + if ($data === null) { + $data = array(); + } $reception = array(); foreach (Receptions::$FIELDS as $field) { if (!isset($data[$field])) { diff --git a/htdocs/recruitment/class/recruitmentcandidature.class.php b/htdocs/recruitment/class/recruitmentcandidature.class.php index 3db699c6d45..46c7c225d2b 100644 --- a/htdocs/recruitment/class/recruitmentcandidature.class.php +++ b/htdocs/recruitment/class/recruitmentcandidature.class.php @@ -1,6 +1,6 @@ - * Copyright (C) 2024 Frédéric France + * Copyright (C) 2024-2025 Frédéric France * Copyright (C) 2024-2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -313,20 +313,11 @@ class RecruitmentCandidature extends CommonObject // @phan-suppress-next-line PhanTypeMismatchProperty $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } - if (property_exists($object, 'status')) { - $object->status = self::STATUS_DRAFT; - } - if (property_exists($object, 'date_creation')) { - $object->date_creation = dol_now(); - } - if (property_exists($object, 'date_modification')) { - $object->date_modification = null; - } - // ... + $object->status = self::STATUS_DRAFT; + $object->date_creation = dol_now(); + $object->date_modification = null; + // Clear extrafields that are unique if (is_array($object->array_options) && count($object->array_options) > 0) { $extrafields->fetch_name_optionals_label($this->table_element); diff --git a/htdocs/salaries/class/api_salaries.class.php b/htdocs/salaries/class/api_salaries.class.php index a7227e4ebe6..4d1171ce34d 100644 --- a/htdocs/salaries/class/api_salaries.class.php +++ b/htdocs/salaries/class/api_salaries.class.php @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/salaries/class/paymentsalary.class.php'; class Salaries extends DolibarrApi { /** - * @var array Mandatory fields, checked when creating an object + * @var string[] Mandatory fields, checked when creating an object */ public static $FIELDS = array( 'fk_user', @@ -41,7 +41,7 @@ class Salaries extends DolibarrApi ); /** - * array $FIELDS Mandatory fields, checked when creating an object + * @var string[] Mandatory fields for mayment, checked when creating an object */ public static $FIELDSPAYMENT = array( "paiementtype", @@ -68,6 +68,8 @@ class Salaries extends DolibarrApi * @param int $limit Limit for list * @param int $page Page number * @return array List of salary objects + * @phan-return Salary[] + * @phpstan-return Salary[] * * @throws RestException */ @@ -235,6 +237,8 @@ class Salaries extends DolibarrApi * @param int $limit Limit for list * @param int $page Page number * @return array List of paymentsalary objects + * @phan-return PaymentSalary[] + * @phpstan-return PaymentSalary[] * * @url GET /payments * diff --git a/htdocs/societe/canvas/actions_card_common.class.php b/htdocs/societe/canvas/actions_card_common.class.php index 860c3e071f6..2876c174b10 100644 --- a/htdocs/societe/canvas/actions_card_common.class.php +++ b/htdocs/societe/canvas/actions_card_common.class.php @@ -357,7 +357,7 @@ abstract class ActionsCardCommon $i = 0; foreach ($listsalesrepresentatives as $val) { $userstatic->id = $val['id']; - $userstatic->lastname = $val['name']; + $userstatic->lastname = $val['lastname']; $userstatic->firstname = $val['firstname']; $this->tpl['sales_representatives'] .= $userstatic->getNomUrl(1); $i++; diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php index bfecfc45047..f7e5c811a03 100644 --- a/htdocs/societe/class/api_thirdparties.class.php +++ b/htdocs/societe/class/api_thirdparties.class.php @@ -32,7 +32,7 @@ use Luracast\Restler\RestException; class Thirdparties extends DolibarrApi { /** - * @var array Mandatory fields, checked when we create and update the object + * @var string[] Mandatory fields, checked when we create and update the object */ public static $FIELDS = array( 'name' @@ -86,6 +86,8 @@ class Thirdparties extends DolibarrApi * * @param string $email Email of third party to load * @return array|mixed Cleaned Societe object + * @phan-return Societe + * @phpstan-return Societe * * @url GET email/{email} * @@ -131,6 +133,8 @@ class Thirdparties extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of thirdparty objects + * @phan-return Societe[]|array{data:Societe[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Societe[]|array{data:Societe[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $properties = '', $pagination_data = false) { @@ -301,7 +305,9 @@ class Thirdparties extends DolibarrApi * @param array $request_data Data * @phan-param ?array $request_data * @phpstan-param ?array $request_data - * @return Object|false Updated object + * @return Object Updated object + * @phan-return Societe + * @phpstan-return Societe * * @throws RestException 401 * @throws RestException 404 @@ -362,6 +368,8 @@ class Thirdparties extends DolibarrApi * @param int $id ID of thirdparty to keep (the target third party) * @param int $idtodelete ID of thirdparty to remove (the thirdparty to delete), once data has been merged into the target third party. * @return Object Return the resulted third party. + * @phan-return Societe + * @phpstan-return Societe * * @url PUT {id}/merge/{idtodelete} */ @@ -423,7 +431,7 @@ class Thirdparties extends DolibarrApi if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) { throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login); } - $this->company->oldcopy = clone $this->company; + $this->company->oldcopy = clone $this->company; // @phan-suppress-current-line PhanTypeMismatchProperty $res = $this->company->delete($id); if ($res < 0) { @@ -576,7 +584,9 @@ class Thirdparties extends DolibarrApi * @param string $sortorder Sort order * @param int $limit Limit for list * @param int $page Page number - * @return array|void + * @return array + * @phan-return array,visible:int,ref_ext:string,multilangs?:array}> + * @phpstan-return array,visible:int,ref_ext:string,multilangs?:array}> * * @url GET {id}/categories */ @@ -611,7 +621,9 @@ class Thirdparties extends DolibarrApi * * @param int $id Id of thirdparty * @param int $category_id Id of category - * @return Object|void + * @return Object + * @phan-return Societe + * @phpstan-return Societe * * @url PUT {id}/categories/{category_id} */ @@ -649,7 +661,9 @@ class Thirdparties extends DolibarrApi * @param int $id Id of thirdparty * @param int $category_id Id of category * - * @return Object|void + * @return Object + * @phan-return Societe + * @phpstan-return Societe * * @url DELETE {id}/categories/{category_id} */ @@ -690,7 +704,9 @@ class Thirdparties extends DolibarrApi * @param int $limit Limit for list * @param int $page Page number * - * @return mixed + * @return array + * @phan-return array,visible:int,ref_ext:string,multilangs?:array}> + * @phpstan-return array,visible:int,ref_ext:string,multilangs?:array}> * * @url GET {id}/supplier_categories */ @@ -727,6 +743,8 @@ class Thirdparties extends DolibarrApi * @param int $category_id Id of category * * @return mixed + * @phan-return Societe + * @phpstan-return Societe * * @url PUT {id}/supplier_categories/{category_id} */ @@ -765,6 +783,8 @@ class Thirdparties extends DolibarrApi * @param int $category_id Id of category * * @return mixed + * @phan-return Societe + * @phpstan-return Societe * * @url DELETE {id}/supplier_categories/{category_id} */ @@ -806,6 +826,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/outstandingproposals * * @return array List of outstandings proposals of thirdparty + * @phan-return array{opened?:float} + * @phpstan-return array{opened?:float} * * @throws RestException 400 * @throws RestException 401 @@ -848,6 +870,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/outstandingorders * * @return array List of outstandings orders of thirdparty + * @phan-return array{opened?:float} + * @phpstan-return array{opened?:float} * * @throws RestException 400 * @throws RestException 401 @@ -888,7 +912,9 @@ class Thirdparties extends DolibarrApi * * @url GET {id}/outstandinginvoices * - * @return array List of outstandings invoices of thirdparty + * @return array List of outstanding invoices of third party + * @phan-return array{opened?:float} + * @phpstan-return array{opened?:float} * * @throws RestException 400 * @throws RestException 401 @@ -930,6 +956,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/representatives * * @return array List of representatives of thirdparty + * @phan-return int[]|array + * @phpstan-return int[]|array * * @throws RestException 400 * @throws RestException 401 @@ -950,7 +978,7 @@ class Thirdparties extends DolibarrApi } $result = $this->company->fetch($id); - if (!$result) { + if (!is_array($result)) { throw new RestException(404, 'Thirdparty not found'); } @@ -970,6 +998,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/fixedamountdiscounts * * @return array List of fixed discount of thirdparty + * @phan-return stdClass[] + * @phpstan-return stdClass[] * * @throws RestException 400 * @throws RestException 401 @@ -1033,6 +1063,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/getinvoicesqualifiedforreplacement * * @return array + * @phan-return array|int + * @phpstan-return array|int * @throws RestException 400 * @throws RestException 401 * @throws RestException 404 @@ -1076,6 +1108,8 @@ class Thirdparties extends DolibarrApi * @url GET {id}/getinvoicesqualifiedforcreditnote * * @return array + * @phan-return array|int + * @phpstan-return array|int * * @throws RestException 400 * @throws RestException 401 @@ -1103,7 +1137,7 @@ class Thirdparties extends DolibarrApi require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $invoice = new Facture($this->db); $result = $invoice->list_qualified_avoir_invoices($id); - if ($result < 0) { + if (!is_array($result) && $result < 0) { throw new RestException(405, $invoice->error); } @@ -1116,6 +1150,8 @@ class Thirdparties extends DolibarrApi * @param int $id ID of thirdparty * * @return array + * @phan-return array + * @phpstan-return array * * @url GET {id}/notifications */ @@ -1175,6 +1211,7 @@ class Thirdparties extends DolibarrApi $returnNotifications[] = $object; } + // Too complex for phan ?: @phan-suppress-next-line PhanTypeMismatchReturn return $returnNotifications; } @@ -1215,9 +1252,9 @@ class Thirdparties extends DolibarrApi $exists_sql = "SELECT rowid, fk_action as event, fk_soc as socid, fk_contact as contact_id, type, datec, tms as datem"; $exists_sql .= " FROM ".MAIN_DB_PREFIX."notify_def"; - $exists_sql .= " WHERE fk_action = '".$this->db->escape($event)."'"; - $exists_sql .= " AND fk_soc = '".$this->db->escape($socid)."'"; - $exists_sql .= " AND fk_contact = '".$this->db->escape($contact_id)."'"; + $exists_sql .= " WHERE fk_action = '".$this->db->escape((string) $event)."'"; + $exists_sql .= " AND fk_soc = '".$this->db->escape((string) $socid)."'"; + $exists_sql .= " AND fk_contact = '".$this->db->escape((string) $contact_id)."'"; $exists_result = $this->db->query($exists_sql); if ($this->db->num_rows($exists_result) > 0) { @@ -1285,9 +1322,9 @@ class Thirdparties extends DolibarrApi $exists_sql = "SELECT rowid, fk_action as event, fk_soc as socid, fk_contact as contact_id, type, datec, tms as datem"; $exists_sql .= " FROM ".MAIN_DB_PREFIX."notify_def"; - $exists_sql .= " WHERE fk_action = '".$this->db->escape($event)."'"; - $exists_sql .= " AND fk_soc = '".$this->db->escape($socid)."'"; - $exists_sql .= " AND fk_contact = '".$this->db->escape($contact_id)."'"; + $exists_sql .= " WHERE fk_action = '".$this->db->escape((string) $event)."'"; + $exists_sql .= " AND fk_soc = '".$this->db->escape((string) $socid)."'"; + $exists_sql .= " AND fk_contact = '".$this->db->escape((string) $contact_id)."'"; $exists_result = $this->db->query($exists_sql); if ($this->db->num_rows($exists_result) > 0) { @@ -1381,6 +1418,8 @@ class Thirdparties extends DolibarrApi * @param int $id ID of thirdparty * * @return array + * @phan-return array + * @phpstan-return array * * @url GET {id}/bankaccounts */ @@ -1496,7 +1535,7 @@ class Thirdparties extends DolibarrApi if (empty($account->rum)) { require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php'; $prelevement = new BonPrelevement($this->db); - $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, $account->id); + $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, (string) $account->id); $account->date_rum = dol_now(); } @@ -1551,7 +1590,7 @@ class Thirdparties extends DolibarrApi if (empty($account->rum)) { require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php'; $prelevement = new BonPrelevement($this->db); - $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, $account->id); + $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, (string) $account->id); $account->date_rum = dol_now(); } @@ -1598,6 +1637,8 @@ class Thirdparties extends DolibarrApi * @param int $companybankid Companybank id * @param string $model Model of document to generate * @return array + * @phan-return array{success:int<0,1>} + * @phpstan-return array{success:int<0,1>} * * @url GET {id}/generateBankAccountDocument/{companybankid}/{model} */ @@ -2022,7 +2063,7 @@ class Thirdparties extends DolibarrApi * Delete a specific site account attached to a thirdparty (by account id) * * @param int $id ID of thirdparty - * @param int $site Site key + * @param string $site Site key * * @return void * @throws RestException 401 Unauthorized: User does not have permission to delete thirdparties accounts @@ -2181,6 +2222,8 @@ class Thirdparties extends DolibarrApi * @param string $email Email of third party (Warning, this can return several records) * @param string $ref_alias Name_alias of third party (Warning, this can return several records) * @return object cleaned Societe object + * @phan-return Societe + * @phpstan-return Societe * * @throws RestException */ @@ -2190,7 +2233,7 @@ class Thirdparties extends DolibarrApi throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login.'. No read permission on thirdparties.'); } - if ($rowid === 0) { + if ($rowid == 0) { $result = $this->company->initAsSpecimen(); } else { $result = $this->company->fetch($rowid, $ref, $ref_ext, $barcode, $idprof1, $idprof2, $idprof3, $idprof4, $idprof5, $idprof6, $email, $ref_alias); @@ -2214,8 +2257,8 @@ class Thirdparties extends DolibarrApi $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')"; } - $absolute_discount = $this->company->getAvailableDiscounts('', $filterabsolutediscount); - $absolute_creditnote = $this->company->getAvailableDiscounts('', $filtercreditnote); + $absolute_discount = $this->company->getAvailableDiscounts(null, $filterabsolutediscount); + $absolute_creditnote = $this->company->getAvailableDiscounts(null, $filtercreditnote); $this->company->absolute_discount = price2num($absolute_discount, 'MT'); $this->company->absolute_creditnote = price2num($absolute_creditnote, 'MT'); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 1828e733dba..f0ea8727029 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -1,5 +1,4 @@ * Copyright (C) 2004-2021 Laurent Destailleur * Copyright (C) 2004 Eric Seigne @@ -85,7 +84,7 @@ class Societe extends CommonObject public $fieldsforcombobox = 'nom,name_alias'; /** - * @var array> List of child tables. To test if we can delete object. + * @var array List of child tables. To test if we can delete object. */ protected $childtables = array( 'supplier_proposal' => array('name' => 'SupplierProposal'), @@ -2674,10 +2673,10 @@ class Societe extends CommonObject * Return array of sales representatives * * @param User $user Object user (not used) - * @param int $mode 0=Array with properties, 1=Array of IDs. + * @param int<0,1> $mode 0=Array with properties, 1=Array of IDs. * @param ?string $sortfield List of sort fields, separated by comma. Example: 't1.fielda,t2.fieldb' * @param ?string $sortorder Sort order, separated by comma. Example: 'ASC,DESC'; - * @return array|int Array of sales representatives of the current third party or <0 if KO + * @return int<-1,-1>|int[]|array Array of sales representatives of the current third party or <0 if KO */ public function getSalesRepresentatives(User $user, $mode = 0, $sortfield = null, $sortorder = null) { @@ -2712,7 +2711,7 @@ class Societe extends CommonObject $obj = $this->db->fetch_object($resql); if (empty($mode)) { - $reparray[$i]['id'] = $obj->rowid; + $reparray[$i]['id'] = (int) $obj->rowid; $reparray[$i]['lastname'] = $obj->lastname; $reparray[$i]['firstname'] = $obj->firstname; $reparray[$i]['email'] = $obj->email; @@ -2729,7 +2728,7 @@ class Societe extends CommonObject $reparray[$i]['photo'] = $obj->photo; $reparray[$i]['gender'] = $obj->gender; } else { - $reparray[] = $obj->rowid; + $reparray[] = (int) $obj->rowid; } $i++; } @@ -3095,8 +3094,7 @@ class Societe extends CommonObject } else { $label = implode($this->getTooltipContentArray($params)); } - print "\n"; - //var_dump($label);exit; + $linkstart = ''; $linkend = ''; @@ -4806,7 +4804,7 @@ class Societe extends CommonObject } /** - * Check if we must use revenue stamps feature or not according to country (country of $mysocin most cases). + * Check if we must use revenue stamps feature or not according to country (country of $mysoc in most cases). * Table c_revenuestamp contains the country and value of stamp per invoice. * * @return boolean true or false diff --git a/htdocs/societe/list.php b/htdocs/societe/list.php index 31a51f8621b..2198e083452 100644 --- a/htdocs/societe/list.php +++ b/htdocs/societe/list.php @@ -346,6 +346,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_array_fields.tpl.php'; // @phpstan-ignore-next-line $object->fields = dol_sort_array($object->fields, 'position'); +// @phpstan-ignore-next-line $arrayfields = dol_sort_array($arrayfields, 'position'); // Security check diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php index e0e1fc29508..cc08b6dfb19 100644 --- a/htdocs/stripe/class/stripe.class.php +++ b/htdocs/stripe/class/stripe.class.php @@ -61,12 +61,6 @@ class Stripe extends CommonObject */ public $entity; - /** - * @var string - * @deprecated Was used by createPaymentStripe only that is deprecated - */ - public $result; - /** * @var string */ @@ -1155,289 +1149,4 @@ class Stripe extends CommonObject return $sepa; } - - - /** - * Create charge. - * This was called by page htdocs/stripe/payment.php and may be deprecated. - * - * @param float $amount Amount to pay - * @param string $currency EUR, GPB... - * @param string $origin Object type to pay (order, invoice, contract...) - * @param int $item Object id to pay - * @param string $source src_xxxxx or card_xxxxx or pm_xxxxx - * @param string $customer Stripe customer ref 'cus_xxxxxxxxxxxxx' via customerStripe() - * @param string $account Stripe account ref 'acc_xxxxxxxxxxxxx' via getStripeAccount() - * @param int<0,1> $status Status (0=test, 1=live) - * @param int<0,1> $usethirdpartyemailforreceiptemail Use thirdparty email as receipt email - * @param bool $capture Set capture flag to true (take payment) or false (wait) - * @return Stripe - * @deprecated - */ - public function createPaymentStripe($amount, $currency, $origin, $item, $source, $customer, $account, $status = 0, $usethirdpartyemailforreceiptemail = 0, $capture = true) - { - global $conf; - - $error = 0; - - if (empty($status)) { - $service = 'StripeTest'; - } else { - $service = 'StripeLive'; - } - - $sql = "SELECT sa.key_account as key_account, sa.fk_soc, sa.entity"; - $sql .= " FROM ".MAIN_DB_PREFIX."societe_account as sa"; - $sql .= " WHERE sa.key_account = '".$this->db->escape($customer)."'"; - //$sql.= " AND sa.entity IN (".getEntity('societe').")"; - $sql .= " AND sa.site = 'stripe' AND sa.status = ".((int) $status); - $sql .= " ORDER BY sa.site_account DESC, sa.rowid DESC"; // To get the entry with a site_account defined in priority - - dol_syslog(get_class($this)."::fetch", LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) { - if ($this->db->num_rows($result)) { - $obj = $this->db->fetch_object($result); - $key = $obj->fk_soc; - } else { - $key = null; - } - } else { - $key = null; - } - - $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'); - if (!in_array($currency, $arrayzerounitcurrency)) { - $stripeamount = $amount * 100; - } else { - $stripeamount = $amount; - } - - $societe = new Societe($this->db); - if ($key > 0) { - $societe->fetch($key); - } - - $description = ""; - $ref = ""; - $invoice = null; - if ($origin == 'order') { - $order = new Commande($this->db); - $order->fetch($item); - $ref = $order->ref; - $description = "ORD=".$ref.".CUS=".$societe->id.".PM=stripe"; - } elseif ($origin == 'invoice') { - $invoice = new Facture($this->db); - $invoice->fetch($item); - $ref = $invoice->ref; - $description = "INV=".$ref.".CUS=".$societe->id.".PM=stripe"; - } - - $ipaddress = getUserRemoteIP(); - - $metadata = array( - "dol_id" => (string) $item, - "dol_type" => (string) $origin, - "dol_thirdparty_id" => (string) $societe->id, - 'dol_thirdparty_name' => $societe->name, - 'dol_version' => DOL_VERSION, - 'dol_entity' => $conf->entity, - 'ipaddress' => $ipaddress - ); - $return = new Stripe($this->db); - try { - // Force to use the correct API key - global $stripearrayofkeysbyenv; - \Stripe\Stripe::setApiKey($stripearrayofkeysbyenv[$status]['secret_key']); - - if (empty($conf->stripeconnect->enabled)) { // With a common Stripe account - if (preg_match('/pm_/i', $source)) { - $stripecard = $source; - $amountstripe = $stripeamount; - $FULLTAG = 'PFBO'; // Payment From Back Office - $stripe = $return; - $amounttopay = $amount; - $servicestatus = $status; - - dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG); - $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here) - - dol_syslog("* createPaymentStripe Create payment for customer ".$customer." on source card ".$stripecard.", amounttopay=".$amounttopay.", amountstripe=".$amountstripe.", FULLTAG=".$FULLTAG, LOG_DEBUG); - - // Create payment intent and charge payment (confirmnow = true) - $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard, 1); - - $charge = new stdClass(); - if ($paymentintent->status == 'succeeded') { - $charge->status = 'ok'; - } else { - $charge->status = 'failed'; - $charge->failure_code = $stripe->code; - $charge->failure_message = $stripe->error; - $charge->failure_declinecode = $stripe->declinecode; - $stripefailurecode = $stripe->code; - $stripefailuremessage = $stripe->error; - $stripefailuredeclinecode = $stripe->declinecode; - } - } elseif (preg_match('/acct_/i', $source)) { - $charge = \Stripe\Charge::create(array( - "amount" => "$stripeamount", - "currency" => "$currency", - "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description) - "description" => "Stripe payment: ".$description, - "capture" => $capture, - "metadata" => $metadata, - "source" => "$source" - )); - } else { - $paymentarray = array( - "amount" => "$stripeamount", - "currency" => "$currency", - "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description) - "description" => "Stripe payment: ".$description, - "capture" => $capture, - "metadata" => $metadata, - "source" => (string) $source, - "customer" => (string) $customer - ); - - if ($societe->email && $usethirdpartyemailforreceiptemail) { - $paymentarray["receipt_email"] = $societe->email; - } - - $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description")); - } - } else { - // With Stripe Connect - $fee = $amount * ($conf->global->STRIPE_APPLICATION_FEE_PERCENT / 100) + $conf->global->STRIPE_APPLICATION_FEE; - if ($fee >= $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL && $conf->global->STRIPE_APPLICATION_FEE_MAXIMAL > $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { - $fee = getDolGlobalString('STRIPE_APPLICATION_FEE_MAXIMAL'); - } elseif ($fee < $conf->global->STRIPE_APPLICATION_FEE_MINIMAL) { - $fee = getDolGlobalString('STRIPE_APPLICATION_FEE_MINIMAL'); - } - - if (!in_array($currency, $arrayzerounitcurrency)) { - $stripefee = round($fee * 100); - } else { - $stripefee = round($fee); - } - - $paymentarray = array( - "amount" => "$stripeamount", - "currency" => "$currency", - "statement_descriptor_suffix" => dol_trunc($description, 10, 'right', 'UTF-8', 1), // 22 chars that appears on bank receipt (company + description) - "description" => "Stripe payment: ".$description, - "capture" => $capture, - "metadata" => $metadata, - "source" => (string) $source, - "customer" => (string) $customer - ); - if ($conf->entity != $conf->global->STRIPECONNECT_PRINCIPAL && $stripefee > 0) { - $paymentarray["application_fee_amount"] = $stripefee; - } - if ($societe->email && $usethirdpartyemailforreceiptemail) { - $paymentarray["receipt_email"] = $societe->email; - } - - if (preg_match('/pm_/i', $source)) { - $stripecard = $source; - $amountstripe = $stripeamount; - $FULLTAG = 'PFBO'; // Payment From Back Office - $stripe = $return; - $amounttopay = $amount; - $servicestatus = $status; - - dol_syslog("* createPaymentStripe get stripeacc", LOG_DEBUG); - $stripeacc = $stripe->getStripeAccount($service); // Get Stripe OAuth connect account if it exists (no network access here) - - dol_syslog("* createPaymentStripe Create payment on card ".$stripecard.", amounttopay=".$amounttopay.", amountstripe=".$amountstripe.", FULLTAG=".$FULLTAG, LOG_DEBUG); - - // Create payment intent and charge payment (confirmnow = true) - $paymentintent = $stripe->getPaymentIntent($amounttopay, $currency, $FULLTAG, $description, $invoice, $customer, $stripeacc, $servicestatus, 0, 'automatic', true, $stripecard, 1); - - $charge = new stdClass(); - if ($paymentintent->status == 'succeeded') { - $charge->status = 'ok'; - $charge->id = $paymentintent->id; - } else { - $charge->status = 'failed'; - $charge->failure_code = $stripe->code; - $charge->failure_message = $stripe->error; - $charge->failure_declinecode = $stripe->declinecode; - } - } else { - $charge = \Stripe\Charge::create($paymentarray, array("idempotency_key" => "$description", "stripe_account" => "$account")); - } - } - '@phan-var-force stdClass|\Stripe\Charge $charge'; - /* - if (isset($charge->id)) { - } - */ - - $return->result = 'success'; - $return->id = $charge->id; - - if (preg_match('/pm_/i', $source)) { - $return->message = 'Payment retrieved by card status = '.$charge->status; - } else { - if ($charge->source->type == 'card') { - $return->message = $charge->source->card->brand." ....".$charge->source->card->last4; - } elseif ($charge->source->type == 'three_d_secure') { - $stripe = new Stripe($this->db); - $src = \Stripe\Source::retrieve((string) $charge->source->three_d_secure->card, array( - "stripe_account" => $stripe->getStripeAccount($service) - )); - $return->message = $src->card->brand." ....".$src->card->last4; - } else { - $return->message = $charge->id; - } - } - } catch (\Stripe\Exception\CardException $e) { - include DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - // Since it's a decline, \Stripe\Exception\Card will be caught - $body = $e->getJsonBody(); - $err = $body['error']; - - $return->result = 'error'; - $return->id = $err['charge']; - $return->type = $err['type']; - $return->code = $err['code']; - $return->message = $err['message']; - $body = "Error:
".$return->id." ".$return->message." "; - $subject = '[Alert] Payment error using Stripe'; - $cmailfile = new CMailFile($subject, $conf->global->ONLINE_PAYMENT_SENDEMAIL, $conf->global->MAIN_INFO_SOCIETE_MAIL, $body); - $cmailfile->sendfile(); - - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (\Stripe\Exception\RateLimitException $e) { - // Too many requests made to the API too quickly - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (\Stripe\Exception\InvalidRequestException $e) { - // Invalid parameters were supplied to Stripe's API - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (\Stripe\Exception\AuthenticationException $e) { - // Authentication with Stripe's API failed - // (maybe you changed API keys recently) - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (\Stripe\Exception\ApiConnectionException $e) { - // Network communication with Stripe failed - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (\Stripe\Exception\ExceptionInterface $e) { - // Display a very generic error to the user, and maybe send - // yourself an email - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } catch (Exception $e) { - // Something else happened, completely unrelated to Stripe - $error++; - dol_syslog($e->getMessage(), LOG_WARNING, 0, '_stripe'); - } - return $return; - } } diff --git a/htdocs/supplier_proposal/class/api_supplier_proposals.class.php b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php index 0d607880f12..d2fa85fa69d 100644 --- a/htdocs/supplier_proposal/class/api_supplier_proposals.class.php +++ b/htdocs/supplier_proposal/class/api_supplier_proposals.class.php @@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class class SupplierProposals extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'socid' @@ -226,6 +226,8 @@ class SupplierProposals extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of order objects + * @phan-return SupplierProposal[]|array{data:SupplierProposal[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return SupplierProposal[]|array{data:SupplierProposal[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '', $properties = '', $pagination_data = false) { diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php index e6c2320a977..2570b8ad24b 100644 --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php @@ -435,7 +435,7 @@ class SupplierProposal extends CommonObject * @param int $pa_ht Buying price without tax * @param string $label ??? * @param array $array_options extrafields array - * @param string $ref_supplier Supplier price reference + * @param string $ref_supplier Supplier price reference * @param int $fk_unit Id of the unit to use. * @param string $origin 'order', 'supplier_proposal', ... * @param int $origin_id Id of origin line diff --git a/htdocs/theme/dolibarr_logo.svg b/htdocs/theme/dolibarr_logo.svg index 72795dfbbe7..94b7c1a6589 100644 --- a/htdocs/theme/dolibarr_logo.svg +++ b/htdocs/theme/dolibarr_logo.svg @@ -1,137 +1 @@ - - - -ERP/CRM + diff --git a/htdocs/ticket/class/api_tickets.class.php b/htdocs/ticket/class/api_tickets.class.php index c633ab5085e..da0eb4c4d87 100644 --- a/htdocs/ticket/class/api_tickets.class.php +++ b/htdocs/ticket/class/api_tickets.class.php @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/ticket.lib.php'; class Tickets extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'subject', @@ -40,7 +40,7 @@ class Tickets extends DolibarrApi ); /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS_MESSAGES = array( 'track_id', @@ -202,6 +202,8 @@ class Tickets extends DolibarrApi * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * * @return array Array of ticket objects + * @phan-return Ticket[]|array{data:Ticket[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Ticket[]|array{data:Ticket[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($socid = 0, $sortfield = "t.rowid", $sortorder = "ASC", $limit = 100, $page = 0, $sqlfilters = '', $properties = '', $pagination_data = false) { diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php index 088a56488a4..19351cd2dbd 100644 --- a/htdocs/variants/class/ProductCombination.class.php +++ b/htdocs/variants/class/ProductCombination.class.php @@ -3,7 +3,7 @@ * Copyright (C) 2018 Juanjo Menent * Copyright (C) 2022 Open-Dsi * Copyright (C) 2024-2025 MDW - * Copyright (C) 2024 Frédéric France + * 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 @@ -577,7 +577,6 @@ class ProductCombination } else { $new_price += $variation_price; } - $ret = $child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, $i, $new_npr, $new_psq, 0, array(), $parent->default_vat_code); if ($ret < 0) { @@ -607,7 +606,7 @@ class ProductCombination $new_price += $this->variation_price; } - $ret = $child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, 1, $new_npr, $new_psq); + $ret = $child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, 1, $new_npr, $new_psq, 0, [], $parent->default_vat_code); if ($ret < 0) { $this->db->rollback(); diff --git a/htdocs/webhook/class/api_webhook.class.php b/htdocs/webhook/class/api_webhook.class.php index e51a73ff463..95aad63f9b8 100644 --- a/htdocs/webhook/class/api_webhook.class.php +++ b/htdocs/webhook/class/api_webhook.class.php @@ -27,7 +27,7 @@ use Luracast\Restler\RestException; class Webhook extends DolibarrApi { /** - * @var array Mandatory fields, checked when we create and update the object + * @var string[] Mandatory fields, checked when we create and update the object */ public static $FIELDS = array( 'url', @@ -80,6 +80,8 @@ class Webhook extends DolibarrApi * @param string $properties Restrict the data returned to these properties. Ignored if empty. Comma separated list of properties names * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0* * @return array Array of target objects + * @phan-return Target[]|array{data:Target[],pagination:array{total:int,page:int,page_count:int,limit:int}} + * @phpstan-return Target[]|array{data:Target[],pagination:array{total:int,page:int,page_count:int,limit:int}} */ public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '', $pagination_data = false) { @@ -259,6 +261,8 @@ class Webhook extends DolibarrApi * Get the list of all available triggers * * @return array + * @phan-return array + * @phpstan-return array * * @url GET triggers */ diff --git a/htdocs/website/samples/wrapper.php b/htdocs/website/samples/wrapper.php index 42250c0460f..a84bc3a75b6 100644 --- a/htdocs/website/samples/wrapper.php +++ b/htdocs/website/samples/wrapper.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2024-2025 Frédéric France * Copyright (C) 2025 MDW * * This program is free software; you can redistribute it and/or modify @@ -128,6 +128,7 @@ if (GETPOSTISSET('type')) { // Security: Delete string ../ into $original_file $original_file = str_replace("../", "/", $original_file); + // Cache or not $cachestring = GETPOST("cache", 'aZ09'); // May be 1, or an int (delay in second of the cache if < 999999, or a timestamp), or a hash $cachedelay = GETPOSTINT('cachedelay') ? GETPOSTINT('cachedelay') : ((is_numeric($cachestring) && (int) $cachestring > 1 && (int) $cachestring < 999999) ? $cachestring : '3600'); diff --git a/htdocs/zapier/class/api_zapier.class.php b/htdocs/zapier/class/api_zapier.class.php index d917d192024..859d2f7a598 100644 --- a/htdocs/zapier/class/api_zapier.class.php +++ b/htdocs/zapier/class/api_zapier.class.php @@ -37,7 +37,7 @@ require_once DOL_DOCUMENT_ROOT.'/zapier/class/hook.class.php'; class Zapier extends DolibarrApi { /** - * @var array Mandatory fields, checked when create and update object + * @var string[] Mandatory fields, checked when create and update object */ public static $FIELDS = array( 'url', diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php index 30fb513b859..67c3e13b816 100644 --- a/test/phpunit/FunctionsLibTest.php +++ b/test/phpunit/FunctionsLibTest.php @@ -1925,13 +1925,36 @@ class FunctionsLibTest extends CommonClassTest */ public function testNaturalSearch() { + global $db; + $s = natural_search("t.field", "abc def"); - $this->assertEquals($s, " AND (t.field LIKE '%abc%' AND t.field LIKE '%def%')"); + $this->assertEquals(" AND (t.field LIKE '%abc%' AND t.field LIKE '%def%')", $s); $s = natural_search("t.field", "'abc def' ghi"); - $this->assertEquals($s, " AND (t.field LIKE '%abc def%' AND t.field LIKE '%ghi%')"); + $this->assertEquals(" AND (t.field LIKE '%abc def%' AND t.field LIKE '%ghi%')", $s); - $s = natural_search("t.field", "abc def,ghi", 3); - $this->assertEquals($s, " AND (t.field IN ('abc def','ghi'))"); + $s = natural_search("t.field", "abc def,ghi", 3); // mode 3 is to provide a list of string separated with coma + $this->assertEquals(" AND (t.field IN ('abc def','ghi'))", $s); + + $s = natural_search("t.field", "'ab\'c' def','ghi', 'jkl'", 3); // mode 3 is to provide a list of string separated with coma + $this->assertEquals(" AND (t.field IN ('abc def','ghi','jkl'))", $s); + + $s = natural_search("t.field", "a,b", 3); // mode 3 is to provide a list of string separated with coma + $this->assertEquals(" AND (t.field IN ('a','b'))", $s); + + $s = natural_search("t.field", "A'@%B", 3); // mode 3 is to provide a list of string separated with coma + $this->assertEquals(" AND (t.field IN ('AB'))", $s); + + /* + $s = $db->sanitize("a,b", 1); + var_dump($s); + $s = $db->sanitize("'a',b", 1); + var_dump($s); + $s = $db->sanitize("'a'b',c", 1); + var_dump($s); + */ + + $s = natural_search("t.field", "KØB", 3); // mode 3 is to provide a list of string separated with coma + $this->assertEquals(" AND (t.field IN ('KØB'))", $s); } }