diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php
index cf412223838..c2538421bfe 100644
--- a/htdocs/core/actions_massactions.inc.php
+++ b/htdocs/core/actions_massactions.inc.php
@@ -631,6 +631,8 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
$createbills_onebythird = GETPOST('createbills_onebythird', 'int');
$validate_invoices = GETPOST('validate_invoices', 'int');
+ $errors = array();
+
$TFact = array();
$TFactThird = array();
@@ -645,18 +647,19 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
if ($cmd->fetch($id_order) <= 0) {
continue;
}
+ $cmd->fetch_thirdparty();
$objecttmp = new Facture($db);
if (!empty($createbills_onebythird) && !empty($TFactThird[$cmd->socid])) {
- $objecttmp = $TFactThird[$cmd->socid]; // If option "one bill per third" is set, we use already created order.
+ // If option "one bill per third" is set, and an invoice for this thirdparty was already created, we re-use it.
+ $objecttmp = $TFactThird[$cmd->socid];
} else {
- // Load extrafields of order
- $cmd->fetch_optionals();
-
+ // If we want one invoice per order or if there is no first invoice yet for this thirdparty.
$objecttmp->socid = $cmd->socid;
$objecttmp->type = $objecttmp::TYPE_STANDARD;
- $objecttmp->cond_reglement_id = $cmd->cond_reglement_id;
- $objecttmp->mode_reglement_id = $cmd->mode_reglement_id;
+ $objecttmp->cond_reglement_id = ($cmd->cond_reglement_id || $cmd->thirdparty->cond_reglement_id);
+ $objecttmp->mode_reglement_id = ($cmd->mode_reglement_id || $cmd->thirdparty->mode_reglement_id);
+
$objecttmp->fk_project = $cmd->fk_project;
$objecttmp->multicurrency_code = $cmd->multicurrency_code;
if (empty($createbills_onebythird)) {
@@ -680,23 +683,20 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
$nb_bills_created++;
$lastref = $objecttmp->ref;
$lastid = $objecttmp->id;
+
+ $TFactThird[$cmd->socid] = $objecttmp;
+ } else {
+ $langs->load("errors");
+ $errors[] = $cmd->ref.' : '.$langs->trans($objecttmp->error);
+ $error++;
}
}
if ($objecttmp->id > 0) {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
- $sql .= "fk_source";
- $sql .= ", sourcetype";
- $sql .= ", fk_target";
- $sql .= ", targettype";
- $sql .= ") VALUES (";
- $sql .= $id_order;
- $sql .= ", '".$db->escape($objecttmp->origin)."'";
- $sql .= ", ".$objecttmp->id;
- $sql .= ", '".$db->escape($objecttmp->element)."'";
- $sql .= ")";
+ $res = $objecttmp->add_object_linked($objecttmp->origin, $id_order);
- if (!$db->query($sql)) {
+ if ($res == 0) {
+ $errors[] = $objecttmp->error;
$error++;
}
@@ -845,7 +845,6 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
}
$id = $objecttmp->id; // For builddoc action
- $object = $objecttmp;
// Builddoc
$donotredirect = 1;
@@ -854,7 +853,7 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
// Call action to build doc
$savobject = $object;
- $object = $objecttmp;
+ $object = $objecttmp;
include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
$object = $savobject;
}
@@ -949,6 +948,7 @@ if ($massaction == 'confirm_createbills') { // Create bills from orders.
exit;
} else {
$db->rollback();
+
$action = 'create';
$_GET["origin"] = $_POST["origin"];
$_GET["originid"] = $_POST["originid"];
diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
index 1e28afd41e0..5df73f49f5c 100644
--- a/htdocs/core/class/commonobject.class.php
+++ b/htdocs/core/class/commonobject.class.php
@@ -3577,7 +3577,7 @@ abstract class CommonObject
* @param string $origin Linked element type
* @param int $origin_id Linked element id
* @param User $f_user User that create
- * @param int $notrigger 1=Does not execute triggers, 0= execute triggers
+ * @param int $notrigger 1=Does not execute triggers, 0=execute triggers
* @return int <=0 if KO, >0 if OK
* @see fetchObjectLinked(), updateObjectLinked(), deleteObjectLinked()
*/
@@ -3611,9 +3611,9 @@ abstract class CommonObject
$sql .= ", fk_target";
$sql .= ", targettype";
$sql .= ") VALUES (";
- $sql .= $origin_id;
+ $sql .= ((int) $origin_id);
$sql .= ", '" . $this->db->escape($origin) . "'";
- $sql .= ", " . $this->id;
+ $sql .= ", " . ((int) $this->id);
$sql .= ", '" . $this->db->escape($this->element) . "'";
$sql .= ")";
diff --git a/htdocs/langs/en_US/orders.lang b/htdocs/langs/en_US/orders.lang
index 5dab5b99bf1..9018db40a5b 100644
--- a/htdocs/langs/en_US/orders.lang
+++ b/htdocs/langs/en_US/orders.lang
@@ -151,6 +151,7 @@ PDFEdisonDescription=A simple order model
PDFProformaDescription=A complete Proforma invoice template
CreateInvoiceForThisCustomer=Bill orders
CreateInvoiceForThisSupplier=Bill orders
+CreateInvoiceForThisReceptions=Bill receptions
NoOrdersToInvoice=No orders billable
CloseProcessedOrdersAutomatically=Classify "Processed" all selected orders.
OrderCreation=Order creation
diff --git a/htdocs/reception/list.php b/htdocs/reception/list.php
index dd9f365c39a..e4b519517ea 100644
--- a/htdocs/reception/list.php
+++ b/htdocs/reception/list.php
@@ -171,87 +171,102 @@ if (empty($reshook)) {
$createbills_onebythird = GETPOST('createbills_onebythird', 'int');
$validate_invoices = GETPOST('validate_invoices', 'int');
+ $errors = array();
+
$TFact = array();
$TFactThird = array();
$nb_bills_created = 0;
+ $lastid= 0;
+ $lastref = '';
$db->begin();
- $errors = array();
+
foreach ($receptions as $id_reception) {
$rcp = new Reception($db);
- // On ne facture que les réceptions validées
- if ($rcp->fetch($id_reception) <= 0 || $rcp->statut != 1) {
+ // We only invoice reception that are validated
+ if ($rcp->fetch($id_reception) <= 0 || $rcp->statut != $rcp::STATUS_VALIDATED) {
$errors[] = $langs->trans('StatusOfRefMustBe', $rcp->ref, $langs->transnoentities("StatusSupplierOrderValidatedShort"));
$error++;
continue;
}
- $object = new FactureFournisseur($db);
+ $objecttmp = new FactureFournisseur($db);
if (!empty($createbills_onebythird) && !empty($TFactThird[$rcp->socid])) {
- $object = $TFactThird[$rcp->socid]; // If option "one bill per third" is set, we use already created reception.
- if (empty($object->rowid) && $object->id != null) {
- $object->rowid = $object->id;
- }
- if (!empty($object->rowid)) {
- $object->fetchObjectLinked();
- }
- $rcp->fetchObjectLinked();
+ // If option "one bill per third" is set, and an invoice for this thirdparty was already created, we re-use it.
+ $objecttmp = $TFactThird[$rcp->socid];
- if (count($rcp->linkedObjectsIds['reception']) > 0) {
- foreach ($rcp->linkedObjectsIds['reception'] as $key => $value) {
- if (empty($object->linkedObjectsIds['reception']) || !in_array($value, $object->linkedObjectsIds['reception'])) { //Dont try to link if already linked
- $object->add_object_linked('reception', $value); // add supplier order linked object
+ // Add all links of this new reception to the existing invoice
+ $objecttmp->fetchObjectLinked();
+ $rcp->fetchObjectLinked();
+ if (count($rcp->linkedObjectsIds['order_supplier']) > 0) {
+ foreach ($rcp->linkedObjectsIds['order_supplier'] as $key => $value) {
+ if (empty($objecttmp->linkedObjectsIds['order_supplier']) || !in_array($value, $objecttmp->linkedObjectsIds['order_supplier'])) { //Dont try to link if already linked
+ $objecttmp->add_object_linked('order_supplier', $value); // add supplier order linked object
}
}
}
} else {
- $object->socid = $rcp->socid;
- $object->type = FactureFournisseur::TYPE_STANDARD;
- $object->cond_reglement_id = $rcp->thirdparty->cond_reglement_supplier_id;
- $object->mode_reglement_id = $rcp->thirdparty->mode_reglement_supplier_id;
- $object->fk_account = !empty($rcp->thirdparty->fk_account) ? $rcp->thirdparty->fk_account : 0;
- $object->remise_percent = !empty($rcp->thirdparty->remise_percent) ? $rcp->thirdparty->remise_percent : 0;
- $object->remise_absolue = !empty($rcp->thirdparty->remise_absolue) ? $rcp->thirdparty->remise_absolue : 0;
+ // If we want one invoice per reception or if there is no first invoice yet for this thirdparty.
+ $objecttmp->socid = $rcp->socid;
+ $objecttmp->type = $objecttmp::TYPE_STANDARD;
+ $objecttmp->cond_reglement_id = $rcp->cond_reglement_id || $rcp->thirdparty->cond_reglement_supplier_id;
+ $objecttmp->mode_reglement_id = $rcp->mode_reglement_id || $rcp->thirdparty->mode_reglement_supplier_id;
- $object->fk_project = $rcp->fk_project;
- $object->ref_supplier = $rcp->ref_supplier;
+ $objecttmp->fk_account = !empty($rcp->thirdparty->fk_account) ? $rcp->thirdparty->fk_account : 0;
+ $objecttmp->remise_percent = !empty($rcp->thirdparty->remise_percent) ? $rcp->thirdparty->remise_percent : 0;
+ $objecttmp->remise_absolue = !empty($rcp->thirdparty->remise_absolue) ? $rcp->thirdparty->remise_absolue : 0;
- $datefacture = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear'));
- if (empty($datefacture)) {
- $datefacture = dol_mktime(date("h"), date("M"), 0, date("m"), date("d"), date("Y"));
+ $objecttmp->fk_project = $rcp->fk_project;
+ //$objecttmp->multicurrency_code = $rcp->multicurrency_code;
+ if (empty($createbills_onebythird)) {
+ $objecttmp->ref_supplier = $rcp->ref;
+ } else {
+ // Set a unique value for the invoice for the n reception
+ $objecttmp->ref_supplier = $langs->trans("Reception").' '.dol_print_date(dol_now(), 'dayhourlog').'-'.$rcp->socid;
}
- $object->date = $datefacture;
- $object->origin = 'reception';
- $object->origin_id = $id_reception;
+ $datefacture = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
+ if (empty($datefacture)) {
+ $datefacture = dol_now();
+ }
+ $objecttmp->date = $datefacture;
+ $objecttmp->origin = 'reception';
+ $objecttmp->origin_id = $id_reception;
+
+ $objecttmp->array_options = $rcp->array_options; // Copy extrafields
+
+ // Set $objecttmp->linked_objects with all links order_supplier existing on reception, so same links will be added to the generated supplier invoice
$rcp->fetchObjectLinked();
- if (count($rcp->linkedObjectsIds['reception']) > 0) {
- foreach ($rcp->linkedObjectsIds['reception'] as $key => $value) {
- $object->linked_objects['reception'] = $value;
+ if (count($rcp->linkedObjectsIds['order_supplier']) > 0) {
+ foreach ($rcp->linkedObjectsIds['order_supplier'] as $key => $value) {
+ $objecttmp->linked_objects['order_supplier'] = $value;
}
}
- $res = $object->create($user);
- //var_dump($object->error);exit;
+ $res = $objecttmp->create($user); // This should create the supplier invoice + links into $objecttmp->linked_objects + add a link to ->origin_id
+
+ //var_dump($objecttmp->error);exit;
if ($res > 0) {
$nb_bills_created++;
- $object->id = $res;
+ $lastref = $objecttmp->ref;
+ $lastid = $objecttmp->id;
+
+ $TFactThird[$rcp->socid] = $objecttmp;
} else {
- $errors[] = $rcp->ref.' : '.$langs->trans($object->error);
+ $langs->load("errors");
+ $errors[] = $rcp->ref.' : '.$langs->trans($objecttmp->error);
$error++;
}
}
- if ($object->id > 0) {
- if (!empty($createbills_onebythird) && !empty($TFactThird[$rcp->socid])) { //cause function create already add object linked for facturefournisseur
- $res = $object->add_object_linked($object->origin, $id_reception);
+ if ($objecttmp->id > 0) {
+ $res = $objecttmp->add_object_linked($objecttmp->origin, $id_reception);
- if ($res == 0) {
- $errors[] = $object->error;
- $error++;
- }
+ if ($res == 0) {
+ $errors[] = $objecttmp->error;
+ $error++;
}
if (!$error) {
@@ -266,10 +281,15 @@ if (empty($reshook)) {
for ($i = 0; $i < $num; $i++) {
$desc = ($lines[$i]->desc ? $lines[$i]->desc : $lines[$i]->libelle);
+ // If we build one invoice for several reception, we must put the ref of reception on the invoice line
+ if (!empty($createbills_onebythird)) {
+ $desc = dol_concatdesc($desc, $langs->trans("Reception").' '.$rcp->ref.' - '.dol_print_date($rcp->date, 'day'));
+ }
+
if ($lines[$i]->subprice < 0) {
// Negative line, we create a discount line
$discount = new DiscountAbsolute($db);
- $discount->fk_soc = $object->socid;
+ $discount->fk_soc = $objecttmp->socid;
$discount->amount_ht = abs($lines[$i]->total_ht);
$discount->amount_tva = abs($lines[$i]->total_tva);
$discount->amount_ttc = abs($lines[$i]->total_ttc);
@@ -278,7 +298,7 @@ if (empty($reshook)) {
$discount->description = $desc;
$discountid = $discount->create($user);
if ($discountid > 0) {
- $result = $object->insert_discount($discountid);
+ $result = $objecttmp->insert_discount($discountid);
//$result=$discount->link_to_invoice($lineid,$id);
} else {
setEventMessages($discount->error, $discount->errors, 'errors');
@@ -314,7 +334,16 @@ if (empty($reshook)) {
if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
$fk_parent_line = 0;
}
- $result = $object->addline(
+
+ // Extrafields
+ if (method_exists($lines[$i], 'fetch_optionals')) {
+ $lines[$i]->fetch_optionals();
+ $array_options = $lines[$i]->array_options;
+ }
+
+ $objecttmp->context['createfromclone'];
+
+ $result = $objecttmp->addline(
$desc,
$lines[$i]->subprice,
$lines[$i]->tva_tx,
@@ -359,9 +388,9 @@ if (empty($reshook)) {
//$rcp->classifyBilled($user); // Disabled. This behavior must be set or not using the workflow module.
if (!empty($createbills_onebythird) && empty($TFactThird[$rcp->socid])) {
- $TFactThird[$rcp->socid] = $object;
+ $TFactThird[$rcp->socid] = $objecttmp;
} else {
- $TFact[$object->id] = $object;
+ $TFact[$objecttmp->id] = $objecttmp;
}
}
@@ -371,21 +400,27 @@ if (empty($reshook)) {
if (!$error && $validate_invoices) {
$massaction = $action = 'builddoc';
- foreach ($TAllFact as &$object) {
- $result = $object->validate($user);
+ foreach ($TAllFact as &$objecttmp) {
+ $result = $objecttmp->validate($user);
if ($result <= 0) {
$error++;
- setEventMessages($object->error, $object->errors, 'errors');
+ setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
break;
}
- $id = $object->id; // For builddoc action
+ $id = $objecttmp->id; // For builddoc action
+ $object =$objecttmp;
// Fac builddoc
$donotredirect = 1;
$upload_dir = $conf->fournisseur->facture->dir_output;
$permissiontoadd = ($user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer);
+
+ // Call action to build doc
+ $savobject = $object;
+ $object = $objecttmp;
include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
+ $object = $savobject;
}
$massaction = $action = 'confirm_createbills';
@@ -393,9 +428,17 @@ if (empty($reshook)) {
if (!$error) {
$db->commit();
- setEventMessage($langs->trans('BillCreated', $nb_bills_created));
+
+ if ($nb_bills_created == 1) {
+ $texttoshow = $langs->trans('BillXCreated', '{s1}');
+ $texttoshow = str_replace('{s1}', ''.$lastref.'', $texttoshow);
+ setEventMessages($texttoshow, null, 'mesgs');
+ } else {
+ setEventMessages($langs->trans('BillCreated', $nb_bills_created), null, 'mesgs');
+ }
} else {
$db->rollback();
+
$action = 'create';
$_GET["origin"] = $_POST["origin"];
$_GET["originid"] = $_POST["originid"];
@@ -597,7 +640,7 @@ $arrayofmassactions = array(
);
if ($user->rights->fournisseur->facture->creer || $user->rights->supplier_invoice->creer) {
- $arrayofmassactions['createbills'] = $langs->trans("CreateInvoiceForThisSupplier");
+ $arrayofmassactions['createbills'] = $langs->trans("CreateInvoiceForThisReceptions");
}
if ($massaction == 'createbills') {
$arrayofmassactions = array();
@@ -656,7 +699,7 @@ if ($massaction == 'createbills') {
print '
';
print '