Compare commits

...

154 Commits

Author SHA1 Message Date
Alexandre SPANGARO
0cc80e65ed FIX SQL Error on VAT not defined in product card (#37159) 2026-02-09 18:33:54 +01:00
Laurent Destailleur
7f9bdc5f45 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2026-02-08 15:50:12 +01:00
Laurent Destailleur
b220cf0832 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-02-08 15:48:06 +01:00
Eric - CAP-REL
94d4f2661d MEMBER_ADDON does not exists, MEMBER_CODEMEMBER_ADDON is the right key (#37151) 2026-02-08 15:38:36 +01:00
Laurent Destailleur
2b3ae6c2d7 Add logs 2026-02-06 13:16:16 +01:00
Laurent Destailleur
da0ece345f Fix label 2026-02-06 13:06:16 +01:00
Laurent Destailleur
173c6865cb Test CI 2026-02-06 13:05:21 +01:00
Vincent Penel
59ce599ba5 set oldCopy and Status (#37117)
* set oldCopy and Status

* Update ticket.class.php

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-02-06 12:18:36 +01:00
Laurent Destailleur
66c552ccb2 Removed not used file 2026-02-06 02:39:30 +01:00
Eric Seigne
07a3d0e4b7 auto assign PR on 18.0 / Unable to resolve action cli/gh-action, repository not found 2026-02-05 09:43:02 +01:00
Benjamin Falière
72ed29a599 FIX(API, thirdparties): get fixed amount discounts (#37068)
Co-authored-by: Benjamin Falière <benjamin.faliere@altairis.fr>
2026-02-04 14:50:21 +01:00
Sylvain Legrand
70b3be5e7f Fix from V22 (#35559)
Using a packaging with a float value less than 1 (0.1, 0.5, etc.) generates a 500 error (division by 0)

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
Co-authored-by: Eric - CAP-REL <1468823+rycks@users.noreply.github.com>
2026-01-29 13:02:25 +01:00
Eric Seigne
07ff579416 auto assign PR to 18 thanks to copilot 2026-01-29 10:01:29 +01:00
HENRY Florian
51e61c8ef3 FIX: missing code to add Ressource to event on creation card (#37002) 2026-01-28 15:17:39 +01:00
Laurent Destailleur
e69d016b9f Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2026-01-27 10:45:17 +01:00
Laurent Destailleur
53dbc754f6 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-01-27 10:43:41 +01:00
Laurent Destailleur
a9dcecbc2f Merge branch '16.0' of git@github.com:/Dolibarr/dolibarr.git into 17.0 2026-01-27 10:43:20 +01:00
Laurent Destailleur
5d524f7973 Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 16.0 2026-01-27 10:43:01 +01:00
Laurent Destailleur
1b2f16b01a Fix ci 2026-01-27 10:42:37 +01:00
Laurent Destailleur
c933e4a25a Merge branch '19.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2026-01-26 19:05:17 +01:00
Laurent Destailleur
449870d347 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2026-01-26 19:05:09 +01:00
Laurent Destailleur
bf09f22239 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-01-26 18:58:35 +01:00
Laurent Destailleur
5595cdbb25 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-01-26 18:58:26 +01:00
Laurent Destailleur
dece1bc0f7 Merge branch '16.0' of git@github.com:/Dolibarr/dolibarr.git into 17.0 2026-01-26 18:57:53 +01:00
Laurent Destailleur
a0e2235adf Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 16.0 2026-01-26 18:56:40 +01:00
Laurent Destailleur
bec138412b Merge branch '14.0' of git@github.com:Dolibarr/dolibarr.git into 15.0 2026-01-26 18:56:02 +01:00
HENRY Florian
926ed04ebe fix: PHP fatal error on php 8.2 Unsupported operand types: string * string (#36930) 2026-01-20 13:58:17 +01:00
atm-lucas
39d30a23fe Duplicates in the result of the SQL query (#36913) 2026-01-19 13:44:09 +01:00
Laurent Destailleur
7df6595351 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-01-13 16:04:30 +01:00
Laurent Destailleur
2cfdbd6b5f Try to use PR ID instead of PR url 2026-01-13 16:04:20 +01:00
ThomasNgr-OpenDSI
2e7ab21d01 FIX #GHSA-w5j3-8fcr-h87w (#36868)
Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-01-13 11:37:36 +01:00
Benjamin Falière
7b6051a0d0 FIX(ticket): check on TICKET_IMAGE_PUBLIC_INTERFACE (#36833)
* FIX(ticket): check on TICKET_IMAGE_PUBLIC_INTERFACE

Must use getDolGlobalString instead of getDolGlobalInt here

* Add contributor

---------

Co-authored-by: Benjamin Falière <benjamin.faliere@altairis.fr>
2026-01-10 17:46:45 +01:00
Laurent Destailleur
6fabf82f1d Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2026-01-10 17:45:28 +01:00
Laurent Destailleur
b3669d4333 Try to fix script 2026-01-10 17:45:20 +01:00
Mathieu Moulin
a5b106fe70 Fix error removing reception with product batches (eatby/sellby) (#36846) 2026-01-10 17:30:45 +01:00
lvessiller-opendsi
f497a6a4fe FIX warning accountancy export from external module (#36832) 2026-01-08 18:54:15 +01:00
Eric - CAP-REL
db3d8a0a1a Merge pull request #35863 from RyAbn/18.0_FIX_CMailFile_syslog_message
FIX: php8.1 warning in syslog message
2026-01-08 09:56:27 +01:00
Eric - CAP-REL
d5cab67f4c Fix log message for empty cid_list
apply same fix as 20.0 to avoid conflicts on next merges
2026-01-08 09:55:28 +01:00
Eric - CAP-REL
85a0383b46 Merge branch '18.0' into 18.0_FIX_CMailFile_syslog_message 2026-01-08 09:52:47 +01:00
Eric - CAP-REL
c981b7ccb6 Merge pull request #36343 from noec764/18_FIX_socid_undefined
FIX: TakePos sometimes thirdpartyid = undefined
2026-01-08 09:47:52 +01:00
lvessiller-opendsi
590bf2dd0e Merge pull request #36616 from rycks/18_fix_ticket_double_slash_on_url
remove slash like other parts of dolibarr code for TICKET_URL_PUBLIC_…
2026-01-08 09:41:28 +01:00
lvessiller-opendsi
c25dda01b4 Merge pull request #36815 from lemathou/mmi-fix-reception-delete-stock-mvt
FIX : remove stock correctly when reception is deleted (like 82e092f)
2026-01-08 09:30:04 +01:00
Laurent Destailleur
f450dd00a8 Merge branch '18.0' into mmi-fix-reception-delete-stock-mvt 2026-01-07 18:41:06 +01:00
Laurent Destailleur
39fe5e85e5 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2026-01-07 18:36:51 +01:00
Laurent Destailleur
05c11e71e2 Fix CI 2026-01-07 18:33:22 +01:00
Mathieu Moulin
ad3304832d FIX : remove stock correctly when reception is deleted (like 82e092f) 2026-01-06 15:32:59 +01:00
Maxime Kohlhaas
bfe8f57c03 Fix : updateline was not possible because of wrong status test (#36802)
* Fix : updateline was not possible because of wrong status test

* Fix : better fix, remove useless test to work like on customer facrec
2026-01-05 18:44:55 +01:00
atm-lucas
70348f8c85 Supplier Proposal line option (#36753) 2025-12-30 11:09:38 +01:00
lvessiller-opendsi
c33b7e0bf1 FIX finished regex in product import (#36770) 2025-12-30 11:03:20 +01:00
Eric - CAP-REL
2e22f9e75a fix concat for a undef entry of array (#36754) 2025-12-27 23:04:40 +01:00
Eric Seigne
c017ea0341 Merge branch '18_fix_ticket_double_slash_on_url' of github.com:rycks/dolibarr into 18_fix_ticket_double_slash_on_url 2025-12-18 09:36:48 +01:00
Eric Seigne
eb4d9dec53 thanks to lionel : remove view.php in default value like other part of dolibarr 2025-12-18 09:36:45 +01:00
Laurent Destailleur
2ca80ffa67 Merge branch '18.0' into 18_fix_ticket_double_slash_on_url 2025-12-17 13:27:57 +01:00
Laurent Destailleur
e1b5e024f5 Merge 2025-12-15 15:56:34 +01:00
Laurent Destailleur
a0be2c8890 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-12-15 15:54:00 +01:00
Laurent Destailleur
77d7ec8a2b Merge branch '16.0' of git@github.com:/Dolibarr/dolibarr.git into 17.0 2025-12-15 15:53:38 +01:00
Laurent Destailleur
cc37c778dc Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 16.0 2025-12-15 15:53:00 +01:00
Laurent Destailleur
722c31d182 Merge branch '14.0' of git@github.com:Dolibarr/dolibarr.git into 15.0 2025-12-15 15:52:34 +01:00
Laurent Destailleur
ba2c173936 Merge pull request #36203 from Easya-Solutions/14.0_fix-purge-files-api-temp
FIX re-create API temp dir after purging temp files
2025-12-15 15:51:52 +01:00
Eric Seigne
8d84cec3ca remove slash like other parts of dolibarr code for TICKET_URL_PUBLIC_INTERFACE 2025-12-11 10:43:24 +01:00
lvessiller-opendsi
3c2e85bdb1 Merge pull request #36541 from rycks/18_fix_deposit_backport_43f551e270a00165dcb7274c0904b66b9eaf30b8
backport of PR36378 : Problem with deposit line on Type of operation
2025-12-11 10:18:58 +01:00
Eric Seigne
18f85df343 remove spaces from prev fix 2025-12-11 10:11:58 +01:00
Eric - CAP-REL
9afa5c713d Merge pull request #36585 from Easya-Solutions/18.0_fix-invoice-card-variables2
FIX undefined variables on create invoice card from order (backport f…
2025-12-11 09:30:15 +01:00
VESSILLER
157aa32e0a FIX undefined variables on create invoice card from order (backport from v19) 2025-12-09 10:12:10 +01:00
Laurent Destailleur
5822887d32 Merge pull request #36555 from noec764/17_FIX_missing_product_ref
FIX: Missing Product ref in Bom stats
2025-12-07 23:50:13 +01:00
Noé
aa6ef5ae11 FIX: Missing Product ref in Bom stats 2025-12-05 17:22:18 +01:00
Laurent Destailleur
7cd529a179 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-12-05 16:22:11 +01:00
Laurent Destailleur
82c3849baa Fix CI 2025-12-05 16:21:15 +01:00
Laurent Destailleur
c932a1c878 Merge pull request #36542 from ATM-Consulting/FIX/155/18.0/regression-variable-renaming
FIX: fix #36401 (for v17.0) doesn't work in v18.0+ because of variable renaming
2025-12-05 09:48:32 +01:00
Laurent Destailleur
f2f8278603 Merge pull request #36539 from W1W1-M/backport-fix-propal-update-shipping-availability
FIX propal shipping and availability update (v18+)
2025-12-05 09:47:25 +01:00
Eric Seigne
c6ed34ebcc backport of PR36378 : Problem with deposit line on Type of operation 2025-12-05 09:32:03 +01:00
atm-florian
cc5a8fd15a FIX: PR#36401 fixed a missing GETPOSTISSET() but the check involves a variable ($taskid) that was renamed ($tmptaskid) in 18.0 2025-12-05 09:29:15 +01:00
William Mead
a567cade7d Fixed shipping and availability updating. Updated contributor details. 2025-12-05 08:56:14 +01:00
Laurent Destailleur
764bb3791b Fix CI 2025-12-04 21:51:03 +01:00
Laurent Destailleur
9ac82f488e Fix CI 2025-12-04 21:50:26 +01:00
Laurent Destailleur
222cd76799 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-12-04 18:53:04 +01:00
Laurent Destailleur
47799b88cf Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-12-04 18:40:23 +01:00
Laurent Destailleur
78ca968db6 Merge pull request #36517 from atm-florianm/SEC/commented-out-restrictedArea
SEC: FIX #36430 permissions not checked on other tabs of HRM evaluation card
2025-12-04 18:37:46 +01:00
Noé
2ee07bb049 FIX: Remove <?= 2025-12-04 17:27:57 +01:00
Laurent Destailleur
aa8fac1deb Merge pull request #36429 from atm-adrien/FIX/MulticompanyStockCompatibility
FIX : Implementation of multi-company compatibility with inventory/warehouse management
2025-12-04 10:42:35 +01:00
Eric - CAP-REL
2ebdcfda5c Merge pull request #35788 from Easya-Solutions/18_allow_credit_invoice_on_situation
FIX : remove useless condition to create credit on situation invoice …
2025-12-04 09:56:30 +01:00
Eric - CAP-REL
70431043af Merge pull request #36398 from Easya-Solutions/18.0_fix-invoice-card-variables
FIX undefined variables on create invoice from shipment card (backport from v20)
2025-12-04 09:30:56 +01:00
lvessiller-opendsi
ad37ece7bc Merge pull request #36494 from atm-florianm/FIX/155/date/minute-second-vs-min-sec
FIX 18.0: `GETPOSTDATE()` and `buildParamDate()` assumed wrong HTTP param names
2025-12-04 09:27:44 +01:00
atm-florian
a1476fd221 SEC: permissions not checked on other tabs of HRM evaluation card 2025-12-03 17:11:14 +01:00
atm-florian
0e1c580f11 FIX 18.0: GETPOSTDATE and buildParamDate assumed HTTP param names 'minute' and 'second' instead of 'min' and 'sec' 2025-12-01 13:47:50 +01:00
Laurent Destailleur
4223ff08ce Merge pull request #36491 from Easya-Solutions/18.0_fix-update-extras
FIX not remove value of others extra-fields on update extras action
2025-12-01 13:10:08 +01:00
lvessiller-opendsi
0beee0bec5 Merge branch '14.0' into 14.0_fix-purge-files-api-temp 2025-12-01 11:53:59 +01:00
VESSILLER
d16f8b68db FIX not remove value of others extra-fields on update extras action 2025-12-01 11:14:16 +01:00
Laurent Destailleur
d8891130f5 Merge pull request #36463 from vold-lu/18.0
NEW: Automatically release docker image for each GitHub release
2025-11-28 18:13:47 +01:00
Aloïs Micard
b2f9de7489 Add new workflow to trigger Docker build 2025-11-28 17:27:32 +01:00
Noé
3416c6ccc0 FIX: getDolGlobalInt 2025-11-27 10:00:43 +01:00
Laurent Destailleur
17ff2bea5d Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-26 21:16:11 +01:00
Laurent Destailleur
1002557746 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-11-26 21:12:58 +01:00
Laurent Destailleur
908880c82c SEC: fix IDOR attack on employee evaluation. Missing permision test 7ed0af2a13
SEC: empty commit for CI automata
2025-11-26 15:41:53 +01:00
atm-florian
3608e9b102 SEC: 7ed0af2a13 2025-11-26 14:44:38 +01:00
Adrien Raze
c1c2358e75 FIX : Implementation of multi-company compatibility with inventory/warehouse management 2025-11-26 12:30:22 +01:00
Laurent Destailleur
69ac8cebbf Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-25 21:09:26 +01:00
Laurent Destailleur
1e16bf5160 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-11-25 21:09:04 +01:00
Florian Mortgat
c2635f5242 FIX 17.0: perweek.php resets task progress to 0% when: (#36401)
* FIX 17.0: perweek.php resets task progress to 0% when:
1. the column "Declared real progress" is hidden (which means the corresponding form inputs won't be displayed)
2. and the user doesn't enter any time for that task (= leaves the input empty)

If the column is shown, the bug doesn't occur because the correct value is sent with $_POST.
If the user enters time, the bug doesn't occur because there is a GETPOSTISSET test for that case.

* Apply suggestion from @atm-florianm

variable name ($taskid vs $tmptaskid)
2025-11-24 16:32:27 +01:00
Laurent Destailleur
9394f24cf7 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-24 16:15:26 +01:00
Laurent Destailleur
b1a4520059 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-11-24 16:10:29 +01:00
Laurent Destailleur
2935a245a3 Merge branch '16.0' of git@github.com:/Dolibarr/dolibarr.git into 17.0 2025-11-24 16:07:46 +01:00
Laurent Destailleur
5589ed71b2 Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 16.0 2025-11-24 16:07:22 +01:00
Laurent Destailleur
32f160355b Merge branch '14.0' of git@github.com:Dolibarr/dolibarr.git into 15.0 2025-11-24 16:03:52 +01:00
Florian Mortgat
5a61cc9393 FIX DA027383: permissions not checked on HRM evaluation card (#36328) (#36399)
Permissions involved:
- hrm->evaluation->readall: the user can view anyone's evaluations
- hrm->evaluation->read: the user can only view their or their subordinates' evaluations
2025-11-24 14:57:20 +01:00
Florian Mortgat
7ed0af2a13 FIX DA027383: permissions not checked on HRM evaluation card (#36328)
Permissions involved:
- hrm->evaluation->readall: the user can view anyone's evaluations
- hrm->evaluation->read: the user can only view their or their subordinates' evaluations
2025-11-24 12:21:51 +01:00
VESSILLER
1cd3ca3222 FIX undefined variables on create invoice from shipment card (backport from v20) 2025-11-24 10:30:08 +01:00
Noé
92197cb100 FIX: php echo instead of <? 2025-11-21 16:06:09 +01:00
Eric - CAP-REL
c8acd48e34 setErrors does not exists, same solution as dolibarr v19.0 (#36107)
* setErrors does not exists, same solution as dolibarr v19.0

* reload ci

* reload ci 2

---------

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
Co-authored-by: lvessiller-opendsi <lvessiller@open-dsi.fr>
2025-11-20 23:58:15 +01:00
ldestailleur
9e8460c3dc Fix CI 2025-11-20 15:17:01 +01:00
ldestailleur
70f5e20572 Fix CI 2025-11-20 15:16:04 +01:00
Laurent Destailleur
3a617ed772 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-20 15:14:27 +01:00
Laurent Destailleur
f32386208d Fix CI 2025-11-20 15:14:09 +01:00
Laurent Destailleur
1adf4ce67f Fix CI 2025-11-20 15:13:52 +01:00
Noé
9319059349 FIX: Sometimes socid = undefined 2025-11-20 14:01:29 +01:00
Laurent Destailleur
515a615915 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-20 11:44:40 +01:00
noec764
ac4820b4cb FIX: TakePOS Missing Thirdparty Id when getting more products (#36341)
Co-authored-by: Noé <noe@scopen.fr>
2025-11-20 11:34:06 +01:00
Eric Seigne
f9d285c416 Merge branch '18.0' of https://github.com/Dolibarr/dolibarr into 18.0 2025-11-20 10:09:57 +01:00
Eric Seigne
f1f7ea93b0 fix assign-and-label-v18 2025-11-20 10:09:29 +01:00
lvessiller-opendsi
1f6cec841f Merge pull request #35795 from hregis/fix_18_multicompany_compatibility
FIX Multicompany compatibility with "project_task"
2025-11-20 10:03:38 +01:00
lvessiller-opendsi
4dcbd826e6 Merge pull request #35812 from Easya-Solutions/18__fix_situation_remove_from_cycle
FIX remove situation invoice from cycle
2025-11-20 10:03:02 +01:00
Eric Seigne
fd5c9b0562 update github actions for race conditions of author/reviewer 2025-11-20 09:46:59 +01:00
Florian Mortgat
8e30fc0bd1 FIX 19.0 - attachments upload dir for invoices not always determined correctly (doesn't always take multi-entity into account) (#36302) 2025-11-18 11:39:45 +01:00
Regis Houssin
21843e68b0 FIX #36149 (#36150) 2025-11-18 10:12:05 +01:00
lvessiller-opendsi
30ecf80732 FIX keep user who validate proposal on update (#36257) 2025-11-14 15:53:31 +01:00
VESSILLER
c2ae7d2da1 FIX create API temp directory in Dolibarr API constructor 2025-11-13 14:01:34 +01:00
lvessiller-opendsi
9de04b1c48 Merge pull request #35809 from marc-dll/18.0_FIX_expensereport_bankaccount_access
FIX: expense report card: do not show bank account if user cannot see them
2025-11-13 09:39:39 +01:00
Eric - CAP-REL
7e7939d234 Merge pull request #35893 from RyAbn/18.0_FIX_Email_collector_no_msg_parts_fatal_error
FIX: Email Collector Module
2025-11-13 09:22:44 +01:00
Laurent Destailleur
dba065c222 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into 19.0 2025-11-12 21:50:04 +01:00
Laurent Destailleur
29edc77dd5 Merge branch '17.0' of git@github.com:Dolibarr/dolibarr.git into 18.0 2025-11-12 21:46:53 +01:00
Laurent Destailleur
99fe044868 Merge branch '16.0' of git@github.com:/Dolibarr/dolibarr.git into 17.0 2025-11-12 21:44:49 +01:00
Laurent Destailleur
8ae27c3a5f Merge branch '15.0' of git@github.com:Dolibarr/dolibarr.git into 16.0 2025-11-12 21:44:34 +01:00
Ryad ABANI
ea28972862 FIX: dol_escape_htmltag in extrafields_view (#36136)
Co-authored-by: Ryad ABANI <ryad.abani@scopen.fr>
2025-11-12 15:44:40 +01:00
VESSILLER
71ec381d3e FIX re-create API temp dir after purging temp files 2025-11-10 10:56:07 +01:00
Frédéric FRANCE
5fa475a074 fix directory was always overwritten (#36148) 2025-11-07 18:43:26 +01:00
Regis Houssin
3ad30f8622 FIX use array_intersect instead in_array 2025-11-07 12:07:50 +01:00
Regis Houssin
3b7cda03f3 Merge branch '18.0' of git@github.com:Dolibarr/dolibarr.git into fix_18_multicompany_compatibility 2025-11-07 12:04:44 +01:00
Eric - CAP-REL
e5f3c2c117 Merge pull request #35963 from hregis/fix_18_wrong_hook_check
FIX wrong check of hook return
2025-11-06 09:28:56 +01:00
lvessiller-opendsi
1d24cf5ea5 Merge pull request #36027 from Easya-Solutions/18_fix_list_on_societe_price_tab
Fix listincsv on tab societe/price.php
2025-11-06 09:26:08 +01:00
Laurent Destailleur
689b992afb Split tasks 2025-11-05 22:40:50 +01:00
Florian Mortgat
a16f3bdf31 FIX 16.0: extrafield of type link to category causes SQL error in selectForFormsList() (#36074)
* FIX 16.0 (up to 19.0): extrafield of type link to category causes SQL error in selectForFormsList

* Apply suggestion from @atm-florianm
2025-11-04 13:06:58 +01:00
atm-GregM
dc7932700b Fix TICKET_ENABLE_PUBLIC_INTERFACE (#36073) 2025-11-04 12:25:57 +01:00
Marc de Lima Lucio
223326610e FIX: expense report card: use correct bank module designator for detection 2025-10-31 13:43:21 +01:00
tnegre
2555b14f9c Fix listincsv on tab societe/price.php 2025-10-31 09:39:09 +01:00
Regis Houssin
edd4565921 FIX wrong check of hook return 2025-10-27 12:09:49 +01:00
Ryad ABANI
38980a935c FIX: Email Collector Module: manage error when imap_fetchstructure return false. Previously it generated warning and fatal error because the returned value was not of type class 2025-10-22 11:56:07 +02:00
Laurent Destailleur
1eed0e18a9 Update CMailFile.class.php 2025-10-21 02:11:56 +02:00
Laurent Destailleur
2153dbb0f1 Update CMailFile.class.php 2025-10-21 02:09:51 +02:00
Ryad ABANI
52446678d0 FIX: php8.1 warning in syslog message 2025-10-20 16:23:22 +02:00
tnegre
66d72d0bba FIX allow a situation with credit to be removed from cycle 2025-10-17 14:13:25 +02:00
Marc de Lima Lucio
403dad1660 FIX: expense report card: do not show bank account if user cannot see them 2025-10-17 13:56:07 +02:00
Regis Houssin
12d078c651 FIXX clean code 2025-10-16 19:33:38 +02:00
Regis Houssin
0dbbd453e5 FIX Multicompany compatibility with "project_task" 2025-10-16 19:10:32 +02:00
tnegre
8ddf9f6075 FIX : remove useless condition to create credit on situation invoice (#35786) 2025-10-16 11:57:49 +02:00
49 changed files with 609 additions and 381 deletions

24
.github/workflows/ci-on-release.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: "CI-RELEASE"
on:
release:
types: [published]
jobs:
trigger-docker:
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ vars.RELEASE_DOCKER_ID }}
private-key: ${{ secrets.RELEASE_DOCKER_SECRET }}
- uses: peter-evans/repository-dispatch@v4
with:
token: ${{ steps.generate-token.outputs.token }}
repository: Dolibarr/dolibarr-docker
event-type: new-release
client-payload: '{"version": "${{ github.event.release.tag_name }}"}'

View File

@@ -181,7 +181,7 @@ class AccountancyExport
);
global $hookmanager;
$code = $formatcode[$type];
$code = $formatcode[$type] ?? '';
$parameters = array('type' => $type);
$reshook = $hookmanager->executeHooks('getFormatCode', $parameters, $code);

View File

@@ -57,7 +57,20 @@ class DolibarrApi
Defaults::$cacheDirectory = $cachedir;
$this->db = $db;
$production_mode = (!getDolGlobalString('API_PRODUCTION_MODE') ? false : true);
$production_mode = (getDolGlobalString('API_PRODUCTION_MODE') ? true : false);
if ($production_mode) {
// Create the directory Defaults::$cacheDirectory if it does not exist. If dir does not exist, using production_mode generates an error 500.
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
if (!dol_is_dir(Defaults::$cacheDirectory)) {
dol_mkdir(Defaults::$cacheDirectory, DOL_DATA_ROOT);
}
if (getDolGlobalString('MAIN_API_DEBUG')) {
dol_syslog("Debug API construct::cacheDirectory=".Defaults::$cacheDirectory, LOG_DEBUG, 0, '_api');
}
}
$this->r = new Restler($production_mode, $refreshCache);
$urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));

View File

@@ -410,6 +410,11 @@ if (empty($reshook) && $action == 'add') {
if (!empty($_SESSION['assignedtouser'])) {
$listofuserid = json_decode($_SESSION['assignedtouser'], true);
}
if (!empty($_SESSION['assignedtoresource'])) {
$listofresourceid = json_decode($_SESSION['assignedtoresource'], true);
}
$i = 0;
foreach ($listofuserid as $key => $value) {
if ($i == 0) { // First entry
@@ -520,22 +525,95 @@ if (empty($reshook) && $action == 'add') {
// Creation of action/event
$idaction = $object->create($user);
$moreparam = '';
if ($idaction > 0) {
if (!$object->error) {
if (is_array($listofresourceid) && count($listofresourceid)) {
foreach ($listofresourceid as $resource_id => $val) {
$resource_type = 'dolresource';
$busy = 1;//GETPOSTINT('busy');
// Resources association
if (getDolGlobalString('RESOURCE_USED_IN_EVENT_CHECK')) {
$eventDateStart = $object->datep;
$eventDateEnd = $object->datef;
$isFullDayEvent = $object->fulldayevent;
if (empty($eventDateEnd)) {
if ($isFullDayEvent) {
$eventDateStartArr = dol_getdate($eventDateStart);
$eventDateStart = dol_mktime(0, 0, 0, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
$eventDateEnd = dol_mktime(23, 59, 59, $eventDateStartArr['mon'], $eventDateStartArr['mday'], $eventDateStartArr['year']);
}
}
$sql = "SELECT er.rowid, r.ref as r_ref, ac.id as ac_id, ac.label as ac_label";
$sql .= " FROM " . MAIN_DB_PREFIX . "element_resources as er";
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "resource as r ON r.rowid = er.resource_id AND er.resource_type = '" . $db->escape($resource_type) . "'";
$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "actioncomm as ac ON ac.id = er.element_id AND er.element_type = '" . $db->escape($object->element) . "'";
$sql .= " WHERE er.resource_id = " . ((int) $resource_id);
$sql .= " AND er.busy = 1";
$sql .= " AND (";
// event date start between ac.datep and ac.datep2 (if datep2 is null we consider there is no end)
$sql .= " (ac.datep <= '" . $db->idate($eventDateStart) . "' AND (ac.datep2 IS NULL OR ac.datep2 >= '" . $db->idate($eventDateStart) . "'))";
// event date end between ac.datep and ac.datep2
if (!empty($eventDateEnd)) {
$sql .= " OR (ac.datep <= '" . $db->idate($eventDateEnd) . "' AND (ac.datep2 >= '" . $db->idate($eventDateEnd) . "'))";
}
// event date start before ac.datep and event date end after ac.datep2
$sql .= " OR (";
$sql .= "ac.datep >= '" . $db->idate($eventDateStart) . "'";
if (!empty($eventDateEnd)) {
$sql .= " AND (ac.datep2 IS NOT NULL AND ac.datep2 <= '" . $db->idate($eventDateEnd) . "')";
}
$sql .= ")";
$sql .= ")";
$resql = $db->query($sql);
if (!$resql) {
$error++;
$object->error = $db->lasterror();
$object->errors[] = $object->error;
} else {
if ($db->num_rows($resql) > 0) {
// Resource already in use
$error++;
$object->error = $langs->trans('ErrorResourcesAlreadyInUse') . ' : ';
while ($obj = $db->fetch_object($resql)) {
$object->error .= '<br> - ' . $langs->trans('ErrorResourceUseInEvent', $obj->r_ref, $obj->ac_label . ' [' . $obj->ac_id . ']');
}
$object->errors[] = $object->error;
setEventMessages($object->error, null, 'errors');
}
$db->free($resql);
}
}
if (!$error) {
$res = $object->add_element_resource($resource_id, $resource_type, $busy, $val['mandatory']);
}
}
}
unset($_SESSION['assignedtoresource']);
// Category association
$categories = GETPOST('categories', 'array');
$object->setCategories($categories);
if (!$error) {
$categories = GETPOST('categories', 'array');
$object->setCategories($categories);
}
unset($_SESSION['assignedtouser']);
$moreparam = '';
if ($user->id != $object->userownerid) {
$moreparam = "filtert=-1"; // We force to remove filter so created record is visible when going back to per user view.
}
// Create reminders
if ($addreminder == 'on') {
if (!$error && $addreminder == 'on') {
$actionCommReminder = new ActionCommReminder($db);
$dateremind = dol_time_plus_duree($datep, -1 * $offsetvalue, $offsetunit);
@@ -606,7 +684,9 @@ if (empty($reshook) && $action == 'add') {
$donotclearsession = 1;
}
if ($eventisrecurring) {
if (!$error && $eventisrecurring) {
$dayoffset = 0;
$monthoffset = 0;
// We set first date of recurrence and offsets
if ($selectedrecurrulefreq == 'WEEKLY' && !empty($selectedrecurrulebyday)) {
$firstdatearray = dol_get_first_day_week(GETPOST("apday", 'int'), GETPOST("apmonth", 'int'), GETPOST("apyear", 'int'));

View File

@@ -18,6 +18,7 @@
* Copyright (C) 2022 ATM Consulting <contact@atm-consulting.fr>
* Copyright (C) 2022 OpenDSI <support@open-dsi.fr>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* Copyright (C) 2025 William Mead <william@m34d.com>
*
* 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
@@ -1770,12 +1771,14 @@ class Propal extends CommonObject
$sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
$sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
$sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
$sql .= " fk_user_valid=".(isset($this->user_validation_id) ? $this->user_validation_id : "null").",";
$sql .= " fk_user_valid = ".(!empty($this->user_validation_id) ? (int) $this->user_validation_id : "null").",";
$sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
$sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
$sql .= " deposit_percent=".(!empty($this->deposit_percent) ? "'".$this->db->escape($this->deposit_percent)."'" : "null").",";
$sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").",";
$sql .= " fk_input_reason=".(isset($this->demand_reason_id) ? $this->demand_reason_id : "null").",";
$sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? (int) $this->shipping_method_id : "null").",";
$sql .= " fk_availability=".(isset($this->availability_id) ? (int) $this->availability_id : "null").",";
$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 .= " model_pdf=".(isset($this->model_pdf) ? "'".$this->db->escape($this->model_pdf)."'" : "null").",";
@@ -2066,7 +2069,6 @@ class Propal extends CommonObject
$this->ref = $num;
$this->statut = self::STATUS_VALIDATED;
$this->status = self::STATUS_VALIDATED;
$this->user_validation_id = $user->id;
$this->datev = $now;
$this->date_validation = $now;

View File

@@ -1733,25 +1733,25 @@ if (empty($reshook)) {
// Date start
$date_start = false;
if ($lines[$i]->date_debut_prevue) {
if (isset($lines[$i]->date_debut_prevue)) {
$date_start = $lines[$i]->date_debut_prevue;
}
if ($lines[$i]->date_debut_reel) {
if (isset($lines[$i]->date_debut_reel)) {
$date_start = $lines[$i]->date_debut_reel;
}
if ($lines[$i]->date_start) {
if (isset($lines[$i]->date_start)) {
$date_start = $lines[$i]->date_start;
}
// Date end
$date_end = false;
if ($lines[$i]->date_fin_prevue) {
if (isset($lines[$i]->date_fin_prevue)) {
$date_end = $lines[$i]->date_fin_prevue;
}
if ($lines[$i]->date_fin_reel) {
if (isset($lines[$i]->date_fin_reel)) {
$date_end = $lines[$i]->date_fin_reel;
}
if ($lines[$i]->date_end) {
if (isset($lines[$i]->date_end)) {
$date_end = $lines[$i]->date_end;
}
@@ -5095,6 +5095,7 @@ if ($action == 'create') {
print '<td>'.$langs->trans('ListOfSituationInvoices').'</td>';
print '<td></td>';
print '<td class="center">'.$langs->trans('Situation').'</td>';
if (isModEnabled("banque")) {
print '<td class="right"></td>';
}
@@ -5186,7 +5187,9 @@ if ($action == 'create') {
$total_next_ht = $total_next_ttc = 0;
foreach ($object->tab_next_situation_invoice as $next_invoice) {
$totalpaid = $next_invoice->getSommePaiement();
$next_invoice_total_paid = $next_invoice->getSommePaiement(0);
$next_invoice_totalcreditnotes = $next_invoice->getSumCreditNotesUsed(0);
$next_invoice_totaldeposits = $next_invoice->getSumDepositsUsed(0);
$total_next_ht += $next_invoice->total_ht;
$total_next_ttc += $next_invoice->total_ttc;
@@ -5199,7 +5202,7 @@ if ($action == 'create') {
}
print '<td class="right"><span class="amount">'.price($next_invoice->total_ht).'</span></td>';
print '<td class="right"><span class="amount">'.price($next_invoice->total_ttc).'</span></td>';
print '<td class="right">'.$next_invoice->getLibStatut(3, $totalpaid).'</td>';
print '<td class="right">'.$next_invoice->getLibStatut(3, $next_invoice_total_paid + $next_invoice_totalcreditnotes + $next_invoice_totaldeposits).'</td>';
print '</tr>';
}
@@ -5859,10 +5862,9 @@ if ($action == 'create') {
}
}
// For situation invoice with excess received
// For situation invoice
if ($object->statut > Facture::STATUS_DRAFT
&& $object->type == Facture::TYPE_SITUATION
&& ($object->total_ttc - $totalpaid - $totalcreditnotes - $totaldeposits) > 0
&& $usercancreate
&& !$objectidnext
&& $object->is_last_in_cycle()

View File

@@ -68,9 +68,9 @@ if (!$sortfield) {
}
$object = new Facture($db);
if ($object->fetch($id, $ref)) {
if ($object->fetch($id, $ref) > 0) {
$object->fetch_thirdparty();
$upload_dir = $conf->facture->dir_output."/".dol_sanitizeFileName($object->ref);
$upload_dir = $conf->facture->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
}
$permissiontoadd = $user->hasRight('facture', 'creer');
@@ -119,7 +119,6 @@ if ($id > 0 || !empty($ref)) {
if ($object->fetch($id, $ref) > 0) {
$object->fetch_thirdparty();
$upload_dir = $conf->facture->multidir_output[$object->entity].'/'.dol_sanitizeFileName($object->ref);
$head = facture_prepare_head($object);
print dol_get_fiche_head($head, 'documents', $langs->trans('InvoiceCustomer'), -1, 'bill');

View File

@@ -293,16 +293,19 @@ if ($modecompta == 'BOOKKEEPING') {
if ($showaccountdetail == 'no') {
$sql .= ", f.thirdparty_code as name";
}
$sql .= " FROM ".MAIN_DB_PREFIX."accounting_bookkeeping as f";
$sql .= ", ".MAIN_DB_PREFIX."accounting_account as aa";
$sql .= " WHERE f.numero_compte = aa.account_number";
$sql .= " FROM ".$db->prefix()."accounting_bookkeeping as f";
$sql .= " INNER JOIN ".$db->prefix()."accounting_account as aa";
$sql .= " ON aa.account_number = f.numero_compte";
$sql .= " AND aa.entity = f.entity"; // Security prevents duplicate.
$sql .= " WHERE 1=1";
$sql .= " AND ".$predefinedgroupwhere;
$sql .= " AND fk_pcg_version = '".$db->escape($charofaccountstring)."'";
$sql .= " AND aa.fk_pcg_version = '".$db->escape($charofaccountstring)."'";
$sql .= " AND f.entity = ".$conf->entity;
if (!empty($date_start) && !empty($date_end)) {
$sql .= " AND f.doc_date >= '".$db->idate($date_start)."' AND f.doc_date <= '".$db->idate($date_end)."'";
$sql .= " AND f.doc_date >= '".$db->idate($date_start)."'";
$sql .= " AND f.doc_date <= '".$db->idate($date_end)."'";
}
$sql .= " GROUP BY pcg_type";
$sql .= " GROUP BY aa.pcg_type";
if ($showaccountdetail == 'no') {
$sql .= ", name, socid"; // group by "accounting group" (INCOME/EXPENSE), then "customer".
}

View File

@@ -358,7 +358,7 @@ if ($action == "update_extras" && GETPOST('id', 'int') > 0 && !empty($permission
$object->oldcopy = dol_clone($object, 2);
$attribute = GETPOST('attribute', 'alphanohtml');
$attribute = GETPOST('attribute', 'aZ09');
$error = 0;

View File

@@ -325,7 +325,7 @@ class CMailFile
foreach ($filename_list as $i => $val) {
if ($filename_list[$i]) {
$this->atleastonefile = 1;
dol_syslog("CMailFile::CMailfile: filename_list[$i]=".$filename_list[$i].", mimetype_list[$i]=".$mimetype_list[$i]." mimefilename_list[$i]=".$mimefilename_list[$i]." cid_list[$i]=".$cid_list[$i], LOG_DEBUG);
dol_syslog("CMailFile::CMailfile: filename_list[$i]=".$filename_list[$i].", mimetype_list[$i]=".$mimetype_list[$i]." mimefilename_list[$i]=".$mimefilename_list[$i]." cid_list[$i]=".(empty($cid_list[$i]) ? '' : $cid_list[$i]), LOG_DEBUG);
}
}
}

View File

@@ -15,7 +15,7 @@
* Copyright (C) 2012-2016 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
* Copyright (C) 2012-2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* Copyright (C) 2014-2023 Alexandre Spangaro <aspangaro@open-dsi.fr>
* Copyright (C) 2014-2026 Alexandre Spangaro <alexandre@inovea-conseil.com>
* Copyright (C) 2018-2022 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
@@ -6446,7 +6446,7 @@ class Form
if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) {
$langs->load("errors");
$new_country_code = $reg[1];
$country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid');
$country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid');
$this->error .= '<br>'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : ''));
}
$this->error .= '</span>';
@@ -8232,6 +8232,8 @@ class Form
if ($tmpfieldstoshow) {
$fieldstoshow = $tmpfieldstoshow;
}
} elseif ($objecttmp->element === 'category') {
$fieldstoshow = 't.label';
} else {
// For backward compatibility
$objecttmp->fields['ref'] = array('type' => 'varchar(30)', 'label' => 'Ref', 'showoncombobox' => 1);

View File

@@ -261,7 +261,6 @@ class FormSetup
$this->errors = $hookmanager->errors;
return -1;
}
if ($reshook > 0) {
return $reshook;
}

View File

@@ -667,7 +667,7 @@ class TimeSpent extends CommonObject
if (isset($this->status)) {
$datas['picto'] .= ' '.$this->getLibStatut(5);
}
$datas['ref'] .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
$datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
return $datas;
}

View File

@@ -13641,8 +13641,8 @@ function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
{
if ($hourTime === 'getpost') {
$hour = GETPOSTINT($prefix . 'hour');
$minute = GETPOSTINT($prefix . 'minute');
$second = GETPOSTINT($prefix . 'second');
$minute = GETPOSTINT($prefix . 'min');
$second = GETPOSTINT($prefix . 'sec');
} elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
$hour = intval($m[1]);
$minute = intval($m[2]);
@@ -13681,8 +13681,8 @@ function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto'
if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
$TParam = array_merge($TParam, array(
$prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
$prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
$prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
$prefix . 'min' => intval(dol_print_date($timestamp, '%M')),
$prefix . 'sec' => intval(dol_print_date($timestamp, '%S'))
));
}

View File

@@ -108,6 +108,9 @@ function facture_prepare_head($object)
require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/link.class.php';
$upload_dir = $conf->facture->dir_output."/".dol_sanitizeFileName($object->ref);
if (!empty($conf->facture->multidir_output[$object->entity])) {
$upload_dir = $conf->facture->multidir_output[$object->entity]."/".dol_sanitizeFileName($object->ref);
}
$nbFiles = count(dol_dir_list($upload_dir, 'files', 0, '', '(\.meta|_preview.*\.png)$'));
$nbLinks = Link::count($db, $object->element, $object->id);
$head[$h][0] = DOL_URL_ROOT.'/compta/facture/document.php?id='.$object->id;

View File

@@ -444,6 +444,10 @@ function restrictedArea(User $user, $features, $object = 0, $tableandshare = '',
$tableandshare = 'paiementcharge';
$parentfortableentity = 'fk_charge@chargesociales';
}
if ($features == 'evaluation') {
$features = 'hrm';
$feature2 = 'evaluation';
}
//print $features.' - '.$tableandshare.' - '.$feature2.' - '.$dbt_select."\n";
@@ -882,8 +886,11 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
if ($feature == 'project') {
$feature = 'projet';
}
if ($feature == 'task') {
$feature = 'projet_task';
if ($feature == 'projet' && !empty($feature2) && is_array($feature2) && !empty(array_intersect(array('project_task', 'projet_task'), $feature2))) {
$feature = 'project_task';
}
if ($feature == 'task' || $feature == 'projet_task') {
$feature = 'project_task';
}
if ($feature == 'eventorganization') {
$feature = 'agenda';
@@ -900,14 +907,14 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
$checkonentitydone = 0;
// Array to define rules of checks to do
$check = array('adherent', 'banque', 'bom', 'don', 'mrp', 'user', 'usergroup', 'payment', 'payment_supplier', 'payment_sc', 'product', 'produit', 'service', 'produit|service', 'categorie', 'resource', 'expensereport', 'holiday', 'salaries', 'website', 'recruitment', 'chargesociales', 'knowledgemanagement'); // Test on entity only (Objects with no link to company)
$check = array('adherent', 'banque', 'bom', 'don', 'mrp', 'user', 'usergroup', 'payment', 'payment_supplier', 'payment_sc', 'product', 'produit', 'service', 'produit|service', 'categorie', 'resource', 'expensereport', 'holiday', 'salaries', 'website', 'recruitment', 'chargesociales', 'knowledgemanagement', 'stock'); // Test on entity only (Objects with no link to company)
$checksoc = array('societe'); // Test for object Societe
$checkparentsoc = array('agenda', 'contact', 'contrat'); // Test on entity + link to third party on field $dbt_keyfield. Allowed if link is empty (Ex: contacts...).
$checkproject = array('projet', 'project'); // Test for project object
$checktask = array('projet_task'); // Test for task object
$checkhierarchy = array('expensereport', 'holiday'); // check permission among the hierarchy of user
$checktask = array('projet_task', 'project_task'); // Test for task object
$checkhierarchy = array('expensereport', 'holiday', 'hrm'); // check permission among the hierarchy of user
$checkuser = array('bookmark'); // check permission among the fk_user (must be myself or null)
$nocheck = array('barcode', 'stock'); // No test
$nocheck = array('barcode'); // No test
//$checkdefault = 'all other not already defined'; // Test on entity + link to third party on field $dbt_keyfield. Not allowed if link is empty (Ex: invoice, orders...).
@@ -1039,6 +1046,7 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
return false;
}
} else {
$sharedelement = 'project'; // for multicompany compatibility
$sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
$sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
$sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
@@ -1122,6 +1130,20 @@ function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tabl
}
}
}
if ($feature == 'hrm' && in_array('evaluation', $feature2)) {
$useridtocheck = $object->fk_user;
if ($user->hasRight('hrm', 'evaluation', 'readall')) {
// the user can view evaluations for anyone
return true;
}
if (!$user->hasRight('hrm', 'evaluation', 'read')) {
// the user can't view any evaluations
return false;
}
// the user can only their own evaluations or their subordinates'
return in_array($useridtocheck, $childids);
}
}
// For some object, we also have to check it is public or owned by user

View File

@@ -2,6 +2,7 @@
/* Copyright (C) 2013-2018 Jean-François FERRY <hello@librethic.io>
* Copyright (C) 2016 Christophe Battarel <christophe@altairis.fr>
* Copyright (C) 2019-2022 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2025 Benjamin Falière <benjamin@faliere.com>
*
* 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
@@ -261,7 +262,7 @@ function llxHeaderTicket($title, $head = "", $disablejs = 0, $disablehead = 0, $
print '</div>';
}
if (getDolGlobalInt('TICKET_IMAGE_PUBLIC_INTERFACE')) {
if (getDolGlobalString('TICKET_IMAGE_PUBLIC_INTERFACE')) {
print '<div class="backimagepublicticket">';
print '<img id="idTICKET_IMAGE_PUBLIC_INTERFACE" src="'.getDolGlobalString('TICKET_IMAGE_PUBLIC_INTERFACE').'">';
print '</div>';

View File

@@ -379,6 +379,19 @@ class pdf_crabe extends ModelePDFFactures
$this->atleastonediscount++;
}
// determine category of operation
$is_deposit = false;
if (preg_match('/^\((.*)\)$/', $object->lines[$i]->desc, $reg)) {
if ($reg[1] == 'DEPOSIT') {
$is_deposit = true;
}
}
// If DEPOSIT, this line is completely ignored for calculations.
if ($is_deposit) {
continue;
}
// determine category of operation
if ($categoryOfOperation < 2) {
$lineProductType = $object->lines[$i]->product_type;

View File

@@ -404,6 +404,19 @@ class pdf_sponge extends ModelePDFFactures
$this->atleastonediscount++;
}
// Do not take into account lines of the type “deposit.”
$is_deposit = false;
if (preg_match('/^\((.*)\)$/', $object->lines[$i]->desc, $reg)) {
if ($reg[1] == 'DEPOSIT') {
$is_deposit = true;
}
}
// If DEPOSIT, this line is completely ignored for calculations.
if ($is_deposit) {
continue;
}
// determine category of operation
if ($categoryOfOperation < 2) {
$lineProductType = $object->lines[$i]->product_type;

View File

@@ -362,8 +362,9 @@ class modAdherent extends DolibarrModules
$this->import_convertvalue_array[$r] = array(
'a.ref'=>array(
'rule'=>'getrefifauto',
'class'=>(!getDolGlobalString('MEMBER_ADDON') ? 'mod_member_simple' : $conf->global->MEMBER_ADDON),
'path'=>"/core/modules/member/".(!getDolGlobalString('MEMBER_ADDON') ? 'mod_member_simple' : $conf->global->MEMBER_ADDON).'.php'
'class'=>(!getDolGlobalString('MEMBER_CODEMEMBER_ADDON') ? 'mod_member_simple' : $conf->global->MEMBER_CODEMEMBER_ADDON),
'path'=>"/core/modules/member/".(!getDolGlobalString('MEMBER_CODEMEMBER_ADDON') ? 'mod_member_simple' : $conf->global->MEMBER_CODEMEMBER_ADDON).'.php'
),
'a.state_id' => array(
'rule' => 'fetchidfromcodeid',

View File

@@ -603,7 +603,8 @@ class modProduct extends DolibarrModules
'p.recuperableonly' => '^[0|1]$',
);
if (isModEnabled('stock')) {//if Stock module enabled
// Complete if Stock module enabled
if (isModEnabled('stock')) {
$this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array(
'p.fk_default_warehouse'=>'DefaultWarehouse',
'p.tobatch'=>'ManageLotSerial',
@@ -914,7 +915,10 @@ class modProduct extends DolibarrModules
if (is_object($mysoc) && $usenpr) {
$this->import_fields_array[$r] = array_merge($this->import_fields_array[$r], array('pr.recuperableonly'=>'NPR'));
}
$this->import_regex_array[$r] = array('pr.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$', 'pr.recuperableonly'=>'^[0|1]$');
$this->import_regex_array[$r] = array(
'pr.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$',
'pr.recuperableonly'=>'^[0|1]$'
);
$this->import_convertvalue_array[$r] = array(
'pr.fk_product'=>array('rule'=>'fetchidfromref', 'classfile'=>'/product/class/product.class.php', 'class'=>'Product', 'method'=>'fetch', 'element'=>'Product')
);

View File

@@ -259,7 +259,7 @@ if (empty($reshook) && !empty($object->table_element) && isset($extrafields->att
} else {
//var_dump($tmpkeyextra.'-'.$value.'-'.$object->table_element);
print $extrafields->showOutputField($tmpkeyextra, $value, '', $object->table_element);
print '<input type="hidden" value="' . $value . '" name="options_' . $tmpkeyextra . '" id="options_' . $tmpkeyextra . '"/>'; // it's needed when to get parent value when extra-field list depend on parent extra-field list
print '<input type="hidden" value="' . dol_escape_htmltag($value) . '" name="options_' . dol_escape_htmltag($tmpkeyextra) . '" id="options_' . dol_escape_htmltag($tmpkeyextra) . '"/>'; // it's needed when to get parent value when extra-field list depend on parent extra-field list
}
print '</td>';

View File

@@ -509,7 +509,7 @@ class InterfaceWorkflowManager extends DolibarrTriggers
if (isModEnabled('contract') && isModEnabled('ticket') && isModEnabled('workflow') && getDolGlobalString('WORKFLOW_TICKET_LINK_CONTRACT') && getDolGlobalString('TICKET_PRODUCT_CATEGORY') && !empty($object->fk_soc)) {
$societe = new Societe($this->db);
$company_ids = (!getDolGlobalString('WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS')) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]);
require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
$contrat = new Contrat($this->db);
$number_contracts_found = 0;
foreach ($company_ids as $company_id) {

View File

@@ -441,7 +441,7 @@ class InterfaceTicketEmail extends DolibarrTriggers
$message_customer .= '<p>'.$langs->trans('Message').' : <br><br>'.$message.'</p><br>';
if (getDolGlobalInt('TICKET_ENABLE_PUBLIC_INTERFACE')) {
$url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.((int) $object->track_id);
$url_public_ticket = getDolGlobalString('TICKET_URL_PUBLIC_INTERFACE', dol_buildpath('/public/ticket/', 2)).'view.php?track_id='.urlencode($object->track_id);
$message_customer .= '<p>'.$langs->trans($see_ticket).' : <a href="'.$url_public_ticket.'">'.$url_public_ticket.'</a></p>';
$message_customer .= '<p>'.$langs->trans('TicketEmailPleaseDoNotReplyToThisEmail').'</p>';
} else {

View File

@@ -858,10 +858,9 @@ class EmailCollector extends CommonObject
{
global $user;
$nberror = 0;
$nbErrors = 0;
$arrayofcollectors = $this->fetchAll($user, 1);
// Loop on each collector
foreach ($arrayofcollectors as $emailcollector) {
$result = $emailcollector->doCollectOneCollector(0);
@@ -870,11 +869,12 @@ class EmailCollector extends CommonObject
$this->error .= 'EmailCollector ID '.$emailcollector->id.':'.$emailcollector->error.'<br>';
if (!empty($emailcollector->errors)) {
$this->error .= join('<br>', $emailcollector->errors);
$nbErrors++;
}
$this->output .= 'EmailCollector ID '.$emailcollector->id.': '.$emailcollector->lastresult.'<br>';
}
return $nberror;
return $nbErrors;
}
/**
@@ -1809,7 +1809,11 @@ class EmailCollector extends CommonObject
$attachments = [];
}
} else {
$this->getmsg($connection, $imapemail); // This set global var $charset, $htmlmsg, $plainmsg, $attachments
$getMsg = $this->getmsg($connection, $imapemail); // This set global var $charset, $htmlmsg, $plainmsg, $attachments
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
}
//print $plainmsg;
//var_dump($plainmsg); exit;
@@ -2983,7 +2987,11 @@ class EmailCollector extends CommonObject
$this->saveAttachment($destdir, $filename, $content);
}
} else {
$this->getmsg($connection, $imapemail, $destdir);
$getMsg = $this->getmsg($connection, $imapemail, $destdir);
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
}
$operationslog .= '<br>Project created with attachments -> id='.dol_escape_htmltag($projecttocreate->id);
@@ -3120,7 +3128,11 @@ class EmailCollector extends CommonObject
$this->saveAttachment($destdir, $filename, $content);
}
} else {
$this->getmsg($connection, $imapemail, $destdir);
$getMsg = $this->getmsg($connection, $imapemail, $destdir);
if ($getMsg < 0) {
$this->errors = array_merge($this->errors, [$this->error]);
return $getMsg;
}
}
$operationslog .= '<br>Ticket created with attachments -> id='.dol_escape_htmltag($tickettocreate->id);
@@ -3407,9 +3419,9 @@ class EmailCollector extends CommonObject
* @param Object $mbox Structure
* @param string $mid UID email
* @param string $destdir Target dir for attachments. Leave blank to parse without writing to disk.
* @return void
* @return int
*/
private function getmsg($mbox, $mid, $destdir = '')
private function getmsg($mbox, $mid, $destdir = ''): int
{
// input $mbox = IMAP stream, $mid = message id
// output all the following:
@@ -3423,9 +3435,12 @@ class EmailCollector extends CommonObject
// BODY
$s = imap_fetchstructure($mbox, $mid, FT_UID);
if ($s === false) {
$this->errors = array_merge($this->errors, [imap_last_error()]);
return -1;
}
if (!$s->parts) {
if (empty($s->parts)) {
// simple
$this->getpart($mbox, $mid, $s, 0); // pass 0 as part-number
} else {
@@ -3434,6 +3449,8 @@ class EmailCollector extends CommonObject
$this->getpart($mbox, $mid, $p, $partno0 + 1, $destdir);
}
}
return 1;
}
/* partno string

View File

@@ -117,12 +117,14 @@ function getDParameters($part)
*/
function getAttachments($jk, $mbox)
{
$structure = imap_fetchstructure($mbox, $jk, FT_UID);
$structure = imap_fetchstructure($mbox, $jk, FT_UID); // @phan-suppress-current-line PhanTypeMismatchArgumentInternal
$parts = getParts($structure);
$fpos = 2;
$attachments = array();
$nb = count($parts);
if ($parts && $nb) {
if (!empty($parts)) {
$nb = count($parts);
for ($i = 1; $i < $nb; $i++) {
$part = $parts[$i];
@@ -139,6 +141,7 @@ function getAttachments($jk, $mbox)
$fpos++;
}
}
return $attachments;
}

View File

@@ -86,6 +86,7 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_elemen
// Load object
include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once.
$upload_dir = $conf->eventorganization->multidir_output[isset($object->entity) ? $object->entity : 1];
if ($id > 0 || !empty($ref)) {
$upload_dir = $conf->eventorganization->multidir_output[$object->entity ? $object->entity : $conf->entity]."/conferenceorbooth/".get_exdir(0, 0, 0, 1, $object);
}
@@ -96,7 +97,6 @@ $permissiontoadd = $user->rights->eventorganization->write; // Used by the inclu
$permissiontodelete = $user->rights->eventorganization->delete || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
$permissionnote = $user->rights->eventorganization->write; // Used by the include of actions_setnotes.inc.php
$permissiondellink = $user->rights->eventorganization->write; // Used by the include of actions_dellink.inc.php
$upload_dir = $conf->eventorganization->multidir_output[isset($object->entity) ? $object->entity : 1];
// Security check
if ($user->socid > 0) {

View File

@@ -1941,9 +1941,10 @@ if ($action == 'create') {
print '</tr>';
// List of payments already done
$canSeeBankAccount = isModEnabled('bank') && $user->hasRight('banque', 'lire');
$nbcols = 3;
$nbrows = 0;
if (isModEnabled("banque")) {
if ($canSeeBankAccount) {
$nbrows++;
$nbcols++;
}
@@ -1954,7 +1955,7 @@ if ($action == 'create') {
print '<td class="liste_titre">'.$langs->trans('Payments').'</td>';
print '<td class="liste_titre">'.$langs->trans('Date').'</td>';
print '<td class="liste_titre">'.$langs->trans('Type').'</td>';
if (isModEnabled("banque")) {
if ($canSeeBankAccount) {
print '<td class="liste_titre right">'.$langs->trans('BankAccount').'</td>';
}
print '<td class="liste_titre right">'.$langs->trans('Amount').'</td>';
@@ -1997,7 +1998,7 @@ if ($action == 'create') {
$labeltype = $langs->trans("PaymentType".$objp->payment_code) != "PaymentType".$objp->payment_code ? $langs->trans("PaymentType".$objp->payment_code) : $objp->payment_type;
print "<td>".$labeltype.' '.$objp->num_payment."</td>\n";
// Bank account
if (isModEnabled("banque")) {
if ($canSeeBankAccount) {
$bankaccountstatic->id = $objp->baid;
$bankaccountstatic->ref = $objp->baref;
$bankaccountstatic->label = $objp->baref;

View File

@@ -606,7 +606,7 @@ class CommandeFournisseur extends CommonOrder
$objsearchpackage = $this->db->fetch_object($resqlsearchpackage);
if ($objsearchpackage) {
$line->fk_fournprice = $objsearchpackage->rowid;
$line->packaging = $objsearchpackage->packaging;
$line->packaging = (float) $objsearchpackage->packaging;
}
} else {
$this->error = $this->db->lasterror();
@@ -1972,14 +1972,14 @@ class CommandeFournisseur extends CommonOrder
// Predefine quantity according to packaging
if (getDolGlobalString('PRODUCT_USE_SUPPLIER_PACKAGING')) {
$prod = new Product($this->db);
$prod->get_buyprice($fk_prod_fourn_price, $qty, $fk_product, 'none', (empty($this->fk_soc) ? $this->socid : $this->fk_soc));
$prod->get_buyprice($fk_prod_fourn_price, (float) $qty, $fk_product, 'none', (empty($this->fk_soc) ? $this->socid : $this->fk_soc));
if ($qty < $prod->packaging) {
$qty = $prod->packaging;
$qty = (float) $prod->packaging;
} else {
if (!empty($prod->packaging) && ($qty % $prod->packaging) > 0) {
$coeff = intval($qty / $prod->packaging) + 1;
$qty = $prod->packaging * $coeff;
if (!empty($prod->packaging) && (fmod((float) $qty, (float) $prod->packaging) > 0.000001)) {
$coeff = intval((float) $qty / $prod->packaging) + 1;
$qty = (float) $prod->packaging * $coeff;
setEventMessages($langs->trans('QtyRecalculatedWithPackaging'), null, 'mesgs');
}
}
@@ -2931,7 +2931,7 @@ class CommandeFournisseur extends CommonOrder
if ($qty < $this->line->packaging) {
$qty = $this->line->packaging;
} else {
if (!empty($this->line->packaging) && ($qty % $this->line->packaging) > 0) {
if (!empty($this->line->packaging) && is_numeric($this->line->packaging) && (float) $this->line->packaging > 0 && (fmod((float) $qty, $this->line->packaging) > 0)) {
$coeff = intval($qty / $this->line->packaging) + 1;
$qty = $this->line->packaging * $coeff;
setEventMessage($langs->trans('QtyRecalculatedWithPackaging'), 'mesgs');
@@ -3824,7 +3824,7 @@ class CommandeFournisseurLigne extends CommonOrderLine
$objsearchpackage = $this->db->fetch_object($resqlsearchpackage);
if ($objsearchpackage) {
$this->fk_fournprice = $objsearchpackage->rowid;
$this->packaging = $objsearchpackage->packaging;
$this->packaging = (float) $objsearchpackage->packaging;
}
} else {
$this->error = $this->db->lasterror();

View File

@@ -899,152 +899,146 @@ class FactureFournisseurRec extends CommonInvoice
return -1;
}
if ($this->suspended == self::STATUS_NOTSUSPENDED) {
$localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
$localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
// Clean vat code
$reg = array();
$vat_src_code = '';
if (preg_match('/\((.*)\)/', $txtva, $reg)) {
$vat_src_code = $reg[1];
$txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
}
// Clean vat code
$reg = array();
$vat_src_code = '';
if (preg_match('/\((.*)\)/', $txtva, $reg)) {
$vat_src_code = $reg[1];
$txtva = preg_replace('/\s*\(.*\)/', '', $txtva); // Remove code into vatrate.
}
// Clean parameters
$fk_product = empty($fk_product) ? 0 : $fk_product;
$label = empty($label) ? '' : $label;
$remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
$qty = price2num($qty);
$pu_ht = price2num($pu_ht);
$pu_ttc = price2num($pu_ttc);
if (!preg_match('/\((.*)\)/', $txtva)) {
$txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
}
$txlocaltax1 = price2num($txlocaltax1);
$txlocaltax2 = price2num($txlocaltax2);
$txtva = !empty($txtva) ? $txtva : 0;
$txlocaltax1 = !empty($txlocaltax1) ? $txlocaltax1 : 0;
$txlocaltax2 = !empty($txlocaltax2) ? $txlocaltax2 : 0;
$info_bits = !empty($info_bits) ? $info_bits : 0;
$info_bits = !empty($info_bits) ? $info_bits : 0;
$pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
// Clean parameters
$fk_product = empty($fk_product) ? 0 : $fk_product;
$label = empty($label) ? '' : $label;
$remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
$qty = price2num($qty);
$pu_ht = price2num($pu_ht);
$pu_ttc = price2num($pu_ttc);
if (!preg_match('/\((.*)\)/', $txtva)) {
$txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
}
$txlocaltax1 = price2num($txlocaltax1);
$txlocaltax2 = price2num($txlocaltax2);
$txtva = !empty($txtva) ? $txtva : 0;
$txlocaltax1 = !empty($txlocaltax1) ? $txlocaltax1 : 0;
$txlocaltax2 = !empty($txlocaltax2) ? $txlocaltax2 : 0;
$info_bits = !empty($info_bits) ? $info_bits : 0;
$info_bits = !empty($info_bits) ? $info_bits : 0;
$pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
// Calcul du total TTC et de la TVA pour la ligne a partir de qty, pu, remise_percent et txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
// Calcul du total TTC et de la TVA pour la ligne a partir de qty, pu, remise_percent et txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
$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);
$total_ht = $tabprice[0];
$total_tva = $tabprice[1];
$total_ttc = $tabprice[2];
$total_localtax1 = $tabprice[9];
$total_localtax2 = $tabprice[10];
$pu_ht = $tabprice[3];
$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);
$total_ht = $tabprice[0];
$total_tva = $tabprice[1];
$total_ttc = $tabprice[2];
$total_localtax1 = $tabprice[9];
$total_localtax2 = $tabprice[10];
$pu_ht = $tabprice[3];
// MultiCurrency
$multicurrency_total_ht = $tabprice[16];
$multicurrency_total_tva = $tabprice[17];
$multicurrency_total_ttc = $tabprice[18];
$pu_ht_devise = $tabprice[19];
$this->db->begin();
$product_type = $type;
if ($fk_product) {
$product = new Product($this->db);
$result = $product->fetch($fk_product);
if ($result < 0) {
return -1;
}
$product_type = $product->type;
if (empty($label)) {
$label = $product->label;
}
}
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec (';
$sql .= 'fk_facture_fourn';
$sql .= ', fk_product';
$sql .= ', ref';
$sql .= ', label';
$sql .= ', description';
$sql .= ', pu_ht';
$sql .= ', pu_ttc';
$sql .= ', qty';
$sql .= ', remise_percent';
$sql .= ', fk_remise_except';
$sql .= ', vat_src_code';
$sql .= ', tva_tx';
$sql .= ', localtax1_tx';
$sql .= ', localtax1_type';
$sql .= ', localtax2_tx';
$sql .= ', localtax2_type';
$sql .= ', total_ht';
$sql .= ', total_tva';
$sql .= ', total_localtax1';
$sql .= ', total_localtax2';
$sql .= ', total_ttc';
$sql .= ', product_type';
$sql .= ', date_start';
$sql .= ', date_end';
$sql .= ', info_bits';
$sql .= ', special_code';
$sql .= ', rang';
$sql .= ', fk_unit';
$sql .= ', fk_user_author';
$sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
$sql .= ') VALUES (';
$sql .= ' ' . (int) $facid; // source supplier invoice id
$sql .= ', ' . (!empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : 'null');
$sql .= ', ' . (!empty($ref) ? "'" . $this->db->escape($ref) . "'" : 'null');
$sql .= ', ' . (!empty($label) ? "'" . $this->db->escape($label) . "'" : 'null');
$sql .= ", '" . $this->db->escape($desc) . "'";
$sql .= ', ' . price2num($pu_ht);
$sql .= ', ' . price2num($pu_ttc);
$sql .= ', ' . price2num($qty);
$sql .= ', ' . price2num($remise_percent);
$sql .= ', null';
$sql .= ", '" . $this->db->escape($vat_src_code) . "'";
$sql .= ', ' . price2num($txtva);
$sql .= ', ' . price2num($txlocaltax1);
$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 .= ', ' . price2num($total_ht);
$sql .= ', ' . price2num($total_tva);
$sql .= ', ' . price2num($total_localtax1);
$sql .= ', ' . price2num($total_localtax2);
$sql .= ', ' . price2num($total_ttc);
$sql .= ', ' . (int) $product_type;
$sql .= ', ' . ($date_start > 0 ? (int) $date_start : 'NULL');
$sql .= ', ' . ($date_end > 0 ? (int) $date_end : 'NULL');
$sql .= ', ' . (int) $info_bits;
$sql .= ', ' . (int) $special_code;
$sql .= ', ' . (int) $rang;
$sql .= ', ' . ($fk_unit ? (int) $fk_unit : 'NULL');
$sql .= ', ' . (int) $user->id;
$sql .= ', ' . (int) $this->fk_multicurrency;
$sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
$sql .= ', ' . price2num($pu_ht_devise, 'CU');
$sql .= ', ' . price2num($multicurrency_total_ht, 'CT');
$sql .= ', ' . price2num($multicurrency_total_tva, 'CT');
$sql .= ', ' . price2num($multicurrency_total_ttc, 'CT');
$sql .= ')';
dol_syslog(get_class($this). '::addline', LOG_DEBUG);
if ($this->db->query($sql)) {
$lineId = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_det_rec');
$this->update_price();
$this->id = $facid;
$this->db->commit();
return $lineId;
} else {
$this->db->rollback();
$this->error = $this->db->lasterror();
// MultiCurrency
$multicurrency_total_ht = $tabprice[16];
$multicurrency_total_tva = $tabprice[17];
$multicurrency_total_ttc = $tabprice[18];
$pu_ht_devise = $tabprice[19];
$this->db->begin();
$product_type = $type;
if ($fk_product) {
$product = new Product($this->db);
$result = $product->fetch($fk_product);
if ($result < 0) {
return -1;
}
$product_type = $product->type;
if (empty($label)) {
$label = $product->label;
}
}
$sql = 'INSERT INTO ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec (';
$sql .= 'fk_facture_fourn';
$sql .= ', fk_product';
$sql .= ', ref';
$sql .= ', label';
$sql .= ', description';
$sql .= ', pu_ht';
$sql .= ', pu_ttc';
$sql .= ', qty';
$sql .= ', remise_percent';
$sql .= ', fk_remise_except';
$sql .= ', vat_src_code';
$sql .= ', tva_tx';
$sql .= ', localtax1_tx';
$sql .= ', localtax1_type';
$sql .= ', localtax2_tx';
$sql .= ', localtax2_type';
$sql .= ', total_ht';
$sql .= ', total_tva';
$sql .= ', total_localtax1';
$sql .= ', total_localtax2';
$sql .= ', total_ttc';
$sql .= ', product_type';
$sql .= ', date_start';
$sql .= ', date_end';
$sql .= ', info_bits';
$sql .= ', special_code';
$sql .= ', rang';
$sql .= ', fk_unit';
$sql .= ', fk_user_author';
$sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
$sql .= ') VALUES (';
$sql .= ' ' . (int) $facid; // source supplier invoice id
$sql .= ', ' . (!empty($fk_product) ? "'" . $this->db->escape($fk_product) . "'" : 'null');
$sql .= ', ' . (!empty($ref) ? "'" . $this->db->escape($ref) . "'" : 'null');
$sql .= ', ' . (!empty($label) ? "'" . $this->db->escape($label) . "'" : 'null');
$sql .= ", '" . $this->db->escape($desc) . "'";
$sql .= ', ' . price2num($pu_ht);
$sql .= ', ' . price2num($pu_ttc);
$sql .= ', ' . price2num($qty);
$sql .= ', ' . price2num($remise_percent);
$sql .= ', null';
$sql .= ", '" . $this->db->escape($vat_src_code) . "'";
$sql .= ', ' . price2num($txtva);
$sql .= ', ' . price2num($txlocaltax1);
$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 .= ', ' . price2num($total_ht);
$sql .= ', ' . price2num($total_tva);
$sql .= ', ' . price2num($total_localtax1);
$sql .= ', ' . price2num($total_localtax2);
$sql .= ', ' . price2num($total_ttc);
$sql .= ', ' . (int) $product_type;
$sql .= ', ' . ($date_start > 0 ? (int) $date_start : 'NULL');
$sql .= ', ' . ($date_end > 0 ? (int) $date_end : 'NULL');
$sql .= ', ' . (int) $info_bits;
$sql .= ', ' . (int) $special_code;
$sql .= ', ' . (int) $rang;
$sql .= ', ' . ($fk_unit ? (int) $fk_unit : 'NULL');
$sql .= ', ' . (int) $user->id;
$sql .= ', ' . (int) $this->fk_multicurrency;
$sql .= ", '" . $this->db->escape($this->multicurrency_code) . "'";
$sql .= ', ' . price2num($pu_ht_devise, 'CU');
$sql .= ', ' . price2num($multicurrency_total_ht, 'CT');
$sql .= ', ' . price2num($multicurrency_total_tva, 'CT');
$sql .= ', ' . price2num($multicurrency_total_ttc, 'CT');
$sql .= ')';
dol_syslog(get_class($this). '::addline', LOG_DEBUG);
if ($this->db->query($sql)) {
$lineId = $this->db->last_insert_id(MAIN_DB_PREFIX. 'facture_fourn_det_rec');
$this->update_price();
$this->id = $facid;
$this->db->commit();
return $lineId;
} else {
$this->error = 'Recurring Invoice is suspended. adding lines not allowed.';
$this->db->rollback();
$this->error = $this->db->lasterror();
return -1;
}
@@ -1091,113 +1085,110 @@ class FactureFournisseurRec extends CommonInvoice
return -1;
}
if ($this->status == self::STATUS_SUSPENDED) {
// Clean parameters
$fk_product = empty($fk_product) ? 0 : $fk_product;
$label = empty($label) ? '' : $label;
$remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
$qty = price2num($qty);
$info_bits = empty($info_bits) ? 0 : $info_bits;
$pu_ht = price2num($pu_ht);
$pu_ttc = price2num($pu_ttc);
$pu_ht_devise = price2num($pu_ht_devise);
// Clean parameters
$fk_product = empty($fk_product) ? 0 : $fk_product;
$label = empty($label) ? '' : $label;
$remise_percent = empty($remise_percent) ? 0 : price2num($remise_percent);
$qty = price2num($qty);
$info_bits = empty($info_bits) ? 0 : $info_bits;
$pu_ht = price2num($pu_ht);
$pu_ttc = price2num($pu_ttc);
$pu_ht_devise = price2num($pu_ht_devise);
if (!preg_match('/\((.*)\)/', $txtva)) {
$txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
}
$txlocaltax1 = empty($txlocaltax1) ? 0 : price2num($txlocaltax1);
$txlocaltax2 = empty($txlocaltax2) ? 0 : price2num($txlocaltax2);
$this->multicurrency_total_ht = empty($this->multicurrency_total_ht) ? 0 : $this->multicurrency_total_ht;
$this->multicurrency_total_tva = empty($this->multicurrency_total_tva) ? 0 : $this->multicurrency_total_tva;
$this->multicurrency_total_ttc = empty($this->multicurrency_total_ttc) ? 0 : $this->multicurrency_total_ttc;
$pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
// Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
$localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
// Clean vat code
$vat_src_code = '';
$reg = array();
if (preg_match('/\((.*)\)/', $txtva, $reg)) {
$vat_src_code = $reg[1];
$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);
$total_ht = $tabprice[0];
$total_tva = $tabprice[1];
$total_ttc = $tabprice[2];
$total_localtax1 = $tabprice[9];
$total_localtax2 = $tabprice[10];
$pu_ht = $tabprice[3];
$pu_tva = $tabprice[4];
$pu_ttc = $tabprice[5];
// MultiCurrency
$multicurrency_total_ht = $tabprice[16];
$multicurrency_total_tva = $tabprice[17];
$multicurrency_total_ttc = $tabprice[18];
$pu_ht_devise = $tabprice[19];
$product_type = $type;
if ($fk_product) {
$product = new Product($this->db);
$result = $product->fetch($fk_product);
$product_type = $product->type;
}
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET';
$sql .= ' fk_facture_fourn = ' . ((int) $facid);
$sql .= ', fk_product = ' . ($fk_product > 0 ? ((int) $fk_product) : 'null');
$sql .= ", ref = '" . $this->db->escape($ref) . "'";
$sql .= ", label = '" . $this->db->escape($label) . "'";
$sql .= ", description = '" . $this->db->escape($desc) . "'";
$sql .= ', pu_ht = ' . price2num($pu_ht);
$sql .= ', qty = ' . price2num($qty);
$sql .= ", remise_percent = '" . price2num($remise_percent) . "'";
$sql .= ", vat_src_code = '" . $this->db->escape($vat_src_code) . "'";
$sql .= ', tva_tx = ' . price2num($txtva);
$sql .= ', localtax1_tx = ' . (float) $txlocaltax1;
$sql .= ", localtax1_type = '" . $this->db->escape($localtaxes_type[0]) . "'";
$sql .= ', localtax2_tx = ' . (float) $txlocaltax2;
$sql .= ", localtax2_type = '" . $this->db->escape($localtaxes_type[2]) . "'";
$sql .= ", total_ht = '" . price2num($total_ht) . "'";
$sql .= ", total_tva = '" . price2num($total_tva) . "'";
$sql .= ", total_localtax1 = '" . price2num($total_localtax1) . "'";
$sql .= ", total_localtax2 = '" . price2num($total_localtax2) . "'";
$sql .= ", total_ttc = '" . price2num($total_ttc) . "'";
$sql .= ', product_type = ' . (int) $product_type;
$sql .= ', date_start = ' . (empty($date_start) ? 'NULL' : (int) $date_start);
$sql .= ', date_end = ' . (empty($date_end) ? 'NULL' : (int) $date_end);
$sql .= ', info_bits = ' . (int) $info_bits;
$sql .= ', special_code = ' . (int) $special_code;
$sql .= ', rang = ' . (int) $rang;
$sql .= ', fk_unit = ' . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : 'null');
$sql .= ', fk_user_modif = ' . (int) $user;
$sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
$sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
$sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
$sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
$sql .= ' WHERE rowid = ' . (int) $rowid;
dol_syslog(get_class($this). '::updateline', LOG_DEBUG);
if ($this->db->query($sql)) {
$this->id = $facid;
$this->update_price();
return 1;
} else {
$this->error = $this->db->lasterror();
return -1;
}
if (!preg_match('/\((.*)\)/', $txtva)) {
$txtva = price2num($txtva); // $txtva can have format '5.0(XXX)' or '5'
}
$txlocaltax1 = empty($txlocaltax1) ? 0 : price2num($txlocaltax1);
$txlocaltax2 = empty($txlocaltax2) ? 0 : price2num($txlocaltax2);
$this->multicurrency_total_ht = empty($this->multicurrency_total_ht) ? 0 : $this->multicurrency_total_ht;
$this->multicurrency_total_tva = empty($this->multicurrency_total_tva) ? 0 : $this->multicurrency_total_tva;
$this->multicurrency_total_ttc = empty($this->multicurrency_total_ttc) ? 0 : $this->multicurrency_total_ttc;
$pu = $price_base_type == 'HT' ? $pu_ht : $pu_ttc;
// Calculate total with, without tax and tax from qty, pu, remise_percent and txtva
// TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
// la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
$localtaxes_type = getLocalTaxesFromRate($txtva, 0, $this->thirdparty, $mysoc);
// Clean vat code
$vat_src_code = '';
$reg = array();
if (preg_match('/\((.*)\)/', $txtva, $reg)) {
$vat_src_code = $reg[1];
$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);
$total_ht = $tabprice[0];
$total_tva = $tabprice[1];
$total_ttc = $tabprice[2];
$total_localtax1 = $tabprice[9];
$total_localtax2 = $tabprice[10];
$pu_ht = $tabprice[3];
$pu_tva = $tabprice[4];
$pu_ttc = $tabprice[5];
// MultiCurrency
$multicurrency_total_ht = $tabprice[16];
$multicurrency_total_tva = $tabprice[17];
$multicurrency_total_ttc = $tabprice[18];
$pu_ht_devise = $tabprice[19];
$product_type = $type;
if ($fk_product) {
$product = new Product($this->db);
$result = $product->fetch($fk_product);
$product_type = $product->type;
}
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'facture_fourn_det_rec SET';
$sql .= ' fk_facture_fourn = ' . ((int) $facid);
$sql .= ', fk_product = ' . ($fk_product > 0 ? ((int) $fk_product) : 'null');
$sql .= ", ref = '" . $this->db->escape($ref) . "'";
$sql .= ", label = '" . $this->db->escape($label) . "'";
$sql .= ", description = '" . $this->db->escape($desc) . "'";
$sql .= ', pu_ht = ' . price2num($pu_ht);
$sql .= ', qty = ' . price2num($qty);
$sql .= ", remise_percent = '" . price2num($remise_percent) . "'";
$sql .= ", vat_src_code = '" . $this->db->escape($vat_src_code) . "'";
$sql .= ', tva_tx = ' . price2num($txtva);
$sql .= ', localtax1_tx = ' . (float) $txlocaltax1;
$sql .= ", localtax1_type = '" . $this->db->escape($localtaxes_type[0]) . "'";
$sql .= ', localtax2_tx = ' . (float) $txlocaltax2;
$sql .= ", localtax2_type = '" . $this->db->escape($localtaxes_type[2]) . "'";
$sql .= ", total_ht = '" . price2num($total_ht) . "'";
$sql .= ", total_tva = '" . price2num($total_tva) . "'";
$sql .= ", total_localtax1 = '" . price2num($total_localtax1) . "'";
$sql .= ", total_localtax2 = '" . price2num($total_localtax2) . "'";
$sql .= ", total_ttc = '" . price2num($total_ttc) . "'";
$sql .= ', product_type = ' . (int) $product_type;
$sql .= ', date_start = ' . (empty($date_start) ? 'NULL' : (int) $date_start);
$sql .= ', date_end = ' . (empty($date_end) ? 'NULL' : (int) $date_end);
$sql .= ', info_bits = ' . (int) $info_bits;
$sql .= ', special_code = ' . (int) $special_code;
$sql .= ', rang = ' . (int) $rang;
$sql .= ', fk_unit = ' . ($fk_unit ? "'" . $this->db->escape($fk_unit) . "'" : 'null');
$sql .= ', fk_user_modif = ' . (int) $user;
$sql .= ', multicurrency_subprice = '.price2num($pu_ht_devise);
$sql .= ', multicurrency_total_ht = '.price2num($multicurrency_total_ht);
$sql .= ', multicurrency_total_tva = '.price2num($multicurrency_total_tva);
$sql .= ', multicurrency_total_ttc = '.price2num($multicurrency_total_ttc);
$sql .= ' WHERE rowid = ' . (int) $rowid;
dol_syslog(get_class($this). '::updateline', LOG_DEBUG);
if ($this->db->query($sql)) {
$this->id = $facid;
$this->update_price();
return 1;
} else {
$this->error = $this->db->lasterror();
return -1;
}
return 0;
}

View File

@@ -1311,7 +1311,7 @@ if (empty($reshook)) {
$num = count($lines);
for ($i = 0; $i < $num; $i++) {
if (empty($lines[$i]->subprice) || $lines[$i]->qty <= 0 || !in_array($lines[$i]->id, $selectedLines)) {
if (empty($lines[$i]->subprice) || $lines[$i]->qty < 0 || !in_array($lines[$i]->id, $selectedLines)) {
continue;
}

View File

@@ -96,8 +96,9 @@ $permissiontoread = $user->rights->hrm->evaluation->read; // Used by the include
// Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
//restrictedArea($user, $object->module, $object->id, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft);
$isdraft = $object->status == Evaluation::STATUS_DRAFT ? 1 : 0;
restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (!isModEnabled('hrm')) {
accessforbidden();
}

View File

@@ -92,8 +92,8 @@ $upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->enti
// Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
$isdraft = ($object->status == Evaluation::STATUS_DRAFT) ? 1 : 0;
restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (!isModEnabled("hrm")) {
accessforbidden();
}

View File

@@ -62,10 +62,8 @@ $permission = $user->rights->hrm->evaluation->write;
// Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
//if (empty($conf->hrm->enabled)) accessforbidden();
//if (!$permissiontoread) accessforbidden();
$isdraft = $object->status == Evaluation::STATUS_DRAFT ? 1 : 0;
restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);

View File

@@ -85,16 +85,12 @@ $permissiontoadd = $user->rights->hrm->evaluation->write; // Used by the includ
$permissiontoread = $user->rights->hrm->evaluation->read;
// Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (empty($conf->hrm->enabled)) {
accessforbidden();
}
if (!$permissiontoread) {
accessforbidden();
}
$isdraft = $object->status == Evaluation::STATUS_DRAFT ? 1 : 0;
restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (!isModEnabled('hrm')) accessforbidden();
if (!$permissiontoread) accessforbidden();
/*

View File

@@ -66,10 +66,10 @@ $permissiontoread = $user->rights->hrm->evaluation->read; // Used by the includ
// Security check (enable the most restrictive one)
//if ($user->socid > 0) accessforbidden();
//if ($user->socid > 0) $socid = $user->socid;
//$isdraft = (($object->status == $object::STATUS_DRAFT) ? 1 : 0);
//restrictedArea($user, $object->element, $object->id, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
//if (empty($conf->hrm->enabled)) accessforbidden();
//if (!$permissiontoread) accessforbidden();
$isdraft = (($object->status == Evaluation::STATUS_DRAFT) ? 1 : 0);
restrictedArea($user, $object->element, $object, $object->table_element, '', 'fk_soc', 'rowid', $isdraft);
if (empty($conf->hrm->enabled)) accessforbidden();
if (!$permissiontoread) accessforbidden();
/*

View File

@@ -840,7 +840,7 @@ IMG;
// using windows libreoffice that must be in path
// using linux/mac libreoffice that must be in path
// Note PHP Config "fastcgi.impersonate=0" must set to 0 - Default is 1
$command ='soffice --headless -env:UserInstallation=file:\''.$conf->user->dir_temp.'/odtaspdf\' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name);
$command ='soffice --headless -env:UserInstallation=file:\''.dol_sanitizePathName($conf->user->dir_temp).'/odtaspdf\' --convert-to pdf --outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name);
} elseif (preg_match('/unoconv/', getDolGlobalString('MAIN_ODT_AS_PDF'))) {
// If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87
@@ -866,17 +866,19 @@ IMG;
// - set shell of user to bash instead of nologin.
// - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back
$command = getDolGlobalString('MAIN_ODT_AS_PDF').' '.escapeshellcmd($name);
$command = getDolGlobalString('MAIN_ODT_AS_PDF').' '.escapeshellarg($name);
//$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name);
} else {
// deprecated old method using odt2pdf.sh (native, jodconverter, ...)
$tmpname=preg_replace('/\.odt/i', '', $name);
if (getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT')) {
$command = getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT').'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($tmpname).' '.(is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF'))?'jodconverter':getDolGlobalString('MAIN_ODT_AS_PDF'));
$command = dol_sanitizePathName(getDolGlobalString('MAIN_DOL_SCRIPTS_ROOT')).'/scripts/odt2pdf/odt2pdf.sh '.escapeshellarg($tmpname).' '.escapeshellarg(is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF')) ? 'jodconverter' : getDolGlobalString('MAIN_ODT_AS_PDF'));
} else {
dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING);
$command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($tmpname).' '.(is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF'))?'jodconverter':getDolGlobalString('MAIN_ODT_AS_PDF'));
$paramodt2pdf = (is_numeric(getDolGlobalString('MAIN_ODT_AS_PDF')) ? 'jodconverter' : getDolGlobalString('MAIN_ODT_AS_PDF'));
$paramodt2pdf = dol_sanitizePathName($paramodt2pdf);
$command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellarg($tmpname).' '.escapeshellarg($paramodt2pdf);
}
}
@@ -884,6 +886,7 @@ IMG;
//$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname;
dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command, LOG_DEBUG);
// TODO Use:
// $outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
// $result = $utils->executeCLI($command, $outputfile); and replace test on $execmethod.
@@ -891,17 +894,17 @@ IMG;
// $errorstring will be $result['output']
$retval=0; $output_arr=array();
if ($execmethod == 1) {
exec($command, $output_arr, $retval);
exec(escapeshellcmd($command), $output_arr, $retval);
}
if ($execmethod == 2) {
$outputfile = DOL_DATA_ROOT.'/odt2pdf.log';
$ok=0;
$handle = fopen($outputfile, 'w');
if ($handle) {
dol_syslog(get_class($this)."Run command ".$command, LOG_DEBUG);
dol_syslog(get_class($this)."escapeshellcmd(command) = ".escapeshellcmd($command), LOG_DEBUG);
fwrite($handle, $command."\n");
$handlein = popen($command, 'r');
$handlein = popen(escapeshellcmd($command), 'r');
while (!feof($handlein)) {
$read = fgets($handlein);
fwrite($handle, $read);
@@ -944,7 +947,7 @@ IMG;
foreach ($output_arr as $line) {
$errorstring.= $line."<br>";
}
throw new OdfException('ODT to PDF convert fail (option MAIN_ODT_AS_PDF is '.$conf->global->MAIN_ODT_AS_PDF.', command was '.$command.', retval='.$retval.') : ' . $errorstring);
throw new OdfException('ODT to PDF convert fail (option MAIN_ODT_AS_PDF is '.getDolGlobalString('MAIN_ODT_AS_PDF').', command was '.$command.', retval='.$retval.') : ' . $errorstring);
}
}
}

View File

@@ -811,7 +811,7 @@ class MyObject extends CommonObject
$datas['ref'] = '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
}
if (property_exists($this, 'label')) {
$datas['ref'] = '<br>'.$langs->trans('Label').':</b> '.$this->label;
$datas['label'] = '<br>'.$langs->trans('Label').':</b> '.$this->label;
}
return $datas;

View File

@@ -250,7 +250,7 @@ if (empty($reshook)) {
$i = 1;
while (GETPOSTISSET('qty-'.$line->id.'-'.$i)) {
$qtytoprocess = price2num(GETPOST('qty-'.$line->id.'-'.$i));
$qtytoprocess = (float) price2num(GETPOST('qty-'.$line->id.'-'.$i));
if ($qtytoprocess != 0) {
// Check warehouse is set if we should have to

View File

@@ -43,9 +43,9 @@ $backtopage = GETPOST('backtopage', 'alpha');
$include_sub_warehouse = !empty(GETPOST('include_sub_warehouse')) ? GETPOST('include_sub_warehouse') : 0;
if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
$result = restrictedArea($user, 'stock', $id);
$result = restrictedArea($user, 'stock', $id, 'inventory&stock');
} else {
$result = restrictedArea($user, 'stock', $id, '', 'inventory_advance');
$result = restrictedArea($user, 'stock', $id, 'inventory&stock', 'inventory_advance');
}
// Initialize technical objects

View File

@@ -59,9 +59,9 @@ $batch = GETPOST('batch', 'alphanohtml');
$totalExpectedValuation = 0;
$totalRealValuation = 0;
if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
$result = restrictedArea($user, 'stock', $id);
$result = restrictedArea($user, 'stock', $id, 'inventory&stock');
} else {
$result = restrictedArea($user, 'stock', $id, '', 'inventory_advance');
$result = restrictedArea($user, 'stock', $id, 'inventory&stock', 'inventory_advance');
}
// Initialize technical objects

View File

@@ -230,7 +230,7 @@ if ($id > 0 || !empty($ref)) {
$bomtmp->ref = $objp->ref;
$product = new Product($db);
if (!empty($objp->fk_product)) {
if (!array_key_exists($product->id, $product_cache)) {
if (!array_key_exists($objp->fk_product, $product_cache)) {
$resultFetch = $product->fetch($objp->fk_product);
if ($resultFetch < 0) {
setEventMessages($product->error, $product->errors, 'errors');

View File

@@ -71,8 +71,7 @@ if (!$sortorder) {
$backtopage = GETPOST('backtopage', 'alpha');
// Security check
//$result=restrictedArea($user,'stock', $id, 'entrepot&stock');
$result = restrictedArea($user, 'stock');
$result=restrictedArea($user, 'stock', $id, 'entrepot&stock');
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
$hookmanager->initHooks(array('warehousecard', 'stocklist', 'globalcard'));

View File

@@ -505,6 +505,7 @@ class MouvementStock extends CommonObject
// Test if there is already a record for couple (warehouse / product), so later we will make an update or create.
$alreadyarecord = 0;
$fk_product_stock = 0;
if (!$error) {
$sql = "SELECT rowid, reel FROM ".$this->db->prefix()."product_stock";
$sql .= " WHERE fk_entrepot = ".((int) $entrepot_id)." AND fk_product = ".((int) $fk_product); // This is a unique key
@@ -535,7 +536,7 @@ class MouvementStock extends CommonObject
if ($price > 0 || (getDolGlobalString('STOCK_UPDATE_AWP_EVEN_WHEN_ENTRY_PRICE_IS_NULL') && $price == 0 && in_array($this->origin_type, array('order_supplier', 'invoice_supplier')))) {
$oldqtytouse = ($oldqty >= 0 ? $oldqty : 0);
// We make a test on oldpmp>0 to avoid to use normal rule on old data with no pmp field defined
if ($oldpmp > 0) {
if ($oldpmp > 0 && ($oldqtytouse + $qty) != 0) {
$newpmp = price2num((($oldqtytouse * $oldpmp) + ($qty * $price)) / ($oldqtytouse + $qty), 'MU');
} else {
$newpmp = $price; // For this product, PMP was not yet set. We set it to input price.

View File

@@ -308,7 +308,7 @@ if ($action == 'addtime' && $user->hasRight('projet', 'lire') && GETPOST('formfi
}
}
if (!$updateoftaskdone) { // Check to update progress if no update were done on task.
if (!$updateoftaskdone && GETPOSTISSET($tmptaskid.'progress')) { // Check to update progress if no update were done on task.
$object->fetch($tmptaskid);
//var_dump($object->progress);
//var_dump(GETPOST($tmptaskid . 'progress', 'int')); exit;

View File

@@ -12,6 +12,7 @@
* Copyright (C) 2016-2022 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2018 Quentin Vial-Gouteyron <quentin.vial-gouteyron@atm-consulting.fr>
* Copyright (C) 2022-2023 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2026 Mathieu Moulin <mathieu@iprospective.fr>
*
* 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
@@ -1041,7 +1042,10 @@ class Reception extends CommonObject
$this->db->begin();
// Stock control
if (isModEnabled('stock') && !getDolGlobalInt('STOCK_CALCULATE_ON_RECEPTION') && $this->statut > 0) {
if (isModEnabled('stock') &&
((getDolGlobalInt('STOCK_CALCULATE_ON_RECEPTION') && $this->statut > self::STATUS_DRAFT) ||
(getDolGlobalInt('STOCK_CALCULATE_ON_RECEPTION_CLOSE') && $this->statut == self::STATUS_CLOSED))
) {
require_once DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php";
$langs->load("agenda");
@@ -1065,7 +1069,7 @@ class Reception extends CommonObject
// we do not log origin because it will be deleted
$mouvS->origin = null;
$result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref), '', $obj->eatby, $obj->sellby, $obj->batch); // Price is set to 0, because we don't want to see WAP changed
$result = $mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref), '', $obj->eatby ? $this->db->jdate($obj->eatby) : null, $obj->sellby ? $this->db->jdate($obj->sellby) : null, $obj->batch); // Price is set to 0, because we don't want to see WAP changed
if ($result < 0) {
$error++;
$this->error = $mouvS->error;

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2020-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2026 Benjamin Falière <benjamin@faliere.com>
*
* 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
@@ -920,8 +921,9 @@ class Thirdparties extends DolibarrApi
$sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line";
$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
$sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id);
$sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON f.rowid = re.fk_facture_source";
$sql .= " WHERE re.fk_soc = ".((int) $id);
if ($filter == "available") {
$sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL";
}

View File

@@ -95,7 +95,8 @@ if ($conf->browser->layout == 'phone') {
$MAXCATEG = (!getDolGlobalString('TAKEPOS_NB_MAXCATEG') ? $maxcategbydefaultforthisdevice : $conf->global->TAKEPOS_NB_MAXCATEG);
$MAXPRODUCT = (!getDolGlobalString('TAKEPOS_NB_MAXPRODUCT') ? $maxproductbydefaultforthisdevice : $conf->global->TAKEPOS_NB_MAXPRODUCT);
$term = empty($_SESSION['takeposterminal']) ? 1: $_SESSION['takeposterminal'];
$term = empty($_SESSION['takeposterminal']) ? 1 : $_SESSION['takeposterminal'];
$socid = getDolGlobalInt('CASHDESK_ID_THIRDPARTY' . $term);
/*
$constforcompanyid = 'CASHDESK_ID_THIRDPARTY'.$_SESSION["takeposterminal"];
@@ -344,8 +345,15 @@ function LoadProducts(position, issubcat) {
if (maxproduct >= 1) {
limit = maxproduct-1;
}
// Get socid
let socid = jQuery('#thirdpartyid').val();
if ((socid === undefined || socid === "") && parseInt("<?php echo dol_escape_js($socid) ?>") > 0) {
socid = parseInt("<?php echo dol_escape_js($socid); ?>");
}
// Only show products for sale (tosell=1)
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&thirdpartyid=' + jQuery('#thirdpartyid').val() + '&category='+currentcat+'&tosell=1&limit='+limit+'&offset=0', function(data) {
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&thirdpartyid=' + socid + '&category='+currentcat+'&tosell=1&limit='+limit+'&offset=0', function(data) {
console.log("Call ajax.php (in LoadProducts) to get Products of category "+currentcat+" then loop on result to fill image thumbs");
console.log(data);
@@ -461,9 +469,16 @@ function MoreProducts(moreorless) {
if (maxproduct >= 1) {
limit = maxproduct-1;
}
var offset = <?php echo($MAXPRODUCT - 2); ?> * pageproducts;
var offset = <?php echo ($MAXPRODUCT - 2); ?> * pageproducts;
// Get socid
let socid = jQuery('#thirdpartyid').val();
if ((socid === undefined || socid === "") && parseInt("<?php echo dol_escape_js($socid) ?>") > 0) {
socid = parseInt("<?php echo dol_escape_js($socid); ?>");
}
// Only show products for sale (tosell=1)
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&category='+currentcat+'&tosell=1&limit='+limit+'&offset='+offset, function(data) {
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=getProducts&token=<?php echo newToken();?>&thirdpartyid=' + socid + '&category='+currentcat+'&tosell=1&limit='+limit+'&offset='+offset, function(data) {
console.log("Call ajax.php (in MoreProducts) to get Products of category "+currentcat);
if (typeof (data[0]) == "undefined" && moreorless=="more"){ // Return if no more pages
@@ -699,7 +714,14 @@ function Search2(keyCodeForEnter, moreorless) {
pageproducts = 0;
jQuery(".wrapper2 .catwatermark").hide();
var nbsearchresults = 0;
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=search&token=<?php echo newToken();?>&term=' + search_term + '&thirdpartyid=' + jQuery('#thirdpartyid').val() + '&search_start=' + search_start + '&search_limit=' + search_limit, function (data) {
// Only show products for sale (tosell=1)
let socid = jQuery('#thirdpartyid').val();
if ((socid === undefined || socid === "") && parseInt("<?php echo dol_escape_js($socid) ?>") > 0) {
socid = parseInt("<?php echo dol_escape_js($socid); ?>");
}
$.getJSON('<?php echo DOL_URL_ROOT ?>/takepos/ajax/ajax.php?action=search&token=<?php echo newToken();?>&term=' + search_term + '&thirdpartyid=' + socid + '&search_start=' + search_start + '&search_limit=' + search_limit, function (data) {
for (i = 0; i < <?php echo $MAXPRODUCT ?>; i++) {
if (typeof (data[i]) == "undefined") {
$("#prowatermark" + i).html("");
@@ -1403,13 +1425,13 @@ if ($reshook == 0) { //add buttons
$menus[$r++] = $butmenu;
}
}
} elseif ($reshook == 1) {
$r = 0; //replace buttons
if (is_array($hookmanager->resArray)) {
foreach ($hookmanager->resArray as $resArray) {
foreach ($resArray as $butmenu) {
$menus[$r++] = $butmenu;
}
}
} elseif ($reshook == 1) {
$r = 0; //replace buttons
if (is_array($hookmanager->resArray) ) {
foreach ($hookmanager->resArray as $resArray) {
foreach ($resArray as $butmenu) {
$menus[$r++] = $butmenu;
}
}
}

View File

@@ -1626,13 +1626,15 @@ class Ticket extends CommonObject
if ($this->statut != self::STATUS_CANCELED) { // no closed
$this->oldcopy = dol_clone($this);
$this->status = Ticket::STATUS_READ;
$this->db->begin();
$oldStatus = $this->fk_statut;
$this->fk_statut = Ticket::STATUS_READ;
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
$sql .= " SET fk_statut = ".Ticket::STATUS_READ.", date_read = '".$this->db->idate(dol_now())."'";
$sql .= " SET fk_statut = ".$this->status .", date_read = '".$this->db->idate(dol_now())."'";
$sql .= " WHERE rowid = ".((int) $this->id);
dol_syslog(get_class($this)."::markAsRead");
@@ -1645,7 +1647,6 @@ class Ticket extends CommonObject
// Call trigger
$result = $this->call_trigger('TICKET_MODIFY', $user);
if ($result < 0) {
$this->fk_statut = $oldStatus;
$error++;
}
// End call triggers
@@ -1656,13 +1657,19 @@ class Ticket extends CommonObject
return 1;
} else {
$this->fk_statut = $oldStatus;
$this->status = $this->oldcopy->status;
$this->db->rollback();
$this->error = implode(',', $this->errors);
dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
return -1;
}
} else {
$this->fk_statut = $oldStatus;
$this->status = $this->oldcopy->status;
$this->db->rollback();
$this->error = $this->db->lasterror();
dol_syslog(get_class($this)."::markAsRead ".$this->error, LOG_ERR);
@@ -1885,9 +1892,11 @@ class Ticket extends CommonObject
if ($this->status != Ticket::STATUS_CLOSED && $this->status != Ticket::STATUS_CANCELED) { // not closed
$this->db->begin();
$this->oldcopy = dol_clone($this);
$this->status = ($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED);
$sql = "UPDATE ".MAIN_DB_PREFIX."ticket";
$sql .= " SET fk_statut=".($mode ? Ticket::STATUS_CANCELED : Ticket::STATUS_CLOSED).", progress=100, date_close='".$this->db->idate(dol_now())."'";
$sql .= " SET fk_statut=".$this->status.", progress=100, date_close='".$this->db->idate(dol_now())."'";
$sql .= " WHERE rowid = ".((int) $this->id);
dol_syslog(get_class($this)."::close mode=".$mode);