Fix #38788 datapolicy: check llx_facture_fourn for pure suppliers, not llx_facture (#38795)

The 'tiers_fournisseur' and 'contact_fournisseur' SQL templates in
htdocs/datapolicy/class/datapolicycron.class.php tested NOT EXISTS against
llx_facture (sales invoices) when the gate must be on llx_facture_fourn
(purchase invoices). A pure supplier (fournisseur=1, client=0) with an
active purchase history but no sales would pass the filter and get
anonymized as if it had no activity, losing the data that was the whole
reason it was kept in the dictionary.

Signed-off-by: Dolicraft <contact@dolicraft.com>
Co-authored-by: Dolicraft <contact@dolicraft.com>
This commit is contained in:
w3houde 2026-06-13 18:54:33 +02:00 committed by GitHub
parent 26e5d969a0
commit c2bcd73c0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -133,7 +133,11 @@ class DataPolicyCron
'picto' => img_picto('', 'supplier', 'class="pictofixedwidth"'),
'const_delete' => '',
'const_anonymize' => 'DATAPOLICY_TIERS_FOURNISSEUR_ANONYMIZE_DELAY',
'sql_template' => "SELECT s.rowid FROM ".$prefix."societe as s WHERE s.entity = __ENTITY__ AND s.fournisseur = 1 AND s.tms < DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH) AND NOT EXISTS (SELECT a.id FROM ".$prefix."actioncomm as a WHERE a.fk_soc = s.rowid AND a.tms > DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH)) AND NOT EXISTS (SELECT f.rowid FROM ".$prefix."facture as f WHERE f.fk_soc = s.rowid)",
// Suppliers must be checked against llx_facture_fourn (purchase invoices),
// not llx_facture (sales invoices). A pure supplier with no sales would
// otherwise always pass the filter and get anonymized regardless of
// purchase history (#38788).
'sql_template' => "SELECT s.rowid FROM ".$prefix."societe as s WHERE s.entity = __ENTITY__ AND s.fournisseur = 1 AND s.tms < DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH) AND NOT EXISTS (SELECT a.id FROM ".$prefix."actioncomm as a WHERE a.fk_soc = s.rowid AND a.tms > DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH)) AND NOT EXISTS (SELECT f.rowid FROM ".$prefix."facture_fourn as f WHERE f.fk_soc = s.rowid)",
'class' => 'Societe',
'file' => DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php',
'anonymize_fields' => array('name' => 'MAKEANONYMOUS', 'name_alias' => 'MAKEANONYMOUS', 'address' => '---', 'town' => '---', 'zip' => '---', 'phone' => '---', 'email' => 'anonymous+__ID__@example.com', 'url' => '---', 'fax' => '---', 'siret' => '---', 'siren' => '---', 'ape' => '---', 'idprof4' => '---', 'idprof5' => '---', 'idprof6' => '---', 'tva_intra' => '---', 'capital' => 0, 'socialnetworks' => [], 'geolat' => 0, 'geolong' => 0, 'ip' => '0.0.0.0'),
@ -209,7 +213,9 @@ class DataPolicyCron
'picto' => img_picto('', 'contact', 'class="pictofixedwidth"'),
'const_delete' => '',
'const_anonymize' => 'DATAPOLICY_CONTACT_FOURNISSEUR_ANONYMIZE_DELAY',
'sql_template' => "SELECT c.rowid FROM ".$prefix."socpeople as c INNER JOIN ".$prefix."societe as s ON s.rowid = c.fk_soc WHERE c.entity = __ENTITY__ AND c.tms < DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH) AND s.fournisseur = 1 AND NOT EXISTS (SELECT a.id FROM ".$prefix."actioncomm as a WHERE a.fk_contact = c.rowid AND a.tms > DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH)) AND NOT EXISTS (SELECT f.rowid FROM ".$prefix."facture as f WHERE f.fk_soc = s.rowid)",
// Same as tiers_fournisseur above: a contact attached to a pure supplier
// must be checked against llx_facture_fourn, not llx_facture (#38788).
'sql_template' => "SELECT c.rowid FROM ".$prefix."socpeople as c INNER JOIN ".$prefix."societe as s ON s.rowid = c.fk_soc WHERE c.entity = __ENTITY__ AND c.tms < DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH) AND s.fournisseur = 1 AND NOT EXISTS (SELECT a.id FROM ".$prefix."actioncomm as a WHERE a.fk_contact = c.rowid AND a.tms > DATE_SUB(__NOW__, INTERVAL __DELAY__ MONTH)) AND NOT EXISTS (SELECT f.rowid FROM ".$prefix."facture_fourn as f WHERE f.fk_soc = s.rowid)",
'class' => 'Contact',
'file' => DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php',
'anonymize_fields' => array('lastname' => 'MAKEANONYMOUS', 'firstname' => 'MAKEANONYMOUS', 'poste' => '---', 'address' => '---', 'town' => '---', 'zip' => '---', 'phone_pro' => '---', 'phone_perso' => '---', 'phone_mobile' => '---', 'email' => 'anonymous+__ID__@example.com', 'photo' => '', 'url' => '---', 'fax' => '---', 'socialnetworks' => [], 'geolat' => 0, 'geolong' => 0, 'ip' => '0.0.0.0'),