From 63a47112ae3280e9f921f1e7ad1395cb0f7266f5 Mon Sep 17 00:00:00 2001 From: Florian HENRY Date: Fri, 16 Jul 2021 11:14:30 +0200 Subject: [PATCH 001/112] new: #18162 --- htdocs/core/modules/modProjet.class.php | 6 ++++++ htdocs/langs/en_US/admin.lang | 5 +++-- htdocs/langs/fr_FR/admin.lang | 3 ++- htdocs/projet/tasks/time.php | 12 ++++++------ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/htdocs/core/modules/modProjet.class.php b/htdocs/core/modules/modProjet.class.php index 25448f239e6..7502fbffa81 100644 --- a/htdocs/core/modules/modProjet.class.php +++ b/htdocs/core/modules/modProjet.class.php @@ -202,6 +202,12 @@ class modProjet extends DolibarrModules $this->rights[$r][4] = 'all'; $this->rights[$r][5] = 'supprimer'; + $r++; + $this->rights[$r][0] = 145; // id de la permission + $this->rights[$r][1] = "Can enter time consumed on assigned tasks (timesheet)"; // libelle de la permission + $this->rights[$r][2] = 'w'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'time'; // Menus //------- diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index a05c9e7ea97..13dbef8bff3 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -707,7 +707,8 @@ Permission34=Delete products Permission36=See/manage hidden products Permission38=Export products Permission39=Ignore minimum price -Permission41=Read projects and tasks (shared project and projects I'm contact for). Can also enter time consumed, for me or my hierarchy, on assigned tasks (Timesheet) +Permission41=Read projects and tasks (shared project and projects I'm contact for). +Permission145=Can enter time consumed, for me or my hierarchy, on assigned tasks (Timesheet) Permission42=Create/modify projects (shared project and projects I'm contact for). Can also create tasks and assign users to project and tasks Permission44=Delete projects (shared project and projects I'm contact for) Permission45=Export projects @@ -2145,4 +2146,4 @@ RandomlySelectedIfSeveral=Randomly selected if several pictures are available DatabasePasswordObfuscated=Database password is obfuscated in conf file DatabasePasswordNotObfuscated=Database password is NOT obfuscated in conf file APIsAreNotEnabled=APIs modules are not enabled -YouShouldSetThisToOff=You should set this to 0 or off \ No newline at end of file +YouShouldSetThisToOff=You should set this to 0 or off diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 57a50388a4f..0d0dadf3327 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -707,7 +707,8 @@ Permission34=Supprimer les produits Permission36=Voir/gérer les produits cachés Permission38=Exporter les produits Permission39=Ignorer le prix minimum -Permission41=Lire les projets et tâches (partagés ou dont vous n'êtes pas contact). Permet la saisie de temps passé, pour vous-même et votre hiérarchie (vos subordonnés), sur les tâches assignées (Feuilles de temps). +Permission41=Lire les projets et tâches (partagés ou dont vous n'êtes pas contact). +Permission145=Permet la saisie de temps passé, pour vous-même et votre hiérarchie (vos subordonnés), sur les tâches assignées (Feuilles de temps). Permission42=Créer/modifier les projets (projets partagés et projets pour lesquels je suis contact). Permet aussi de créer des tâches et d'assigner des utilisateurs aux projets et tâches. Permission44=Supprimer les projets et tâches (partagés ou dont je suis contact) Permission45=Exporter les projets diff --git a/htdocs/projet/tasks/time.php b/htdocs/projet/tasks/time.php index a9316bcedcd..4cac12ad801 100644 --- a/htdocs/projet/tasks/time.php +++ b/htdocs/projet/tasks/time.php @@ -149,7 +149,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x' $action = ''; } -if ($action == 'addtimespent' && $user->rights->projet->lire) { +if ($action == 'addtimespent' && $user->rights->projet->time) { $error = 0; $timespent_durationhour = GETPOST('timespent_durationhour', 'int'); @@ -281,7 +281,7 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us } } -if ($action == 'confirm_delete' && $confirm == "yes" && $user->rights->projet->lire) { +if ($action == 'confirm_delete' && $confirm == "yes" && $user->rights->projet->supprimer) { $object->fetchTimeSpent(GETPOST('lineid', 'int')); // TODO Check that ($task_time->fk_user == $user->id || in_array($task_time->fk_user, $childids)) $result = $object->delTimeSpent($user); @@ -722,7 +722,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { $linktocreatetimeBtnStatus = 0; $linktocreatetimeUrl = ''; $linktocreatetimeHelpText = ''; - if ($user->rights->projet->all->lire || $user->rights->projet->lire) { // To enter time, read permission is enough + if ($user->rights->projet->all->lire || $user->rights->projet->time) { if ($projectstatic->public || $userRead > 0) { $linktocreatetimeBtnStatus = 1; @@ -940,7 +940,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { print ''; } elseif ($action == 'splitline') { print ''; - } elseif ($action == 'createtime' && $user->rights->projet->lire) { + } elseif ($action == 'createtime' && $user->rights->projet->time) { print ''; } elseif ($massaction == 'generateinvoice' && $user->rights->facture->lire) { print ''; @@ -1122,7 +1122,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { /* * Form to add a new line of time spent */ - if ($action == 'createtime' && $user->rights->projet->lire) { + if ($action == 'createtime' && $user->rights->projet->time) { print ''."\n"; if (!empty($id)) { print ''; @@ -1537,7 +1537,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) { print ''; print '
'; print ''; - } elseif ($user->rights->projet->lire || $user->rights->projet->all->creer) { // Read project and enter time consumed on assigned tasks + } elseif ($user->rights->projet->time || $user->rights->projet->all->creer) { // Read project and enter time consumed on assigned tasks if ($task_time->fk_user == $user->id || in_array($task_time->fk_user, $childids) || $user->rights->projet->all->creer) { if ($conf->MAIN_FEATURES_LEVEL >= 2) { print ' '; From ab48351d15ce4fa150618fd2f189039fd8a84379 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:10:58 +0200 Subject: [PATCH 002/112] NEW: deposit payment terms: database fields --- htdocs/install/mysql/migration/14.0.0-15.0.0.sql | 5 +++++ htdocs/install/mysql/tables/llx_c_payment_term.sql | 1 + htdocs/install/mysql/tables/llx_commande.sql | 1 + htdocs/install/mysql/tables/llx_propal.sql | 1 + htdocs/install/mysql/tables/llx_societe.sql | 1 + 5 files changed, 9 insertions(+) diff --git a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql index 03bb7631dda..3e5d86b5dd6 100644 --- a/htdocs/install/mysql/migration/14.0.0-15.0.0.sql +++ b/htdocs/install/mysql/migration/14.0.0-15.0.0.sql @@ -149,3 +149,8 @@ INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle) VALUES (20, '2010', ' INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle) VALUES (20, '2011', 'Ideell förening'); INSERT INTO llx_c_forme_juridique (fk_pays, code, libelle) VALUES (20, '2012', 'Stiftelse'); +-- Deposit generation helper with specific payment terms +ALTER TABLE llx_c_payment_term ADD COLUMN deposit_percent real DEFAULT NULL AFTER decalage; +ALTER TABLE llx_societe ADD COLUMN deposit_percent real DEFAULT NULL AFTER cond_reglement; +ALTER TABLE llx_propal ADD COLUMN deposit_percent real DEFAULT NULL AFTER fk_cond_reglement; +ALTER TABLE llx_commande ADD COLUMN deposit_percent real DEFAULT NULL AFTER fk_cond_reglement; diff --git a/htdocs/install/mysql/tables/llx_c_payment_term.sql b/htdocs/install/mysql/tables/llx_c_payment_term.sql index 087ab63c184..6ed1c580e4f 100644 --- a/htdocs/install/mysql/tables/llx_c_payment_term.sql +++ b/htdocs/install/mysql/tables/llx_c_payment_term.sql @@ -30,6 +30,7 @@ create table llx_c_payment_term type_cdr tinyint, -- Type of change date reckoning. 1=Payment at end of current month, 2=the Nth of next month nbjour smallint, decalage smallint, + deposit_percent real DEFAULT NULL, module varchar(32) NULL, position integer NOT NULL DEFAULT 0 )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_commande.sql b/htdocs/install/mysql/tables/llx_commande.sql index e3a075933c2..096bd8305a2 100644 --- a/htdocs/install/mysql/tables/llx_commande.sql +++ b/htdocs/install/mysql/tables/llx_commande.sql @@ -63,6 +63,7 @@ create table llx_commande fk_account integer, -- bank account fk_currency varchar(3), -- currency code fk_cond_reglement integer, -- condition de reglement + deposit_percent real DEFAULT NULL, -- default deposit % if payment term needs it fk_mode_reglement integer, -- mode de reglement date_livraison datetime default NULL, diff --git a/htdocs/install/mysql/tables/llx_propal.sql b/htdocs/install/mysql/tables/llx_propal.sql index 7c94086b3b9..e795d63ff8b 100644 --- a/htdocs/install/mysql/tables/llx_propal.sql +++ b/htdocs/install/mysql/tables/llx_propal.sql @@ -58,6 +58,7 @@ create table llx_propal fk_account integer, -- bank account fk_currency varchar(3), -- currency code fk_cond_reglement integer, -- condition de reglement (30 jours, fin de mois ...) + deposit_percent real DEFAULT NULL, -- default deposit % if payment term needs it fk_mode_reglement integer, -- mode de reglement (Virement, Prelevement) note_private text, diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index 7112b6e93ea..eb2ac1cd136 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -92,6 +92,7 @@ create table llx_societe remise_supplier real DEFAULT 0, -- discount by default granted by this supplier mode_reglement tinyint, -- payment mode customer cond_reglement tinyint, -- payment term customer + deposit_percent real DEFAULT NULL, -- default deposit % if payment term needs it transport_mode tinyint, -- transport mode customer (Intracomm report) mode_reglement_supplier tinyint, -- payment mode supplier cond_reglement_supplier tinyint, -- payment term supplier From ef624ec5bc5cbb1daab90d2fe6fdf5e8026bfcfb Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:34:30 +0200 Subject: [PATCH 003/112] NEW: deposit payment terms: add field into dictionary admin page --- htdocs/admin/dict.php | 23 +++++++++++++++++------ htdocs/langs/en_US/bills.lang | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 9073c9e238c..02a3cb07ffa 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -207,7 +207,7 @@ $tabsql[8] = "SELECT t.id as rowid, t.code as code, t.libelle, t.fk_country as $tabsql[9] = "SELECT c.code_iso as code, c.label, c.unicode, c.active FROM ".MAIN_DB_PREFIX."c_currencies AS c"; $tabsql[10] = "SELECT t.rowid, t.code, t.taux, t.localtax1_type, t.localtax1, t.localtax2_type, t.localtax2, c.label as country, c.code as country_code, t.fk_pays as country_id, t.recuperableonly, t.note, t.active, t.accountancy_code_sell, t.accountancy_code_buy FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c WHERE t.fk_pays=c.rowid"; $tabsql[11] = "SELECT t.rowid as rowid, t.element, t.source, t.code, t.libelle, t.position, t.active FROM ".MAIN_DB_PREFIX."c_type_contact AS t"; -$tabsql[12] = "SELECT c.rowid as rowid, c.code, c.libelle, c.libelle_facture, c.nbjour, c.type_cdr, c.decalage, c.active, c.sortorder, c.entity FROM ".MAIN_DB_PREFIX."c_payment_term AS c WHERE c.entity = ".getEntity($tabname[12]); +$tabsql[12] = "SELECT c.rowid as rowid, c.code, c.libelle, c.libelle_facture, c.deposit_percent, c.nbjour, c.type_cdr, c.decalage, c.active, c.sortorder, c.entity FROM ".MAIN_DB_PREFIX."c_payment_term AS c WHERE c.entity = ".getEntity($tabname[12]); $tabsql[13] = "SELECT c.id as rowid, c.code, c.libelle, c.type, c.active, c.entity FROM ".MAIN_DB_PREFIX."c_paiement AS c WHERE c.entity = ".getEntity($tabname[13]); $tabsql[14] = "SELECT e.rowid as rowid, e.code as code, e.label, e.price, e.organization, e.fk_pays as country_id, c.code as country_code, c.label as country, e.active FROM ".MAIN_DB_PREFIX."c_ecotaxe AS e, ".MAIN_DB_PREFIX."c_country as c WHERE e.fk_pays=c.rowid and c.active=1"; $tabsql[15] = "SELECT rowid as rowid, code, label as libelle, width, height, unit, active FROM ".MAIN_DB_PREFIX."c_paper_format"; @@ -299,7 +299,7 @@ $tabfield[8] = "code,libelle,country_id,country".(!empty($conf->global->SOCIETE_ $tabfield[9] = "code,label,unicode"; $tabfield[10] = "country_id,country,code,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note"; $tabfield[11] = "element,source,code,libelle,position"; -$tabfield[12] = "code,libelle,libelle_facture,nbjour,type_cdr,decalage,sortorder,entity"; +$tabfield[12] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder,entity"; $tabfield[13] = "code,libelle,type,entity"; $tabfield[14] = "code,label,price,organization,country"; $tabfield[15] = "code,libelle,width,height,unit"; @@ -345,7 +345,7 @@ $tabfieldvalue[8] = "code,libelle,country".(!empty($conf->global->SOCIETE_SORT_O $tabfieldvalue[9] = "code,label,unicode"; $tabfieldvalue[10] = "country,code,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note"; $tabfieldvalue[11] = "element,source,code,libelle,position"; -$tabfieldvalue[12] = "code,libelle,libelle_facture,nbjour,type_cdr,decalage,sortorder"; +$tabfieldvalue[12] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder"; $tabfieldvalue[13] = "code,libelle,type"; $tabfieldvalue[14] = "code,label,price,organization,country"; $tabfieldvalue[15] = "code,libelle,width,height,unit"; @@ -391,7 +391,7 @@ $tabfieldinsert[8] = "code,libelle,fk_country".(!empty($conf->global->SOCIETE_SO $tabfieldinsert[9] = "code_iso,label,unicode"; $tabfieldinsert[10] = "fk_pays,code,taux,localtax1_type,localtax1,localtax2_type,localtax2,recuperableonly,accountancy_code_sell,accountancy_code_buy,note"; $tabfieldinsert[11] = "element,source,code,libelle,position"; -$tabfieldinsert[12] = "code,libelle,libelle_facture,nbjour,type_cdr,decalage,sortorder,entity"; +$tabfieldinsert[12] = "code,libelle,libelle_facture,deposit_percent,nbjour,type_cdr,decalage,sortorder,entity"; $tabfieldinsert[13] = "code,libelle,type,entity"; $tabfieldinsert[14] = "code,label,price,organization,fk_pays"; $tabfieldinsert[15] = "code,label,width,height,unit"; @@ -738,6 +738,9 @@ if (GETPOST('actionadd') || GETPOST('actionmodify')) { if ($fieldnamekey == 'libelle_facture') { $fieldnamekey = 'LabelOnDocuments'; } + if ($fieldnamekey == 'deposit_percent') { + $fieldnamekey = 'DepositPercent'; + } if ($fieldnamekey == 'nbjour') { $fieldnamekey = 'NbOfDays'; } @@ -1284,6 +1287,10 @@ if ($id) { if ($value == 'libelle_facture') { $valuetoshow = $form->textwithtooltip($langs->trans("LabelOnDocuments"), $langs->trans("LabelUsedByDefault"), 2, 1, img_help(1, '')); } + if ($value == 'deposit_percent') { + $valuetoshow = $langs->trans('DepositPercent'); + $class = 'right'; + } if ($value == 'country') { if (in_array('region_id', $fieldlist)) { print ' '; continue; @@ -1635,6 +1642,10 @@ if ($id) { if ($value == 'libelle_facture') { $valuetoshow = $langs->trans("LabelOnDocuments"); } + if ($value == 'deposit_percent') { + $valuetoshow = $langs->trans('DepositPercent'); + $cssprefix = 'right '; + } if ($value == 'country') { $valuetoshow = $langs->trans("Country"); } @@ -1995,7 +2006,7 @@ if ($id) { if ($value == 'tracking') { $class .= ' tdoverflowauto'; } - if (in_array($value, array('pos', 'position'))) { + if (in_array($value, array('pos', 'position', 'deposit_percent'))) { $class .= ' right'; } if (in_array($value, array('localtax1_type', 'localtax2_type'))) { @@ -2380,7 +2391,7 @@ function fieldList($fieldlist, $obj = '', $tabname = '', $context = '') if ($fieldlist[$field] == 'code') { $class = 'maxwidth100'; } - if (in_array($fieldlist[$field], array('pos', 'position'))) { + if (in_array($fieldlist[$field], array('pos', 'position', 'deposit_percent'))) { $classtd = 'right'; $class = 'maxwidth50 right'; } if (in_array($fieldlist[$field], array('dayrule', 'day', 'month', 'year', 'use_default', 'affect', 'delay', 'public', 'sortorder', 'sens', 'category_type', 'fk_parent'))) { diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index e475a815ac9..86344105168 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -424,6 +424,7 @@ FixAmount=Fixed amount - 1 line with label '%s' VarAmount=Variable amount (%% tot.) VarAmountOneLine=Variable amount (%% tot.) - 1 line with label '%s' VarAmountAllLines=Variable amount (%% tot.) - all lines from origin +DepositPercent=Deposit %% # PaymentType PaymentTypeVIR=Bank transfer PaymentTypeShortVIR=Bank transfer From 004b52f590ebed7ee7acfccf99bac8184dbcc947 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 12:05:38 +0200 Subject: [PATCH 004/112] NEW: deposit payment terms: add field into CRUD methods --- htdocs/comm/propal/class/propal.class.php | 9 ++++++++- htdocs/commande/class/commande.class.php | 15 +++++++++++++-- htdocs/societe/class/societe.class.php | 8 +++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index a7b5c465226..f2132799007 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -203,6 +203,7 @@ class Propal extends CommonObject public $total; public $cond_reglement_code; + public $deposit_percent; public $mode_reglement_code; public $remise = 0; public $remise_percent = 0; @@ -309,6 +310,7 @@ class Propal extends CommonObject 'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>1, 'visible'=>-1, 'position'=>150), 'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'Currency', 'enabled'=>1, 'visible'=>-1, 'position'=>155), 'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>160), + 'deposit_percent' =>array('type'=>'double', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>161), 'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>165), 'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>170), 'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>175), @@ -1080,6 +1082,7 @@ class Propal extends CommonObject $sql .= ", model_pdf"; $sql .= ", fin_validite"; $sql .= ", fk_cond_reglement"; + $sql .= ", deposit_percent"; $sql .= ", fk_mode_reglement"; $sql .= ", fk_account"; $sql .= ", ref_client"; @@ -1113,6 +1116,7 @@ class Propal extends CommonObject $sql .= ", '".$this->db->escape($this->model_pdf)."'"; $sql .= ", ".($this->fin_validite != '' ? "'".$this->db->idate($this->fin_validite)."'" : "NULL"); $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : 'NULL'); + $sql .= ", ".(! empty($this->deposit_percent) ? floatval($this->deposit_percent) : 'NULL'); $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : 'NULL'); $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL'); $sql .= ", '".$this->db->escape($this->ref_client)."'"; @@ -1336,6 +1340,7 @@ class Propal extends CommonObject if ($objsoc->fetch($socid) > 0) { $object->socid = $objsoc->id; $object->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); + $object->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : null); $object->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); $object->fk_delivery_address = ''; @@ -1463,7 +1468,7 @@ class Propal extends CommonObject $sql .= ", c.label as statut_label"; $sql .= ", ca.code as availability_code, ca.label as availability"; $sql .= ", dr.code as demand_reason_code, dr.label as demand_reason"; - $sql .= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc"; + $sql .= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc, p.deposit_percent"; $sql .= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement"; $sql .= " FROM ".MAIN_DB_PREFIX."propal as p"; $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_propalst as c ON p.fk_statut = c.id'; @@ -1546,6 +1551,7 @@ class Propal extends CommonObject $this->cond_reglement_code = $obj->cond_reglement_code; $this->cond_reglement = $obj->cond_reglement; $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; + $this->deposit_percent = $obj->deposit_percent; $this->extraparams = (array) json_decode($obj->extraparams, true); @@ -1655,6 +1661,7 @@ class Propal extends CommonObject $sql .= " fk_user_valid=".(isset($this->user_valid) ? $this->user_valid : "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) ? floatval($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 .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").","; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index e3675129198..90566bd2051 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -133,6 +133,11 @@ class Commande extends CommonOrder */ public $cond_reglement_code; + /** + * @var double Deposit % for payment terms + */ + public $deposit_percent; + /** * @var int bank account ID */ @@ -321,6 +326,7 @@ class Commande extends CommonOrder 'fk_account' =>array('type'=>'integer', 'label'=>'BankAccount', 'enabled'=>1, 'visible'=>-1, 'position'=>170), 'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'MulticurrencyID', 'enabled'=>1, 'visible'=>-1, 'position'=>175), 'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'position'=>180), + 'deposit_percent' =>array('type'=>'double', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>181), 'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>185), 'date_livraison' =>array('type'=>'date', 'label'=>'DateDeliveryPlanned', 'enabled'=>1, 'visible'=>-1, 'position'=>190), 'fk_shipping_method' =>array('type'=>'integer', 'label'=>'ShippingMethod', 'enabled'=>1, 'visible'=>-1, 'position'=>195), @@ -924,7 +930,7 @@ class Commande extends CommonOrder $sql = "INSERT INTO ".MAIN_DB_PREFIX."commande ("; $sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client, ref_int"; - $sql .= ", model_pdf, fk_cond_reglement, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address"; + $sql .= ", model_pdf, fk_cond_reglement, deposit_percent, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address"; $sql .= ", fk_shipping_method"; $sql .= ", fk_warehouse"; $sql .= ", remise_absolue, remise_percent"; @@ -945,6 +951,7 @@ class Commande extends CommonOrder $sql .= ", ".($this->ref_int ? "'".$this->db->escape($this->ref_int)."'" : "null"); $sql .= ", '".$this->db->escape($this->model_pdf)."'"; $sql .= ", ".($this->cond_reglement_id > 0 ? ((int) $this->cond_reglement_id) : "null"); + $sql .= ", ".(! empty($this->deposit_percent) ? floatval($this->deposit_percent) : "null"); $sql .= ", ".($this->mode_reglement_id > 0 ? ((int) $this->mode_reglement_id) : "null"); $sql .= ", ".($this->fk_account > 0 ? ((int) $this->fk_account) : 'NULL'); $sql .= ", ".($this->availability_id > 0 ? ((int) $this->availability_id) : "null"); @@ -1193,6 +1200,7 @@ class Commande extends CommonOrder if ($objsoc->fetch($socid) > 0) { $this->socid = $objsoc->id; $this->cond_reglement_id = (!empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); + $this->deposit_percent = (!empty($objsoc->deposit_percent) ? $objsoc->deposit_percent : null); $this->mode_reglement_id = (!empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); $this->fk_project = 0; $this->fk_delivery_address = 0; @@ -1335,6 +1343,7 @@ class Commande extends CommonOrder $this->socid = $object->socid; $this->fk_project = $object->fk_project; $this->cond_reglement_id = $object->cond_reglement_id; + $this->deposit_percent = $object->deposit_percent; $this->mode_reglement_id = $object->mode_reglement_id; $this->fk_account = $object->fk_account; $this->availability_id = $object->availability_id; @@ -1783,7 +1792,7 @@ class Commande extends CommonOrder } $sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut'; - $sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason'; + $sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.deposit_percent, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason'; $sql .= ', c.fk_account'; $sql .= ', c.date_commande, c.date_valid, c.tms'; $sql .= ', c.date_livraison as delivery_date'; @@ -1875,6 +1884,7 @@ class Commande extends CommonOrder $this->cond_reglement_code = $obj->cond_reglement_code; $this->cond_reglement = $obj->cond_reglement_libelle; $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; + $this->deposit_percent = $obj->deposit_percent; $this->fk_account = $obj->fk_account; $this->availability_id = $obj->fk_availability; $this->availability_code = $obj->availability_code; @@ -3309,6 +3319,7 @@ class Commande extends CommonOrder $sql .= " fk_user_valid=".(isset($this->user_valid) ? $this->user_valid : "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) ? floatval($this->deposit_percent) : "null"); $sql .= " fk_mode_reglement=".(isset($this->mode_reglement_id) ? $this->mode_reglement_id : "null").","; $sql .= " date_livraison=".(strval($this->delivery_date) != '' ? "'".$this->db->idate($this->delivery_date)."'" : 'null').","; $sql .= " fk_shipping_method=".(isset($this->shipping_method_id) ? $this->shipping_method_id : "null").","; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 8f0e2c84805..16bcfdfb52f 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -208,6 +208,7 @@ class Societe extends CommonObject //'remise_supplier' =>array('type'=>'double', 'label'=>'SupplierDiscount', 'enabled'=>1, 'visible'=>-1, 'position'=>290, 'isameasure'=>1), 'mode_reglement' =>array('type'=>'tinyint(4)', 'label'=>'Mode reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>295), 'cond_reglement' =>array('type'=>'tinyint(4)', 'label'=>'Cond reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>300), + 'deposit_percent' =>array('type'=>'double', 'label'=>'DepositPercent', 'enabled'=>1, 'visible'=>-1, 'position'=>301), 'mode_reglement_supplier' =>array('type'=>'integer', 'label'=>'Mode reglement supplier', 'enabled'=>1, 'visible'=>-1, 'position'=>305), 'outstanding_limit' =>array('type'=>'double(24,8)', 'label'=>'OutstandingBill', 'enabled'=>1, 'visible'=>-1, 'position'=>310, 'isameasure'=>1), 'order_min_amount' =>array('type'=>'double(24,8)', 'label'=>'Order min amount', 'enabled'=>'!empty($conf->commande->enabled) && !empty($conf->global->ORDER_MANAGE_MIN_AMOUNT)', 'visible'=>-1, 'position'=>315, 'isameasure'=>1), @@ -481,6 +482,9 @@ class Societe extends CommonObject public $remise_percent; public $remise_supplier_percent; + public $mode_reglement_id; + public $cond_reglement_id; + public $deposit_percent; public $mode_reglement_supplier_id; public $cond_reglement_supplier_id; public $transport_mode_supplier_id; @@ -1432,6 +1436,7 @@ class Societe extends CommonObject $sql .= ",mode_reglement = ".(!empty($this->mode_reglement_id) ? "'".$this->db->escape($this->mode_reglement_id)."'" : "null"); $sql .= ",cond_reglement = ".(!empty($this->cond_reglement_id) ? "'".$this->db->escape($this->cond_reglement_id)."'" : "null"); + $sql .= ",deposit_percent = ".(!empty($this->deposit_percent) ? floatval($this->deposit_percent) : "null"); $sql .= ",transport_mode = ".(!empty($this->transport_mode_id) ? "'".$this->db->escape($this->transport_mode_id)."'" : "null"); $sql .= ",mode_reglement_supplier = ".(!empty($this->mode_reglement_supplier_id) ? "'".$this->db->escape($this->mode_reglement_supplier_id)."'" : "null"); $sql .= ",cond_reglement_supplier = ".(!empty($this->cond_reglement_supplier_id) ? "'".$this->db->escape($this->cond_reglement_supplier_id)."'" : "null"); @@ -1651,7 +1656,7 @@ class Societe extends CommonObject $sql .= ', spe.accountancy_code_buy, spe.accountancy_code_sell'; } $sql .= ', s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur, s.parent, s.barcode'; - $sql .= ', s.fk_departement as state_id, s.fk_pays as country_id, s.fk_stcomm, s.mode_reglement, s.cond_reglement, s.transport_mode'; + $sql .= ', s.fk_departement as state_id, s.fk_pays as country_id, s.fk_stcomm, s.mode_reglement, s.cond_reglement, s.deposit_percent, s.transport_mode'; $sql .= ', s.fk_account, s.tva_assuj'; $sql .= ', s.mode_reglement_supplier, s.cond_reglement_supplier, s.transport_mode_supplier'; $sql .= ', s.localtax1_assuj, s.localtax1_value, s.localtax2_assuj, s.localtax2_value, s.fk_prospectlevel, s.default_lang, s.logo, s.logo_squarred'; @@ -1828,6 +1833,7 @@ class Societe extends CommonObject $this->mode_reglement_id = $obj->mode_reglement; $this->cond_reglement_id = $obj->cond_reglement; + $this->deposit_percent = $obj->deposit_percent; $this->transport_mode_id = $obj->transport_mode; $this->mode_reglement_supplier_id = $obj->mode_reglement_supplier; $this->cond_reglement_supplier_id = $obj->cond_reglement_supplier; From 4b3fc4d7f33f3b2489a2e763c0e9e551202b0343 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 13:02:32 +0200 Subject: [PATCH 005/112] NEW: deposit payment terms: add input in payment conditions form --- htdocs/core/class/html.form.class.php | 67 +++++++++++++++++++++------ 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 8deda2ecd09..61b00812efd 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3609,7 +3609,7 @@ class Form dol_syslog(__METHOD__, LOG_DEBUG); - $sql = "SELECT rowid, code, libelle as label"; + $sql = "SELECT rowid, code, libelle as label, deposit_percent"; $sql .= " FROM ".MAIN_DB_PREFIX.'c_payment_term'; $sql .= " WHERE entity IN (".getEntity('c_payment_term').")"; $sql .= " AND active > 0"; @@ -3621,11 +3621,11 @@ class Form $i = 0; while ($i < $num) { $obj = $this->db->fetch_object($resql); - // Si traduction existe, on l'utilise, sinon on prend le libelle par defaut $label = ($langs->trans("PaymentConditionShort".$obj->code) != ("PaymentConditionShort".$obj->code) ? $langs->trans("PaymentConditionShort".$obj->code) : ($obj->label != '-' ? $obj->label : '')); $this->cache_conditions_paiements[$obj->rowid]['code'] = $obj->code; $this->cache_conditions_paiements[$obj->rowid]['label'] = $label; + $this->cache_conditions_paiements[$obj->rowid]['deposit_percent'] = $obj->deposit_percent; $i++; } @@ -3881,9 +3881,10 @@ class Form * @param int $addempty Add an empty entry * @param int $noinfoadmin 0=Add admin info, 1=Disable admin info * @param string $morecss Add more CSS on select tag + * @param float $deposit_percent % of deposit if needed by payment conditions * @return void */ - public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '') + public function select_conditions_paiements($selected = 0, $htmlname = 'condid', $filtertype = -1, $addempty = 0, $noinfoadmin = 0, $morecss = '', $deposit_percent = null) { // phpcs:enable global $langs, $user, $conf; @@ -3901,13 +3902,24 @@ class Form if ($addempty) { print ''; } + + $selectedDepositPercent = null; foreach ($this->cache_conditions_paiements as $id => $arrayconditions) { if ($selected == $id) { - print ''; } print ''; @@ -3915,6 +3927,28 @@ class Form print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1); } print ajax_combobox($htmlname); + print ' '; + print ' + '; } @@ -5099,13 +5133,14 @@ class Form /** * Show a form to select payment conditions * - * @param int $page Page - * @param string $selected Id condition pre-selectionne - * @param string $htmlname Name of select html field - * @param int $addempty Add empty entry + * @param int $page Page + * @param string $selected Id condition pre-selectionne + * @param string $htmlname Name of select html field + * @param int $addempty Add empty entry + * @param float $deposit_percent % of deposit if needed by payment conditions * @return void */ - public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0) + public function form_conditions_reglement($page, $selected = '', $htmlname = 'cond_reglement_id', $addempty = 0, $deposit_percent = null) { // phpcs:enable global $langs; @@ -5113,14 +5148,20 @@ class Form print '
'; print ''; print ''; - $this->select_conditions_paiements($selected, $htmlname, -1, $addempty); + $this->select_conditions_paiements($selected, $htmlname, -1, $addempty, 0, '', $deposit_percent); print ''; print '
'; } else { if ($selected) { $this->load_cache_conditions_paiements(); if (isset($this->cache_conditions_paiements[$selected])) { - print $this->cache_conditions_paiements[$selected]['label']; + $label = $this->cache_conditions_paiements[$selected]['label']; + + if (! empty($this->cache_conditions_paiements[$selected]['deposit_percent'])) { + $label = sprintf($label, ! empty($deposit_percent) ? $deposit_percent : $this->cache_conditions_paiements[$selected]['deposit_percent']); + } + + print $label; } else { $langs->load('errors'); print $langs->trans('ErrorNotInDictionaryPaymentConditions'); From 4d6c1d892b120c314283be4c66a210964d6b4590 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 14:03:35 +0200 Subject: [PATCH 006/112] NEW: deposit payment terms: set deposit percentage in company card --- htdocs/comm/card.php | 6 +++--- htdocs/core/class/commonobject.class.php | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index c9f422d78c8..b511d932f52 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -169,7 +169,7 @@ if (empty($reshook)) { // terms of the settlement if ($action == 'setconditions' && $user->rights->societe->creer) { $object->fetch($id); - $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int')); + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'), GETPOST('cond_reglement_id_deposit_percent', 'int')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -411,9 +411,9 @@ if ($object->id > 0) { print ''; print ''; if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 1); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 1, $object->deposit_percent); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->cond_reglement_id, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id, $object->cond_reglement_id, 'none', 0, $object->deposit_percent); } print ""; print ''; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 7adf7a89079..01f42a73417 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2548,10 +2548,11 @@ abstract class CommonObject /** * Change the payments terms * - * @param int $id Id of new payment terms - * @return int >0 if OK, <0 if KO + * @param int $id Id of new payment terms + * @param float $deposit_percent % of deposit if needed by payment terms + * @return int >0 if OK, <0 if KO */ - public function setPaymentTerms($id) + public function setPaymentTerms($id, $deposit_percent = null) { dol_syslog(get_class($this).'::setPaymentTerms('.$id.')'); if ($this->statut >= 0 || $this->element == 'societe') { @@ -2564,8 +2565,17 @@ abstract class CommonObject $fieldname = 'cond_reglement_supplier'; } + if (empty($deposit_percent) || $deposit_percent < 0) { + $deposit_percent = null; + } + + if ($deposit_percent > 100) { + $deposit_percent = 100; + } + $sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element; $sql .= " SET ".$fieldname." = ".(($id > 0 || $id == '0') ? ((int) $id) : 'NULL'); + $sql .= " , deposit_percent = " . (! empty($deposit_percent) ? floatval($deposit_percent) : 'NULL'); $sql .= ' WHERE rowid='.((int) $this->id); if ($this->db->query($sql)) { @@ -2575,6 +2585,7 @@ abstract class CommonObject $this->cond_reglement_supplier_id = $id; } $this->cond_reglement = $id; // for compatibility + $this->deposit_percent = $deposit_percent; return 1; } else { dol_syslog(get_class($this).'::setPaymentTerms Error '.$sql.' - '.$this->db->error()); From b0aa502ed425aac4b091c8248b8c24d8a1efdd46 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Wed, 29 Sep 2021 14:51:30 +0200 Subject: [PATCH 007/112] NEW: deposit payment terms: set deposit percentage in proposals/orders + get from origin document or company --- htdocs/comm/propal/card.php | 10 ++++++---- htdocs/commande/card.php | 20 +++++++++++++++----- htdocs/core/class/commonobject.class.php | 2 +- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index cff5c5d0e35..12b7138ce51 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -397,6 +397,7 @@ if (empty($reshook)) { $object->warehouse_id = GETPOST('warehouse_id', 'int'); $object->duree_validite = $duration; $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'int'); $object->mode_reglement_id = GETPOST('mode_reglement_id'); $object->fk_account = GETPOST('fk_account', 'int'); $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); @@ -429,6 +430,7 @@ if (empty($reshook)) { $object->warehouse_id = GETPOST('warehouse_id', 'int'); $object->duree_validite = price2num(GETPOST('duree_validite', 'alpha')); $object->cond_reglement_id = GETPOST('cond_reglement_id', 'int'); + $object->deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'int'); $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int'); $object->fk_account = GETPOST('fk_account', 'int'); $object->contact_id = GETPOST('contactid', 'int'); @@ -1358,7 +1360,7 @@ if (empty($reshook)) { $result = $object->set_demand_reason($user, GETPOST('demand_reason_id', 'int')); } elseif ($action == 'setconditions' && $usercancreate) { // Terms of payment - $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int')); + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'), GETPOST('cond_reglement_id_deposit_percent', 'int')); } elseif ($action == 'setremisepercent' && $usercancreate) { $result = $object->set_remise_percent($user, price2num(GETPOST('remise_percent'), '', 2)); } elseif ($action == 'setremiseabsolue' && $usercancreate) { @@ -1647,7 +1649,7 @@ if ($action == 'create') { // Terms of payment print ''.$langs->trans('PaymentConditionsShort').''; print img_picto('', 'paiment'); - $form->select_conditions_paiements((GETPOSTISSET('cond_reglement_id') ? GETPOST('cond_reglement_id', 'int') : $soc->cond_reglement_id), 'cond_reglement_id', -1, 1); + $form->select_conditions_paiements((GETPOSTISSET('cond_reglement_id') ? GETPOST('cond_reglement_id', 'int') : $soc->cond_reglement_id), 'cond_reglement_id', -1, 1, 0, '', (GETPOSTISSET('cond_reglement_id_deposit_percent') ? GETPOST('cond_reglement_id_deposit_percent', 'int') : $soc->deposit_percent)); print ''; // Mode of payment @@ -2155,9 +2157,9 @@ if ($action == 'create') { print ''; print ''; if ($object->statut == Propal::STATUS_DRAFT && $action == 'editconditions' && $usercancreate) { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 0, $object->deposit_percent); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none'); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 0, $object->deposit_percent); } print ''; print ''; diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index decabedc2e8..e933231822a 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -268,6 +268,7 @@ if (empty($reshook)) { $object->ref_client = GETPOST('ref_client', 'alpha'); $object->model_pdf = GETPOST('model'); $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'int'); $object->mode_reglement_id = GETPOST('mode_reglement_id'); $object->fk_account = GETPOST('fk_account', 'int'); $object->availability_id = GETPOST('availability_id'); @@ -548,7 +549,7 @@ if (empty($reshook)) { setEventMessages($object->error, $object->errors, 'errors'); } } elseif ($action == 'setmode' && $usercancreate) { - $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int')); + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int'), GETPOST('mode_reglement_id_deposit_percent', 'int')); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -569,7 +570,7 @@ if (empty($reshook)) { setEventMessages($object->error, $object->errors, 'errors'); } } elseif ($action == 'setconditions' && $usercancreate) { - $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int')); + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int'), GETPOST('cond_reglement_id_deposit_percent', 'int')); if ($result < 0) { dol_print_error($db, $object->error); } else { @@ -1437,6 +1438,10 @@ if ($action == 'create' && $usercancreate) { $currency_code = $conf->currency; + $cond_reglement_id = GETPOST('cond_reglement_id', 'int'); + $deposit_percent = GETPOST('cond_reglement_id_deposit_percent', 'int'); + $mode_reglement_id = GETPOST('mode_reglement_id', 'int'); + if (!empty($origin) && !empty($originid)) { // Parse element/subelement (ex: project_task) $element = $subelement = $origin; @@ -1452,6 +1457,9 @@ if ($action == 'create' && $usercancreate) { if (!$cond_reglement_id) { $cond_reglement_id = $soc->cond_reglement_id; } + if (!$deposit_percent) { + $deposit_percent = $soc->deposit_percent; + } if (!$mode_reglement_id) { $mode_reglement_id = $soc->mode_reglement_id; } @@ -1492,6 +1500,7 @@ if ($action == 'create' && $usercancreate) { $soc = $objectsrc->thirdparty; $cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0)); // TODO maybe add default value option + $deposit_percent = (!empty($objectsrc->deposit_percent) ? $objectsrc->deposit_percent : (!empty($soc->deposit_percent) ? $soc->deposit_percent : null)); $mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0)); $fk_account = (!empty($objectsrc->fk_account) ? $objectsrc->fk_account : (!empty($soc->fk_account) ? $soc->fk_account : 0)); $availability_id = (!empty($objectsrc->availability_id) ? $objectsrc->availability_id : (!empty($soc->availability_id) ? $soc->availability_id : 0)); @@ -1524,6 +1533,7 @@ if ($action == 'create' && $usercancreate) { } } else { $cond_reglement_id = $soc->cond_reglement_id; + $deposit_percent = $soc->deposit_percent; $mode_reglement_id = $soc->mode_reglement_id; $fk_account = $soc->fk_account; $availability_id = $soc->availability_id; @@ -1649,7 +1659,7 @@ if ($action == 'create' && $usercancreate) { // Terms of the settlement print ''.$langs->trans('PaymentConditionsShort').''; print img_picto('', 'paiment'); - $form->select_conditions_paiements($cond_reglement_id, 'cond_reglement_id', - 1, 1); + $form->select_conditions_paiements($cond_reglement_id, 'cond_reglement_id', - 1, 1, 0, '', $deposit_percent); print ''; // Mode de reglement @@ -2215,9 +2225,9 @@ if ($action == 'create' && $usercancreate) { print $form->editfieldkey("PaymentConditionsShort", 'conditions', '', $object, $editenable); print ''; if ($action == 'editconditions') { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 1); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'cond_reglement_id', 1, $object->deposit_percent); } else { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 1); + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id, $object->cond_reglement_id, 'none', 1, $object->deposit_percent); } print ''; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 01f42a73417..2a7c0c87353 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2554,7 +2554,7 @@ abstract class CommonObject */ public function setPaymentTerms($id, $deposit_percent = null) { - dol_syslog(get_class($this).'::setPaymentTerms('.$id.')'); + dol_syslog(get_class($this).'::setPaymentTerms('.$id.', '.var_export($deposit_percent, true).')'); if ($this->statut >= 0 || $this->element == 'societe') { // TODO uniformize field name $fieldname = 'fk_cond_reglement'; From 8cb6cdf1bc1c8a8074fdd5183db913297cdcc0df Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 30 Sep 2021 11:48:32 +0200 Subject: [PATCH 008/112] NEW: deposit payment terms: prefill deposit parameters if coming from an origin with the corresponding payment conditions --- htdocs/compta/facture/card.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 764af7a232a..b2cb45e5b1a 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -3256,10 +3256,21 @@ if ($action == 'create') { 'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')), 'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines') ); - print $form->selectarray('typedeposit', $arraylist, GETPOST('typedeposit', 'aZ09'), 0, 0, 0, '', 1); + $typedeposit = GETPOST('typedeposit', 'aZ09'); + $valuedeposit = GETPOST('valuedeposit', 'int'); + if (empty($typedeposit) && ! empty($objectsrc->deposit_percent)) { + $origin_payment_conditions_deposit_percent = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $objectsrc->cond_reglement_id); + if (! empty($origin_payment_conditions_deposit_percent)) { + $typedeposit = 'variable'; + } + } + if (empty($valuedeposit) && $typedeposit == 'variable' && ! empty($objectsrc->deposit_percent)) { + $valuedeposit = $objectsrc->deposit_percent; + } + print $form->selectarray('typedeposit', $arraylist, $typedeposit, 0, 0, 0, '', 1); print ''; print ''; - print ''.$langs->trans("AmountOrPercent").''; + print ''.$langs->trans("AmountOrPercent").''; print ''; } print ''; From 81ddc6c0f6367c15305bd2223347ca9974ad60ed Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:41:07 +0200 Subject: [PATCH 009/112] NEW: deposit payment terms: generate deposit from proposal --- htdocs/comm/propal/card.php | 100 +++++++ htdocs/compta/facture/class/facture.class.php | 260 ++++++++++++++++++ htdocs/langs/en_US/bills.lang | 6 + 3 files changed, 366 insertions(+) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 12b7138ce51..fc16dcdbe16 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -684,11 +684,46 @@ if (empty($reshook)) { $error++; } + $deposit = null; + $locationTarget = $_SERVER['PHP_SELF'] . '?id=' . $object->id; + + if (!$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'int') > 0) { + $deposit = Facture::createDepositFromOrigin($object, $user, 0, GETPOST('validate_generated_deposit', 'int') > 0); + + if ($deposit) { + setEventMessage('DepositGenerated'); + $locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id; + } else { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + } + } + if (!$error) { $db->commit(); + + if ($deposit && empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + $ret = $deposit->fetch($deposit->id); // Reload to get new records + $outputlangs = $langs; + + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + $outputlangs = new Translate('', $conf); + $outputlangs->setDefaultLang($deposit->thirdparty->default_lang); + $outputlangs->load('products'); + } + + $result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + + if ($result < 0) { + setEventMessages($deposit->error, $deposit->errors, 'errors'); + } + } } else { $db->rollback(); } + + header('Location: ' . $locationTarget); + exit; } } } elseif ($action == 'confirm_reopen' && $usercanclose && !GETPOST('cancel', 'alpha')) { @@ -1934,6 +1969,71 @@ if ($action == 'create') { array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => '') // Field to complete private note (not replace) ); + $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); + + if (! empty($deposit_percent_from_payment_terms)) { + $object->fetchObjectLinked(); + + $eligibleForDepositGeneration = true; + + if (array_key_exists('facture', $object->linkedObjects)) { + foreach ($object->linkedObjectsIds['facture'] as $invoice) { + if ($invoice->type == Facture::TYPE_DEPOSIT) { + $eligibleForDepositGeneration = false; + break; + } + } + } + + if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) { + foreach ($object->linkedObjects['commande'] as $order) { + $order->fetchObjectLinked(); + + if (array_key_exists('facture', $order->linkedObjects)) { + foreach ($order->linkedObjects['facture'] as $invoice) { + if ($invoice->type == Facture::TYPE_DEPOSIT) { + $eligibleForDepositGeneration = false; + break 2; + } + } + } + } + } + + if ($eligibleForDepositGeneration) { + $formquestion[] = array( + 'type' => 'onecolumn', + 'name' => 'generate_deposit,validate_generated_deposit', + 'value' => ' + + + ' + ); + } + } + if (!empty($conf->notification->enabled)) { require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; $notify = new Notify($db); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 22cd946275c..d8265aeef01 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1406,6 +1406,266 @@ class Facture extends CommonInvoice } } + /** + * @param Propal|Commande $origin + * @param User $user + * @param type $notrigger + * @param bool $autoValidate + * @return Facture + */ + static public function createDepositFromOrigin(CommonObject $origin, User $user, $notrigger = 0, $autoValidateDeposit = false, $forceInvoiceDate = null) + { + global $conf, $langs, $hookmanager, $action; + + if (! in_array($origin->element, array('propal', 'commande'))) { + $origin->error = 'ErrorCanOnlyAutomaticallyGenerateADepositFromProposalOrOrder'; // TRAD + return null; + } + + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + + $invoiceDate = ! empty($forceInvoiceDate) ? $forceInvoiceDate : dol_now(); + + if ($invoiceDate > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) { + $origin->error = 'ErrorDateIsInFuture'; + return null; + } + + if ($origin->cond_reglement_id <= 0) { + $origin->error = $langs->trans('ErrorFieldRequired', $langs->transnoentities('PaymentConditionsShort')); + return null; + } + + $payment_conditions_deposit_percent = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $origin->cond_reglement_id); + + if (empty($payment_conditions_deposit_percent)) { + $origin->error = 'ErrorPaymentConditionsNotEligibleToDepositCreation'; + return null; + } + + if (empty($origin->deposit_percent)) { + $origin->error = $langs->trans('ErrorFieldRequired', $langs->transnoentities('DepositPercent')); + return null; + } + + $deposit = new self($origin->db); + $deposit->socid = $origin->socid; + $deposit->type = self::TYPE_DEPOSIT; + $deposit->fk_project = $origin->fk_project; + $deposit->ref_client = $origin->ref_client; + $deposit->date = $invoiceDate; + $deposit->mode_reglement_id = $origin->mode_reglement_id; // CHECK + // TODO Deposit is always due upon reception ? + $deposit->availability_id = $origin->availability_id; + $deposit->demand_reason_id = $origin->demand_reason_id; + $deposit->fk_account = $origin->fk_account; + $deposit->fk_incoterms = $origin->fk_incoterms; + $deposit->location_incoterms = $origin->location_incoterms; + $deposit->fk_multicurrency = $origin->fk_multicurrency; + $deposit->multicurrency_code = $origin->multicurrency_code; + $deposit->multicurrency_tx = $origin->multicurrency_tx; + $deposit->module_source = $origin->module_source; + $deposit->pos_source = $origin->pos_source; + $deposit->model_pdf = 'crabe'; + + $modelByTypeConfName = 'FACTURE_ADDON_PDF_' . $deposit->type; + + if (!empty($conf->global->$modelByTypeConfName)) { + $deposit->model_pdf = $conf->global->$modelByTypeConfName; + } elseif (!empty($conf->global->FACTURE_ADDON_PDF)) { + $deposit->model_pdf = $conf->global->FACTURE_ADDON_PDF; + } + + if (empty($conf->global->MAIN_DISABLE_PROPAGATE_NOTES_FROM_ORIGIN)) { + $deposit->note_private = $origin->note_private; + $deposit->note_public = $origin->note_public; + } + + $deposit->origin = $origin->element; + $deposit->origin_id = $origin->id; + + $origin->fetch_optionals(); + + foreach ($origin->array_options as $extrakey => $value) { + $deposit->array_options[$extrakey] = $value; + } + + $deposit->linked_objects[$deposit->origin] = $deposit->origin_id; + + $deposit->context['createdepositfromorigin'] = 'createdepositfromorigin'; + + $origin->db->begin(); + + // Facture::create() also imports contact from origin + $createReturn = $deposit->create($user, $notrigger); + + if ($createReturn <= 0) { + $origin->db->rollback(); + $origin->error = $deposit->error; + $origin->errors = $deposit->errors; + return null; + } + + $amount_ttc_diff = 0; + $amountdeposit = array(); + + if (! empty($conf->global->MAIN_DEPOSIT_MULTI_TVA)) { + $amount = $origin->total_ttc * ($origin->deposit_percent / 100); + + $TTotalByTva = array(); + foreach ($origin->lines as &$line) { + if (!empty($line->special_code)) { + continue; + } + $TTotalByTva[$line->tva_tx] += $line->total_ttc; + } + + foreach ($TTotalByTva as $tva => &$total) { + $coef = $total / $origin->total_ttc; // Calc coef + $am = $amount * $coef; + $amount_ttc_diff += $am; + $amountdeposit[$tva] += $am / (1 + $tva / 100); // Convert into HT for the addline + } + } else { + $totalamount = 0; + $lines = $origin->lines; + $numlines = count($lines); + for ($i = 0; $i < $numlines; $i++) { + if (empty($lines[$i]->qty)) { + continue; // We discard qty=0, it is an option + } + if (!empty($lines[$i]->special_code)) { + continue; // We discard special_code (frais port, ecotaxe, option, ...) + } + + $totalamount += $lines[$i]->total_ht; // Fixme : is it not for the customer ? Shouldn't we take total_ttc ? + $tva_tx = $lines[$i]->tva_tx; + $amountdeposit[$tva_tx] += ($lines[$i]->total_ht * $origin->deposit_percent) / 100; + } + + if ($totalamount == 0) { + $amountdeposit[0] = 0; + } + + $amount_ttc_diff = $amountdeposit[0]; + } + + foreach ($amountdeposit as $tva => $amount) { + if (empty($amount)) { + continue; + } + + $descline = '(DEPOSIT) ('. $origin->deposit_percent .'%) - '.$origin->ref; + + $addlineResult = $deposit->addline( + $descline, + $amount, // subprice + 1, // quantity + $tva, // vat rate + 0, // localtax1_tx + 0, // localtax2_tx + (empty($conf->global->INVOICE_PRODUCTID_DEPOSIT) ? 0 : $conf->global->INVOICE_PRODUCTID_DEPOSIT), // fk_product + 0, // remise_percent + 0, // date_start + 0, // date_end + 0, + $lines[$i]->info_bits, // info_bits + 0, + 'HT', + 0, + 0, // product_type + 1, + $lines[$i]->special_code, + $deposit->origin, + 0, + 0, + 0, + 0 + //,$langs->trans('Deposit') //Deprecated + ); + + if ($addlineResult < 0) { + $origin->db->rollback(); + $origin->error = $deposit->error; + $origin->errors = $deposit->errors; + return null; + } + } + + $diff = $deposit->total_ttc - $amount_ttc_diff; + + if (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA) && $diff != 0) { + $deposit->fetch_lines(); + $subprice_diff = $deposit->lines[0]->subprice - $diff / (1 + $deposit->lines[0]->tva_tx / 100); + + $updatelineResult = $deposit->updateline( + $deposit->lines[0]->id, + $deposit->lines[0]->desc, + $subprice_diff, + $deposit->lines[0]->qty, + $deposit->lines[0]->remise_percent, + $deposit->lines[0]->date_start, + $deposit->lines[0]->date_end, + $deposit->lines[0]->tva_tx, + 0, + 0, + 'HT', + $deposit->lines[0]->info_bits, + $deposit->lines[0]->product_type, + 0, + 0, + 0, + $deposit->lines[0]->pa_ht, + $deposit->lines[0]->label, + 0, + array(), + 100 + ); + + if ($updatelineResult < 0) { + $origin->db->rollback(); + $origin->error = $deposit->error; + $origin->errors = $deposit->errors; + return null; + } + } + + + if (! is_object($hookmanager)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php'; + $hookmanager = new HookManager($origin->db); + } + + $hookmanager->initHooks(array('invoicedao')); + + $parameters = array('objFrom' => $origin); + $reshook = $hookmanager->executeHooks('createFrom', $parameters, $deposit, $action); // Note that $action and $object may have been + // modified by hook + if ($reshook < 0) { + $origin->db->rollback(); + $origin->error = $hookmanager->error; + $origin->errors = $hookmanager->errors; + return null; + } + + if (! empty($autoValidateDeposit)) { + $validateReturn = $deposit->validate($user, '', 0, $notrigger); + + if ($validateReturn < 0) { + $origin->db->rollback(); + $origin->error = $deposit->error; + $origin->errors = $deposit->errors; + return null; + } + } + + unset($object->context['createdepositfromorigin']); + + $origin->db->commit(); + + return $deposit; + } + /** * Return clicable link of object (with eventually picto) * diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 86344105168..88f653473d5 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -425,6 +425,12 @@ VarAmount=Variable amount (%% tot.) VarAmountOneLine=Variable amount (%% tot.) - 1 line with label '%s' VarAmountAllLines=Variable amount (%% tot.) - all lines from origin DepositPercent=Deposit %% +PaymentConditionPermitsDepositGenerationSelected=You can generate a deposit invoice with the payment conditions you selected +GenerateDeposit=Generate a %s%% deposit invoice +ValidateGeneratedDeposit=Validate the generated deposit +DepositGenerated=Deposit generated +ErrorCanOnlyAutomaticallyGenerateADepositFromProposalOrOrder=You can only automatically generate a deposit from a proposal or an order +ErrorPaymentConditionsNotEligibleToDepositCreation=The chose payment conditions are not eligible for automatic deposit generation # PaymentType PaymentTypeVIR=Bank transfer PaymentTypeShortVIR=Bank transfer From e1c5d01361c92dc818ec0cdddce4cc9630929555 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 30 Sep 2021 10:43:40 +0000 Subject: [PATCH 010/112] Fixing style errors. --- htdocs/comm/propal/card.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index fc16dcdbe16..6cdcb94e169 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -1969,9 +1969,9 @@ if ($action == 'create') { array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => '') // Field to complete private note (not replace) ); - $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); + $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); - if (! empty($deposit_percent_from_payment_terms)) { + if (! empty($deposit_percent_from_payment_terms)) { $object->fetchObjectLinked(); $eligibleForDepositGeneration = true; @@ -2032,7 +2032,7 @@ if ($action == 'create') { ' ); } - } + } if (!empty($conf->notification->enabled)) { require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; From d74776622d87b8361923bb4e166c2621a77259b8 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Thu, 30 Sep 2021 12:57:00 +0200 Subject: [PATCH 011/112] NEW: deposit payment terms: check invoice module activation + rights --- htdocs/comm/propal/card.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 6cdcb94e169..039b8fc25ec 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -687,7 +687,12 @@ if (empty($reshook)) { $deposit = null; $locationTarget = $_SERVER['PHP_SELF'] . '?id=' . $object->id; - if (!$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'int') > 0) { + $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); + + if ( + !$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'int') > 0 + && ! empty($deposit_percent_from_payment_terms) && ! empty($conf->facture->enabled) && ! empty($user->rights->facture->creer) + ) { $deposit = Facture::createDepositFromOrigin($object, $user, 0, GETPOST('validate_generated_deposit', 'int') > 0); if ($deposit) { @@ -1971,7 +1976,7 @@ if ($action == 'create') { $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); - if (! empty($deposit_percent_from_payment_terms)) { + if (! empty($deposit_percent_from_payment_terms) && ! empty($conf->facture->enabled) && ! empty($user->rights->facture->creer)) { $object->fetchObjectLinked(); $eligibleForDepositGeneration = true; @@ -2032,7 +2037,7 @@ if ($action == 'create') { ' ); } - } + } if (!empty($conf->notification->enabled)) { require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; From f6b9336a82649d0eb4ad44a6ea8657faf026e633 Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Thu, 30 Sep 2021 10:59:29 +0000 Subject: [PATCH 012/112] Fixing style errors. --- htdocs/comm/propal/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 039b8fc25ec..8002c199efc 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -2037,7 +2037,7 @@ if ($action == 'create') { ' ); } - } + } if (!empty($conf->notification->enabled)) { require_once DOL_DOCUMENT_ROOT.'/core/class/notify.class.php'; From 087157890e77c650244b6c913aef329dd481ab01 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Mon, 4 Oct 2021 15:06:52 +0200 Subject: [PATCH 013/112] FIX: deposit payment terms: unused variable --- htdocs/comm/propal/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 8002c199efc..83e905461c6 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -711,7 +711,7 @@ if (empty($reshook)) { $ret = $deposit->fetch($deposit->id); // Reload to get new records $outputlangs = $langs; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) { + if ($conf->global->MAIN_MULTILANGS) { $outputlangs = new Translate('', $conf); $outputlangs->setDefaultLang($deposit->thirdparty->default_lang); $outputlangs->load('products'); From 6580c2e30837e04a3bee75d6e16c3c37c68759db Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Mon, 4 Oct 2021 15:07:27 +0200 Subject: [PATCH 014/112] FIX: deposit payment terms: correctly untag deposit as created from an origin --- htdocs/compta/facture/class/facture.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index d8265aeef01..e209994c9ae 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1659,7 +1659,7 @@ class Facture extends CommonInvoice } } - unset($object->context['createdepositfromorigin']); + unset($deposit->context['createdepositfromorigin']); $origin->db->commit(); From 1b2494855d60dd0a4e1be8b66de5b4d867202736 Mon Sep 17 00:00:00 2001 From: Marc de Lima Lucio <68746600+marc-dll@users.noreply.github.com> Date: Mon, 4 Oct 2021 18:09:24 +0200 Subject: [PATCH 015/112] NEW: deposit payment terms: set required invoice fields + filter payment terms with deposits in select + UI --- htdocs/comm/propal/card.php | 95 +++++++++++++++---- htdocs/compta/facture/class/facture.class.php | 24 +++-- htdocs/core/class/html.form.class.php | 7 +- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 83e905461c6..8dffa7ee5c3 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -690,10 +690,17 @@ if (empty($reshook)) { $deposit_percent_from_payment_terms = getDictvalue(MAIN_DB_PREFIX . 'c_payment_term', 'deposit_percent', $object->cond_reglement_id); if ( - !$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'int') > 0 + !$error && GETPOST('statut', 'int') == $object::STATUS_SIGNED && GETPOST('generate_deposit', 'alpha') == 'on' && ! empty($deposit_percent_from_payment_terms) && ! empty($conf->facture->enabled) && ! empty($user->rights->facture->creer) ) { - $deposit = Facture::createDepositFromOrigin($object, $user, 0, GETPOST('validate_generated_deposit', 'int') > 0); + $date = dol_mktime(0, 0, 0, GETPOST('datefmonth', 'int'), GETPOST('datefday', 'int'), GETPOST('datefyear', 'int')); + $forceFields = array(); + + if (GETPOSTISSET('date_pointoftax')) { + $forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOST('date_pointoftaxmonth', 'int'), GETPOST('date_pointoftaxday', 'int'), GETPOST('date_pointoftaxyear', 'int')); + } + + $deposit = Facture::createDepositFromOrigin($object, $date, GETPOST('cond_reglement_id', 'int'), $user, 0, GETPOST('validate_generated_deposit', 'alpha') == 'on', $forceFields); if ($deposit) { setEventMessage('DepositGenerated'); @@ -2005,33 +2012,89 @@ if ($action == 'create') { } } + if ($eligibleForDepositGeneration) { + $formquestion[] = array( + 'type' => 'checkbox', + 'tdclass' => 'showonlyifsigned', + 'name' => 'generate_deposit', + 'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('PaymentConditionPermitsDepositGenerationSelected')) + ); + + $formquestion[] = array( + 'type' => 'date', + 'tdclass' => 'fieldrequired showonlyifgeneratedeposit', + 'name' => 'datef', + 'label' => $langs->trans('DateInvoice'), + 'value' => dol_now(), + 'datenow' => true + ); + + if (! empty($conf->global->INVOICE_POINTOFTAX_DATE)) { + $formquestion[] = array( + 'type' => 'date', + 'tdclass' => 'fieldrequired showonlyifgeneratedeposit', + 'name' => 'date_pointoftax', + 'label' => $langs->trans('DatePointOfTax'), + 'value' => dol_now(), + 'datenow' => true + ); + } + + ob_start(); + $form->select_conditions_paiements(0, 'cond_reglement_id', 1, 0, 0, 'minwidth200'); // TODO param 3 + $paymentTermsSelect = ob_get_clean(); + + $formquestion[] = array( + 'type' => 'other', + 'tdclass' => 'fieldrequired showonlyifgeneratedeposit', + 'name' => 'cond_reglement_id', + 'label' => $langs->trans('PaymentTerm'), + 'value' => $paymentTermsSelect + ); + + $formquestion[] = array( + 'type' => 'checkbox', + 'tdclass' => 'showonlyifgeneratedeposit', + 'name' => 'validate_generated_deposit', + 'label' => $langs->trans('ValidateGeneratedDeposit') + ); + $formquestion[] = array( 'type' => 'onecolumn', - 'name' => 'generate_deposit,validate_generated_deposit', 'value' => ' - ' diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index e209994c9ae..bf4271ef7d0 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1411,9 +1411,10 @@ class Facture extends CommonInvoice * @param User $user * @param type $notrigger * @param bool $autoValidate + * @param array $overrideFields * @return Facture */ - static public function createDepositFromOrigin(CommonObject $origin, User $user, $notrigger = 0, $autoValidateDeposit = false, $forceInvoiceDate = null) + static public function createDepositFromOrigin(CommonObject $origin, $date, $cond_reglement_id, User $user, $notrigger = 0, $autoValidateDeposit = false, $overrideFields = array()) { global $conf, $langs, $hookmanager, $action; @@ -1422,16 +1423,19 @@ class Facture extends CommonInvoice return null; } + if (empty($date)) { + $origin->error = $langs->trans('ErrorFieldRequired', $langs->transnoentities('DateInvoice')); + return null; + } + require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; - $invoiceDate = ! empty($forceInvoiceDate) ? $forceInvoiceDate : dol_now(); - - if ($invoiceDate > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) { + if ($date > (dol_get_last_hour(dol_now('tzuserrel')) + (empty($conf->global->INVOICE_MAX_FUTURE_DELAY) ? 0 : $conf->global->INVOICE_MAX_FUTURE_DELAY))) { $origin->error = 'ErrorDateIsInFuture'; return null; } - if ($origin->cond_reglement_id <= 0) { + if ($cond_reglement_id <= 0) { $origin->error = $langs->trans('ErrorFieldRequired', $langs->transnoentities('PaymentConditionsShort')); return null; } @@ -1453,9 +1457,9 @@ class Facture extends CommonInvoice $deposit->type = self::TYPE_DEPOSIT; $deposit->fk_project = $origin->fk_project; $deposit->ref_client = $origin->ref_client; - $deposit->date = $invoiceDate; - $deposit->mode_reglement_id = $origin->mode_reglement_id; // CHECK - // TODO Deposit is always due upon reception ? + $deposit->date = $date; + $deposit->mode_reglement_id = $origin->mode_reglement_id; + $deposit->cond_reglement_id = $cond_reglement_id; $deposit->availability_id = $origin->availability_id; $deposit->demand_reason_id = $origin->demand_reason_id; $deposit->fk_account = $origin->fk_account; @@ -1492,6 +1496,10 @@ class Facture extends CommonInvoice $deposit->linked_objects[$deposit->origin] = $deposit->origin_id; + foreach ($overrideFields as $key => $value) { + $deposit->$key = $value; + } + $deposit->context['createdepositfromorigin'] = 'createdepositfromorigin'; $origin->db->begin(); diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 61b00812efd..98ea68e5542 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3877,7 +3877,7 @@ class Form * * @param int $selected Id of payment term to preselect by default * @param string $htmlname Nom de la zone select - * @param int $filtertype Not used + * @param int $filtertype If > 0, don't include payment terms with deposit percentage (for invoices) * @param int $addempty Add an empty entry * @param int $noinfoadmin 0=Add admin info, 1=Disable admin info * @param string $morecss Add more CSS on select tag @@ -3905,6 +3905,10 @@ class Form $selectedDepositPercent = null; foreach ($this->cache_conditions_paiements as $id => $arrayconditions) { + if ($filtertype > 0 && ! empty($arrayconditions['deposit_percent'])) { + continue; + } + if ($selected == $id) { $selectedDepositPercent = ! empty($deposit_percent) ? $deposit_percent : $arrayconditions['deposit_percent']; print '