diff --git a/ChangeLog b/ChangeLog
index 95a4a7a3ae6..5808fbf313f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,19 +16,12 @@ NEW: A lot of fix into english text after a small proofreading campaign (still n
NEW: All main menu entries are using the picto of the module
NEW: Add a copy to clipboard button on some fields
NEW: Add an example of scheduled job to send email reminder for unpaid invoices
-NEW: Accountancy - Add FEC import
-NEW: Accountancy - Add a confirmation form with options on export
-NEW: Accountancy - Add select date from/to in already bind customer and supplier list
-NEW: Accountancy - Format FEC - Add new field DateLimitReglmt
-NEW: Accountancy - In ledger & journals, show link on bank transaction
-NEW: Accountancy - Possibility to filter on journals in balance
-NEW: Accountancy - Add a page to list subledger accounts
-NEW: add the Channel column into the list of orders
NEW: Add a check to avoid an invoice date in the future
NEW: Add some color and picto for the direction of movement
+NEW: add the column "Channel" into the list of orders
NEW: Add the column "alias" of company in the list of proposal, order, invoice
NEW: Add the column "Office phone" and "User mobile" in user list
-NEW: Add the column "Price level"in thirdparty list
+NEW: Add the column "Price level" in thirdparty list
NEW: Add some company information in the dropdown login menu
NEW: Add constant MAIN_BUGTRACK_URL to set a custom url to redirect to when clicking on link "declare a bug"
NEW: Add contact tag and bulk email status on the thirdparty + contact create form
@@ -92,13 +85,22 @@ NEW: When a doc file is shared, link is visible from the main page of doc.
NEW: #16378 More E-Mail Contact substitution Values for better salutation
NEW: option to keep the "Automatically create a total payment" checkbox empty on the tax creation page
+ Accountancy
+NEW: Accountancy - Add FEC import
+NEW: Accountancy - Add a confirmation form with options on export
+NEW: Accountancy - Add select date from/to in already bind customer and supplier list
+NEW: Accountancy - Format FEC - Add new field DateLimitReglmt
+NEW: Accountancy - In ledger & journals, show link on bank transaction
+NEW: Accountancy - Possibility to filter on journals in balance
+NEW: Accountancy - Add a page to list subledger accounts
+
ECM/GED
-NEW: Add db fields note_public and note_private for ECM module
-NEW: Can filter files in GED on status Shared/Not shared
+NEW: add DB fields note_public and note_private for ECM module
+NEW: Can filter files in ECM/GED on status Shared/Not shared
Members
NEW: #17292 default subscription amount by adherent type
-NEW: Option to automatically create a login/user when a new subscription of a member is done online
+NEW: option to automatically create a login/user when a new subscription of a member is done online
NEW: option to select membership type on the online payment page for membership subscription or renewal
Projects/Tasks
@@ -122,17 +124,17 @@ NEW: option for TakePOS to show the total price without tax
NEW: more permissions in TakePOS (can edit added line, can modify once order sent to kitchen)
Third-Parties
-NEW: Can set a Warehouse on a Thirdparty
+NEW: can set a warehouse on a Thirdparty
Tickets
NEW: can use captcha on public page to create a ticket #16347
NEW: can set if a ticket group is visible on public interface or not
Warehouse
-NEW: Can make massive stock transfers from a CSV file
-NEW: Stock movement list - Add more complete date field
-NEW: Can set a Warehouse on a Thirdparty
+NEW: can make massive stock transfers from a CSV file
+NEW: Stock movement list - add more complete date field
NEW: can set a warehouse in a proposal
+NEW: can set a warehouse on a Thirdparty
Website Module
NEW: #17113 Can upload a favicon in website module
@@ -147,10 +149,10 @@ NEW: start new experimental module Knowledge Management
NEW: start new experimental module Workstations Management
new Options
-NEW: Add option CONTRACT_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
-NEW: Add option SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
-NEW: Add option MAIN_SECURITY_ANTI_SSRF_SERVER_IP to define list of IPs that are local IPs
-NEW: Add option SOCIETE_DISABLE_WORKFORCE to hide staff field
+NEW: add option CONTRACT_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
+NEW: add option SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD to make generated doc automatically shared
+NEW: add option MAIN_SECURITY_ANTI_SSRF_SERVER_IP to define list of IPs that are local IPs
+NEW: add option SOCIETE_DISABLE_WORKFORCE to hide staff field
For developers:
@@ -164,10 +166,7 @@ NEW: Add experimental repair script to switch to dynamic row format and utf8mb4
NEW: add form confirm hook on company card
NEW: Add function showValueWithClipboardCPButton() to add a copy/paste
NEW: Add hook addSectionECMAuto method to add custom diretory into ECM auto files
-NEW: Add native compression in rest apis
-NEW: Product Variants API, add variant stock to response by parameter
NEW: Upgrade Stripe PHP lib to 7.67.0
-NEW: Add link to OpenAPI specifications xml file in REST API module setup: swagger.json file can be included into external tools like redoc
NEW: Support sepa_debit in stripe paymentmethods list
NEW: Update doleditor.class.php for easily activate SCAYT
NEW: Add triggers in the function add_object_linked(), updateObjectLinked() and deleteObjectLinked()
@@ -181,8 +180,11 @@ NEW: unit selection on object edit line
NEW: #13739 #17390 Product API route added to get product stock and product with or without variants
APIs
-NEW: API Add option $includeifobjectisused to get a product
-NEW: API Get the list of product ids only
+NEW: API add option $includeifobjectisused to get a product
+NEW: API get the list of product ids only
+NEW: add native compression in REST APIs
+NEW: Product Variants API, add variant stock to response by parameter
+NEW: add link to OpenAPI specifications XML file in REST API module setup: swagger.json file can be included into external tools like redoc
WARNING:
diff --git a/htdocs/accountancy/closure/index.php b/htdocs/accountancy/closure/index.php
index bcb3d7901f5..b612762d358 100644
--- a/htdocs/accountancy/closure/index.php
+++ b/htdocs/accountancy/closure/index.php
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
+ * along with this program. If not, see .
*
*/
@@ -124,7 +124,11 @@ if ($action == 'validate_movements_confirm' && !empty($user->rights->accounting-
$form = new Form($db);
$formaccounting = new FormAccounting($db);
-llxHeader('', $langs->trans("Closure"));
+$title = $langs->trans('Closure');
+
+$help_url ='EN:Module_Double_Entry_Accounting';
+
+llxHeader('', $title, $help_url);
if ($action == 'validate_movements') {
$form_question = array();
diff --git a/htdocs/core/tpl/document_actions_post_headers.tpl.php b/htdocs/core/tpl/document_actions_post_headers.tpl.php
index 45090824248..4ec69efbac8 100644
--- a/htdocs/core/tpl/document_actions_post_headers.tpl.php
+++ b/htdocs/core/tpl/document_actions_post_headers.tpl.php
@@ -47,6 +47,9 @@ if (!isset($permission)) {
if (!isset($permtoedit)) {
$permtoedit = $permissiontoadd;
}
+if (!isset($param)) {
+ $param = '';
+}
// Drag and drop for up and down allowed on product, thirdparty, ...
// The drag and drop call the page core/ajax/row.php
diff --git a/htdocs/mrp/class/api_mos.class.php b/htdocs/mrp/class/api_mos.class.php
index 33d4a108f17..22420733a45 100644
--- a/htdocs/mrp/class/api_mos.class.php
+++ b/htdocs/mrp/class/api_mos.class.php
@@ -327,6 +327,12 @@ class Mos extends DolibarrApi
if ($field == 'autoclose') {
$autoclose = $value;
}
+ if ($field == 'arraytoconsume') {
+ $arraytoconsume = $value;
+ }
+ if ($field == 'arraytoproduce') {
+ $arraytoproduce = $value;
+ }
}
if (empty($labelmovement)) {
@@ -337,7 +343,289 @@ class Mos extends DolibarrApi
}
// TODO Add code for consume and produce...
- throw new RestException(500, "Feature not yet available");
+ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+ require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
+ dol_include_once('/mrp/lib/mrp_mo.lib.php');
+ $stockmove = new MouvementStock($this->db);
+ if (!empty($arraytoconsume) && !empty($arraytoproduce)) {
+ $pos = 0;
+ $arrayofarrayname = array("arraytoconsume","arraytoproduce");
+ foreach ($arrayofarrayname as $arrayname) {
+ foreach ($$arrayname as $value) {
+ $tmpproduct = new Product($this->db);
+ if (empty($value["objectid"])) {
+ throw new RestException(500, "Field objectid required in ".$arrayname);
+ }
+ $tmpproduct->fetch($value["qty"]);
+ if (empty($value["qty"])) {
+ throw new RestException(500, "Field qty required in ".$arrayname);
+ }
+ if ($value["qty"]!=0) {
+ $qtytoprocess = $value["qty"];
+ if (isset($value["fk_warehouse"])) { // If there is a warehouse to set
+ if (!($value["fk_warehouse"] > 0)) { // If there is no warehouse set.
+ throw new RestException(500, "Field fk_warehouse must be > 0 in ".$arrayname);
+ $error++;
+ }
+ if ($tmpproduct->status_batch) {
+ throw new RestException(500, "Product ".$tmpproduct->ref."must be in batch");
+ $error++;
+ }
+ }
+ $idstockmove = 0;
+ if (!$error && $value["fk_warehouse"] > 0) {
+ // Record stock movement
+ $id_product_batch = 0;
+ $stockmove->origin = $this->mo;
+ if ($qtytoprocess >= 0) {
+ $moline = new MoLine($this->db);
+ $moline->fk_mo = $this->mo->id;
+ $moline->position = $pos;
+ $moline->fk_product = $value["objectid"];
+ $moline->fk_warehouse = $value["fk_warehouse"];
+ $moline->qty = $qtytoprocess;
+ $moline->batch = $tmpproduct->status_batch;
+ $moline->role = 'toproduce';
+ $moline->fk_mrp_production = "";
+ $moline->fk_stock_movement = $idstockmove;
+ $moline->fk_user_creat = DolibarrApiAccess::$user->id;
+
+ $resultmoline = $moline->create(DolibarrApiAccess::$user);
+ if ($resultmoline <= 0) {
+ $error++;
+ throw new RestException(500, $moline->error);
+ }
+ $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ } else {
+ $moline = new MoLine($this->db);
+ $moline->fk_mo = $this->mo->id;
+ $moline->position = $pos;
+ $moline->fk_product = $value["objectid"];
+ $moline->fk_warehouse = $value["fk_warehouse"];
+ $moline->qty = $qtytoprocess;
+ $moline->batch = $tmpproduct->status_batch;
+ $moline->role = 'toconsume';
+ $moline->fk_mrp_production = "";
+ $moline->fk_stock_movement = $idstockmove;
+ $moline->fk_user_creat = DolibarrApiAccess::$user->id;
+
+ $resultmoline = $moline->create(DolibarrApiAccess::$user);
+ if ($resultmoline <= 0) {
+ $error++;
+ throw new RestException(500, $moline->error);
+ }
+ $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $value["objectid"], $value["fk_warehouse"], $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ }
+ if ($idstockmove < 0) {
+ $error++;
+ throw new RestException(500, $stockmove->error);
+ }
+ }
+ if (!$error) {
+ // Record consumption
+ $moline = new MoLine($this->db);
+ $moline->fk_mo = $this->mo->id;
+ $moline->position = $pos;
+ $moline->fk_product = $value["objectid"];
+ $moline->fk_warehouse = $value["fk_warehouse"];
+ $moline->qty = $qtytoprocess;
+ $moline->batch = $tmpproduct->status_batch;
+ if ($arrayname == "arraytoconsume") {
+ $moline->role = 'consumed';
+ } else {
+ $moline->role = 'produced';
+ }
+ $moline->fk_mrp_production = "";
+ $moline->fk_stock_movement = $idstockmove;
+ $moline->fk_user_creat = DolibarrApiAccess::$user->id;
+
+ $resultmoline = $moline->create(DolibarrApiAccess::$user);
+ if ($resultmoline <= 0) {
+ $error++;
+ throw new RestException(500, $moline->error);
+ }
+
+ $pos++;
+ }
+ }
+ }
+ }
+ if (!$error) {
+ $consumptioncomplete = true;
+ $productioncomplete = true;
+
+ if ($autoclose <= 0) {
+ $consumptioncomplete = false;
+ $productioncomplete = false;
+ }
+ }
+ } else {
+ $pos = 0;
+ foreach ($this->mo->lines as $line) {
+ if ($line->role == 'toconsume') {
+ $tmpproduct = new Product($this->db);
+ $tmpproduct->fetch($line->fk_product);
+ if ($line->qty != 0) {
+ $qtytoprocess = $line->qty;
+ if (isset($line->fk_warehouse)) { // If there is a warehouse to set
+ if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
+ $langs->load("errors");
+ throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
+ $error++;
+ }
+ if ($tmpproduct->status_batch) {
+ $langs->load("errors");
+ throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
+ $error++;
+ }
+ }
+ $idstockmove = 0;
+ if (!$error && $line->fk_warehouse > 0) {
+ // Record stock movement
+ $id_product_batch = 0;
+ $stockmove->origin = $this->mo;
+ if ($qtytoprocess >= 0) {
+ $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ } else {
+ $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ }
+ if ($idstockmove < 0) {
+ $error++;
+ throw new RestException(500, $stockmove->error);
+ }
+ }
+ if (!$error) {
+ // Record consumption
+ $moline = new MoLine($this->db);
+ $moline->fk_mo = $this->mo->id;
+ $moline->position = $pos;
+ $moline->fk_product = $line->fk_product;
+ $moline->fk_warehouse = $line->fk_warehouse;
+ $moline->qty = $qtytoprocess;
+ $moline->batch = $tmpproduct->status_batch;
+ $moline->role = 'consumed';
+ $moline->fk_mrp_production = $line->id;
+ $moline->fk_stock_movement = $idstockmove;
+ $moline->fk_user_creat = DolibarrApiAccess::$user->id;
+
+ $resultmoline = $moline->create(DolibarrApiAccess::$user);
+ if ($resultmoline <= 0) {
+ $error++;
+ throw new RestException(500, $moline->error);
+ }
+
+ $pos++;
+ }
+ }
+ }
+ }
+ $pos = 0;
+ foreach ($this->mo->lines as $line) {
+ if ($line->role == 'toproduce') {
+ $tmpproduct = new Product($this->db);
+ $tmpproduct->fetch($line->fk_product);
+ if ($line->qty != 0) {
+ $qtytoprocess = $line->qty;
+ if (isset($line->fk_warehouse)) { // If there is a warehouse to set
+ if (!($line->fk_warehouse > 0)) { // If there is no warehouse set.
+ $langs->load("errors");
+ throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Warehouse"), $tmpproduct->ref));
+ $error++;
+ }
+ if ($tmpproduct->status_batch) {
+ $langs->load("errors");
+ throw new RestException(500, $langs->trans("ErrorFieldRequiredForProduct", $langs->transnoentitiesnoconv("Batch"), $tmpproduct->ref));
+ $error++;
+ }
+ }
+ $idstockmove = 0;
+ if (!$error && $line->fk_warehouse > 0) {
+ // Record stock movement
+ $id_product_batch = 0;
+ $stockmove->origin = $this->mo;
+ if ($qtytoprocess >= 0) {
+ $idstockmove = $stockmove->livraison(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ } else {
+ $idstockmove = $stockmove->reception(DolibarrApiAccess::$user, $line->fk_product, $line->fk_warehouse, $qtytoprocess, 0, $labelmovement, dol_now(), '', '', $tmpproduct->status_batch, $id_product_batch, $codemovement);
+ }
+ if ($idstockmove < 0) {
+ $error++;
+ throw new RestException(500, $stockmove->error);
+ }
+ }
+ if (!$error) {
+ // Record consumption
+ $moline = new MoLine($this->db);
+ $moline->fk_mo = $this->mo->id;
+ $moline->position = $pos;
+ $moline->fk_product = $line->fk_product;
+ $moline->fk_warehouse = $line->fk_warehouse;
+ $moline->qty = $qtytoprocess;
+ $moline->batch = $tmpproduct->status_batch;
+ $moline->role = 'produced';
+ $moline->fk_mrp_production = $line->id;
+ $moline->fk_stock_movement = $idstockmove;
+ $moline->fk_user_creat = DolibarrApiAccess::$user->id;
+
+ $resultmoline = $moline->create(DolibarrApiAccess::$user);
+ if ($resultmoline <= 0) {
+ $error++;
+ throw new RestException(500, $moline->error);
+ }
+
+ $pos++;
+ }
+ }
+ }
+ }
+
+ if (!$error) {
+ $consumptioncomplete = true;
+ $productioncomplete = true;
+
+ if ($autoclose > 0) {
+ foreach ($this->mo->lines as $line) {
+ if ($line->role == 'toconsume') {
+ $arrayoflines = $this->mo->fetchLinesLinked('consumed', $line->id);
+ $alreadyconsumed = 0;
+ foreach ($arrayoflines as $line2) {
+ $alreadyconsumed += $line2['qty'];
+ }
+
+ if ($alreadyconsumed < $line->qty) {
+ $consumptioncomplete = false;
+ }
+ }
+ if ($line->role == 'toproduce') {
+ $arrayoflines = $this->mo->fetchLinesLinked('produced', $line->id);
+ $alreadyproduced = 0;
+ foreach ($arrayoflines as $line2) {
+ $alreadyproduced += $line2['qty'];
+ }
+
+ if ($alreadyproduced < $line->qty) {
+ $productioncomplete = false;
+ }
+ }
+ }
+ } else {
+ $consumptioncomplete = false;
+ $productioncomplete = false;
+ }
+ }
+ }
+ // Update status of MO
+ dol_syslog("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
+ //var_dump("consumptioncomplete = ".$consumptioncomplete." productioncomplete = ".$productioncomplete);
+ if ($consumptioncomplete && $productioncomplete) {
+ $result = $this->mo->setStatut($this->mo::STATUS_PRODUCED, 0, '', 'MRP_MO_PRODUCED');
+ } else {
+ $result = $this->mo->setStatut($this->mo::STATUS_INPROGRESS, 0, '', 'MRP_MO_PRODUCED');
+ }
+ if ($result <= 0) {
+ $error++;
+ throw new RestException(500, $this->mo->error);
+ }
return $this->mo->id;
}
diff --git a/htdocs/opensurvey/wizard/choix_date.php b/htdocs/opensurvey/wizard/choix_date.php
index ce5f79b1174..817f3d88139 100644
--- a/htdocs/opensurvey/wizard/choix_date.php
+++ b/htdocs/opensurvey/wizard/choix_date.php
@@ -55,7 +55,7 @@ if (GETPOST('confirmation')) {
$tmphorairesi = GETPOST('horaires'.$i, 'array');
- if (!is_array($tmphorairesi) || empty($tmphorairesi[$j])) {
+ if (!is_array($tmphorairesi)) {
$errheure[$i][$j] = true;
$erreur = true;
continue;
@@ -155,7 +155,7 @@ if (GETPOST('confirmation')) {
}
}
- if (isset($errheure)) {
+ if (!empty($errheure)) {
setEventMessages($langs->trans("ErrorBadFormat"), null, 'errors');
}
}