From baed678b6e22da0da76c919269b430f7d4086c6d Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Tue, 2 Oct 2018 15:49:31 +0200 Subject: [PATCH 01/50] NEW shipping set draft and update line --- htdocs/expedition/card.php | 758 +++++++++++++++---- htdocs/expedition/class/expedition.class.php | 545 ++++++++++++- htdocs/langs/en_US/agenda.lang | 1 + htdocs/langs/fr_FR/agenda.lang | 1 + 4 files changed, 1153 insertions(+), 152 deletions(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index 81b6ed455a7..fbe7d81622c 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -7,7 +7,7 @@ * Copyright (C) 2013 Florian Henry * Copyright (C) 2013 Marcos García * Copyright (C) 2014 Cedric GROSS - * Copyright (C) 2014-2015 Francis Appels + * Copyright (C) 2014-2017 Francis Appels * Copyright (C) 2015 Claudio Aschieri * Copyright (C) 2016 Ferran Marcet * Copyright (C) 2016 Yasser Carreón @@ -29,7 +29,7 @@ /** * \file htdocs/expedition/card.php * \ingroup expedition - * \brief Fiche descriptive d'une expedition + * \brief Card of a shipment */ require '../main.inc.php'; @@ -52,14 +52,8 @@ if (! empty($conf->projet->enabled)) { require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; } -$langs->load("sendings"); -$langs->load("companies"); -$langs->load("bills"); -$langs->load('deliveries'); -$langs->load('orders'); -$langs->load('stocks'); -$langs->load('other'); -$langs->load('propal'); +$langs->loadLangs(array("sendings","companies","bills",'deliveries','orders','stocks','other','propal')); + if (!empty($conf->incoterm->enabled)) $langs->load('incoterm'); if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); @@ -69,6 +63,7 @@ $id = $origin_id; if (empty($origin_id)) $origin_id = GETPOST('origin_id','int'); // Id of order or propal if (empty($origin_id)) $origin_id = GETPOST('object_id','int'); // Id of order or propal $ref=GETPOST('ref','alpha'); +$line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; // Security check $socid=''; @@ -107,6 +102,7 @@ include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be inclu $hookmanager->initHooks(array('expeditioncard','globalcard')); $permissiondellink=$user->rights->expedition->livraison->creer; // Used by the include of actions_dellink.inc.php +//var_dump($object->lines[0]->detail_batch); /* @@ -127,12 +123,36 @@ if (empty($reshook)) include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once - // Set incoterm + // Reopen if ($action == 'reopen' && $user->rights->expedition->creer) { $object->fetch($id); $result = $object->reOpen(); } + + // Confirm back to draft status + if ($action == 'modif' && $user->rights->expedition->creer) + { + $result = $object->set_draft($user); + if ($result >= 0) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + } // Set incoterm if ($action == 'set_incoterms' && !empty($conf->incoterm->enabled)) @@ -173,9 +193,11 @@ if (empty($reshook)) $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { $result = $object->insertExtraFields(); - if ($result < 0) { - $error++; - } + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } } else if ($reshook < 0) $error++; } @@ -503,8 +525,8 @@ if (empty($reshook)) } } - // Action update description of emailing - else if ($action == 'settrackingnumber' || $action == 'settrackingurl' + // Action update + else if ($action == 'settracking_number' || $action == 'settracking_url' || $action == 'settrueWeight' || $action == 'settrueWidth' || $action == 'settrueHeight' @@ -513,8 +535,8 @@ if (empty($reshook)) { $error=0; - if ($action == 'settrackingnumber') $object->tracking_number = trim(GETPOST('trackingnumber','alpha')); - if ($action == 'settrackingurl') $object->tracking_url = trim(GETPOST('trackingurl','int')); + if ($action == 'settracking_number') $object->tracking_number = trim(GETPOST('tracking_number','alpha')); + if ($action == 'settracking_url') $object->tracking_url = trim(GETPOST('tracking_url','int')); if ($action == 'settrueWeight') { $object->trueWeight = trim(GETPOST('trueWeight','int')); $object->weight_units = GETPOST('weight_units','int'); @@ -596,6 +618,292 @@ if (empty($reshook)) } } + /* + * delete a line + */ + elseif ($action == 'deleteline' && ! empty($line_id)) + { + $object->fetch($id); + $lines = $object->lines; + $line = new ExpeditionLigne($db); + + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) + { + if (count($lines[$i]->details_entrepot) > 1) + { + // delete multi warehouse lines + foreach ($lines[$i]->details_entrepot as $details_entrepot) { + $line->id = $details_entrepot->line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + else + { + // delete single warehouse line + $line->id = $line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + unset($_POST["lineid"]); + } + + if(! $error) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + } + } + + /* + * Update a line + */ + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('save')) + { + // Clean parameters + $qty=0; + $entrepot_id = 0; + $batch_id = 0; + + $lines = $object->lines; + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) // we have found line to update + { + $line = new ExpeditionLigne($db); + // Extrafields Lines + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $line->array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline); + // Unset extrafield POST Data + if (is_array($extralabelsline)) { + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + $line->fk_product = $lines[$i]->fk_product; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + // line with lot + foreach ($lines[$i]->detail_batch as $detail_batch) + { + $lotStock = new Productbatch($db); + $batch="batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock; + $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id; + $batch_id = GETPOST($batch,'int'); + $batch_qty = GETPOST($qty, 'int'); + if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->dluo_qty)) + { + if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) // $line is ExpeditionLine + { + if ($lines[$i]->entrepot_id != 0) + { + // allow update line entrepot_id if not multi warehouse shipping + $line->entrepot_id = $lotStock->warehouseid; + } + + // detail_batch can be an object with keys, or an array of ExpeditionLineBatch + if (empty($line->detail_batch)) $line->detail_batch=new stdClass(); + + $line->detail_batch->fk_origin_stock = $batch_id; + $line->detail_batch->batch = $lotStock->batch; + $line->detail_batch->id = $detail_batch->id; + $line->detail_batch->entrepot_id = $lotStock->warehouseid; + $line->detail_batch->dluo_qty = $batch_qty; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + setEventMessages($lotStock->error, $lotStock->errors, 'errors'); + $error++; + } + } + unset($_POST[$batch]); + unset($_POST[$qty]); + } + // add new batch + $lotStock = new Productbatch($db); + $batch="batchl".$line_id."_0"; + $qty = "qtyl".$line_id."_0"; + $batch_id = GETPOST($batch,'int'); + $batch_qty = GETPOST($qty, 'int'); + $lineIdToAddLot = 0; + if ($batch_qty > 0 && ! empty($batch_id)) + { + if ($lotStock->fetch($batch_id) > 0) + { + // check if lotStock warehouse id is same as line warehouse id + if ($lines[$i]->entrepot_id > 0) + { + // single warehouse shipment line + if ($lines[i]->entrepot_id == $lotStock->warehouseid) + { + $lineIdToAddLot = $line_id; + } + } + else if (count($lines[$i]->details_entrepot) > 1) + { + // multi warehouse shipment lines + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) + { + $lineIdToAddLot = $detail_entrepot->line_id; + } + } + } + if ($lineIdToAddLot) + { + // add lot to existing line + if ($line->fetch($lineIdToAddLot) > 0) + { + $line->detail_batch->fk_origin_stock = $batch_id; + $line->detail_batch->batch = $lotStock->batch; + $line->detail_batch->entrepot_id = $lotStock->warehouseid; + $line->detail_batch->dluo_qty = $batch_qty; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + // create new line with new lot + $line->origin_line_id = $lines[$i]->origin_line_id; + $line->entrepot_id = $lotStock->warehouseid; + $line->detail_batch[0] = new ExpeditionLineBatch($db); + $line->detail_batch[0]->fk_origin_stock = $batch_id; + $line->detail_batch[0]->batch = $lotStock->batch; + $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid; + $line->detail_batch[0]->dluo_qty = $batch_qty; + if ($object->create_line_batch($line, $line->array_options) < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + else + { + setEventMessages($lotStock->error, $lotStock->errors, 'errors'); + $error++; + } + } + } + else + { + if ($lines[$i]->fk_product > 0) + { + // line without lot + if ($lines[$i]->entrepot_id > 0) + { + // single warehouse shipment line + $stockLocation="entl".$line_id; + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->entrepot_id = GETPOST($stockLocation,'int'); + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + // multi warehouse shipment lines + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if (! $error) { + $stockLocation="entl".$detail_entrepot->line_id; + $qty = "qtyl".$detail_entrepot->line_id; + $warehouse = GETPOST($stockLocation,'int'); + if (!empty ($warehouse)) + { + $line->id = $detail_entrepot->line_id; + $line->entrepot_id = $warehouse; + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + } + } + } + else // Product no predefined + { + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->qty = GETPOST($qty, 'int'); + $line->entrepot_id = 0; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$qty]); + } + } + } + } + + unset($_POST["lineid"]); + + if (! $error) { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) + $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + $ret = $object->fetch($object->id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + } + + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; // Actions to send emails @@ -704,6 +1012,7 @@ if ($action == 'create') if (! empty($conf->projet->enabled)) { $projectid = GETPOST('projectid','int')?GETPOST('projectid','int'):0; + if(empty($projectid) && ! empty($object->fk_project)) $projectid = $object->fk_project; if ($origin == 'project') $projectid = ($originid ? $originid : 0); $langs->load("projects"); @@ -902,7 +1211,8 @@ if ($action == 'create') if ($line->fk_product > 0) // If predefined product { $product->fetch($line->fk_product); - $product->load_stock('warehouseopen'); + $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch + //var_dump($product->stock_warehouse[1]); print ''; print ''; // ancre pour retourner sur la ligne @@ -983,7 +1293,7 @@ if ($action == 'create') { // Quantity to send print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { if (GETPOST('qtyl'.$indiceAsked, 'int')) $defaultqty=GETPOST('qtyl'.$indiceAsked, 'int'); print ''; @@ -996,7 +1306,7 @@ if ($action == 'create') if (! empty($conf->stock->enabled)) { print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) // Type of product need stock change ? + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) // Type of product need stock change ? { // Show warehouse combo list $ent = "entl".$indiceAsked; @@ -1079,13 +1389,21 @@ if ($action == 'create') print ''; print ''; + print ''; print ''; print $staticwarehouse->getNomUrl(0).' / '; - print ''; print ''; - print $langs->trans("DetailBatchFormat", $dbatch->batch, dol_print_date($dbatch->eatby,"day"), dol_print_date($dbatch->sellby,"day"), $dbatch->qty); + + $detail=''; + $detail.= $langs->trans("Batch").': '.$dbatch->batch; + $detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day"); + $detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day"); + $detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty; + $detail.= '
'; + print $detail; + $quantityToBeDelivered -= $deliverableQty; if ($quantityToBeDelivered < 0) { @@ -1139,7 +1457,7 @@ if ($action == 'create') // Quantity to send print ''; print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { print ''; print ''; @@ -1151,7 +1469,7 @@ if ($action == 'create') if (! empty($conf->stock->enabled)) { print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { print $tmpwarehouseObject->getNomUrl(0).' '; @@ -1241,14 +1559,12 @@ if ($action == 'create') print ''; print ''; - //print $langs->trans("DetailBatchFormat", $dbatch->batch, dol_print_date($dbatch->eatby,"day"), dol_print_date($dbatch->sellby,"day"), $dbatch->qty); //print $line->fk_product.' - '.$dbatch->batch; print $langs->trans("Batch").': '; $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch); if ($result > 0) print $productlotObject->getNomUrl(1); else print 'TableLotIncompleteRunRepair'; print ' ('.$dbatch->qty.')'; - //print $langs->trans("DetailBatchFormat", 'ee'.$dbatch->batch, dol_print_date($dbatch->eatby,"day"), dol_print_date($dbatch->sellby,"day"), $dbatch->qty); $quantityToBeDelivered -= $deliverableQty; if ($quantityToBeDelivered < 0) { @@ -1266,7 +1582,7 @@ if ($action == 'create') { print ''; print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { $disabled=''; if (! empty($conf->productbatch->enabled) && $product->hasbatch()) @@ -1282,7 +1598,7 @@ if ($action == 'create') print ''; print ''; - if ($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) { $warehouse_selected_id = GETPOST('entrepot_id','int'); if ($warehouse_selected_id > 0) @@ -1328,7 +1644,13 @@ if ($action == 'create') print ""; - print '
'; + print '
'; + + print '
'; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
'; print ''; @@ -1440,7 +1762,7 @@ else if ($id || $ref) } // Shipment card - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref='
'; // Ref customer shipment $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1); @@ -1692,8 +2014,8 @@ else if ($id || $ref) print ''; // Tracking Number - print ''.$form->editfieldkey("TrackingNumber",'trackingnumber',$object->tracking_number,$object,$user->rights->expedition->creer).''; - print $form->editfieldval("TrackingNumber",'trackingnumber',$object->tracking_url,$object,$user->rights->expedition->creer,'string',$object->tracking_number); + print ''.$form->editfieldkey("TrackingNumber",'tracking_number',$object->tracking_number,$object,$user->rights->expedition->creer).''; + print $form->editfieldval("TrackingNumber",'tracking_number',$object->tracking_url,$object,$user->rights->expedition->creer,'string',$object->tracking_number); print ''; // Incoterms @@ -1728,48 +2050,87 @@ else if ($id || $ref) print '
'; - /* - * Lines of products - */ + // Lines of products + + if ($action == 'editline') + { + print '
+ + + + + '; + } print '
'; print '
'; print ''; print ''; + // # if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { print ''; } + // Product/Service print ''; + // Qty print ''; - if ($object->statut <= 1) + if ($origin && $origin_id > 0) { - print ''; + print ''; + } + if ($action == 'editline') + { + $editColspan = 3; + if (empty($conf->stock->enabled)) $editColspan--; + if (empty($conf->productbatch->enabled)) $editColspan--; + print ''; } else { - print ''; - } + if ($object->statut <= 1) + { + print ''; + } + else + { + print ''; + } + if (! empty($conf->stock->enabled)) + { + print ''; + } - if ($origin && $origin_id > 0) - { - print ''; + if (! empty($conf->productbatch->enabled)) + { + print ''; + } } - print ''; print ''; //print ''; - - if (! empty($conf->stock->enabled)) + if ($object->statut == 0) { - print ''; + print ''; + print ''; } - - if (! empty($conf->productbatch->enabled)) - { - print ''; - } - print "\n"; $var=false; @@ -1788,7 +2149,7 @@ else if ($id || $ref) } } - // Get list of products already sent for same source object + // Get list of products already sent for same source object into $alreadysent $alreadysent = array(); if ($origin && $origin_id > 0) { @@ -1837,6 +2198,7 @@ else if ($id || $ref) print ''; // id of order line print ''; + // # if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { print ''; @@ -1876,7 +2238,7 @@ else if ($id || $ref) else { print "'; - // Qty to ship or shipped - print ''; - // Qty in other shipments (with shipment and warehouse used) if ($origin && $origin_id > 0) { @@ -1927,70 +2286,188 @@ else if ($id || $ref) } print ''; + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + // edit mode + print ''; + } + else + { + // Qty to ship or shipped + print ''; + + // Warehouse source + if (! empty($conf->stock->enabled)) + { + print ''; + } + + // Batch number managment + if (! empty($conf->productbatch->enabled)) + { + if (isset($lines[$i]->detail_batch)) + { + print ''; + print ''; + } else { + print ''; + } + } + } + // Weight print ''; // Volume print ''; // Size //print ''; - // Warehouse source - if (! empty($conf->stock->enabled)) + if ($action == 'editline' && $lines[$i]->id == $line_id) { - print ''; + print ''; + print ''; + + // Display lines extrafields + if (! empty($rowExtrafieldsStart)) { - print ''; - } else { - print ''; + print $rowExtrafieldsStart; + print $rowExtrafieldsView; + print $rowEnd; } } print ""; @@ -2001,11 +2478,16 @@ else if ($id || $ref) $line = new ExpeditionLigne($db); $line->fetch_optionals($lines[$i]->id,$extralabelslines); print ''; - print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + else + { + print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } print ''; } - - } // TODO Show also lines ordered but not delivered @@ -2035,7 +2517,7 @@ else if ($id || $ref) if (empty($reshook)) { - if ($object->statut == 0 && $num_prod > 0) + if ($object->statut == Expedition::STATUS_DRAFT && $num_prod > 0) { if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer)) || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate))) @@ -2047,12 +2529,23 @@ else if ($id || $ref) print ''.$langs->trans("Validate").''; } } + // Edit + if ($object->statut == Expedition::STATUS_VALIDATED && $user->rights->expedition->creer) { + print ''; + } // TODO add alternative status // 0=draft, 1=validated, 2=billed, we miss a status "delivered" (only available on order) - if ($object->statut == 2 && $object->billed && $user->rights->expedition->creer) + if ($object->statut == Expedition::STATUS_CLOSED && $user->rights->expedition->creer) { - print ''.$langs->trans("ReOpen").''; + if (! empty($conf->facture->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + { + print ''.$langs->trans("ClassifyUnbilled").''; + } + else + { + print ''.$langs->trans("ReOpen").''; + } } // Send @@ -2066,7 +2559,7 @@ else if ($id || $ref) } // Create bill - if (! empty($conf->facture->enabled) && $object->statut > 0) + if (! empty($conf->facture->enabled) && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED)) { if ($user->rights->facture->creer) { @@ -2078,18 +2571,18 @@ else if ($id || $ref) // This is just to generate a delivery receipt //var_dump($object->linkedObjectsIds['delivery']); - if ($conf->livraison_bon->enabled && ($object->statut == 1 || $object->statut == 2) && $user->rights->expedition->livraison->creer && count($object->linkedObjectsIds['delivery']) == 0) + if ($conf->livraison_bon->enabled && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED) && $user->rights->expedition->livraison->creer && count($object->linkedObjectsIds['delivery']) == 0) { print ''.$langs->trans("CreateDeliveryOrder").''; } // Close - if (! empty($conf->facture->enabled) && $object->statut > 0) + if ($object->statut == Expedition::STATUS_VALIDATED) { if ($user->rights->expedition->creer && $object->statut > 0 && ! $object->billed) { $label="Close"; $paramaction='classifyclosed'; // = Transferred/Received // Label here should be "Close" or "ClassifyBilled" if we decided to make bill on shipments instead of orders - if (! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) // TODO Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close. + if (! empty($conf->facture->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? { $label="ClassifyBilled"; $paramaction='classifybilled'; @@ -2113,7 +2606,7 @@ else if ($id || $ref) * Documents generated */ - if ($action != 'presend') + if ($action != 'presend' && $action != 'editline') { print '
'; @@ -2135,19 +2628,7 @@ else if ($id || $ref) print '
'; - // List of actions on element - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; - $formactions=new FormActions($db); - $somethingshown=$formactions->showactions($object,'shipping',$socid); - - print '
'; } - - - /* - * Action presend - */ - //Select mail models is same action as presend if (GETPOST('modelselected')) { $action = 'presend'; @@ -2158,7 +2639,6 @@ else if ($id || $ref) include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $fileparams = dol_most_recent_file($conf->expedition->dir_output . '/sending/' . $ref, preg_quote($ref, '/').'[^\-]+'); $file=$fileparams['fullname']; - // Define output language $outputlangs = $langs; $newlang = ''; @@ -2166,14 +2646,12 @@ else if ($id || $ref) $newlang = $_REQUEST['lang_id']; if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; - if (!empty($newlang)) { $outputlangs = new Translate('', $conf); $outputlangs->setDefaultLang($newlang); $outputlangs->load('sendings'); } - // Build document if it not exists if (! $file || ! is_readable($file)) { @@ -2186,23 +2664,18 @@ else if ($id || $ref) $fileparams = dol_most_recent_file($conf->expedition->dir_output . '/sending/' . $ref, preg_quote($ref, '/').'[^\-]+'); $file=$fileparams['fullname']; } - print '
'; print '
'; print '
'; print load_fiche_titre($langs->trans('SendShippingByEMail')); - dol_fiche_head(''); - // Cree l'objet formulaire mail include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; $formmail = new FormMail($db); $formmail->param['langsmodels']=(empty($newlang)?$langs->defaultlang:$newlang); $formmail->fromtype = (GETPOST('fromtype')?GETPOST('fromtype'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user')); - if($formmail->fromtype === 'user'){ $formmail->fromid = $user->id; - } $formmail->trackid='shi'.$object->id; if (! empty($conf->global->MAIN_EMAIL_ADD_TRACK_ID) && ($conf->global->MAIN_EMAIL_ADD_TRACK_ID & 2)) // If bit 2 is set @@ -2226,7 +2699,6 @@ else if ($id || $ref) $formmail->substit['__SHIPPINGREF__']=$object->ref; $formmail->substit['__SHIPPINGTRACKNUM__']=$object->tracking_number; $formmail->substit['__SHIPPINGTRACKNUMURL__']=$object->tracking_url; - //Find the good contact adress if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) { $objectsrc=new Commande($db); @@ -2242,44 +2714,38 @@ else if ($id || $ref) { $contactarr=$objectsrc->liste_contact(-1,'external'); } - if (is_array($contactarr) && count($contactarr)>0) { foreach($contactarr as $contact) { - if ($contact['libelle']==$langs->trans('TypeContact_commande_external_CUSTOMER')) { - require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; - $contactstatic=new Contact($db); $contactstatic->fetch($contact['id']); $custcontact=$contactstatic->getFullName($langs,1); } } - if (!empty($custcontact)) { $formmail->substit['__CONTACTCIVNAME__']=$custcontact; } } - // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='shipping_send'; $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['shippingid']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; - // Init list of files if (GETPOST("mode")=='init') { $formmail->clear_attached_files(); $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); } - // Show form print $formmail->get_form(); - dol_fiche_end(); } + + + } diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 879b5745db4..f5eb969149a 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -642,9 +642,8 @@ class Expedition extends CommonObject { $numref = $this->getNextNumRef($soc); } - else - { - $numref = "EXP".$this->id; + else { + $numref = $this->ref; } $this->newref = $numref; @@ -2170,6 +2169,138 @@ class Expedition extends CommonObject return -1; } } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @return int <0 if KO, >0 if OK + */ + function set_draft($user) + { + global $conf,$langs; + + $error=0; + + // Protection + if ($this->statut <= self::STATUS_DRAFT) + { + return 0; + } + + if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + } + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."expedition"; + $sql.= " SET fk_statut = ".self::STATUS_DRAFT; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_draft", LOG_DEBUG); + if ($this->db->query($sql)) + { + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite d'expedier a partir d'une propale ou autre origine + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."expeditiondet as ed"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expeditiondet_batch as edb on edb.fk_expeditiondet = ed.rowid"; + $sql.= " WHERE ed.fk_expedition = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) + { + $qty = $obj->qty; + } + else + { + $qty = $obj->edbqty; + } + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::reopen expedition movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->edbrowid)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentBackToDraftInDolibarr",$this->ref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ShipmentBackToDraftInDolibarr",$this->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + if (!$error) { + // Call trigger + $result=$this->call_trigger('SHIPPING_UNVALIDATE',$user); + if ($result < 0) $error++; + } + + if (!$error) { + $this->statut=self::STATUS_DRAFT; + $this->db->commit(); + return 1; + }else { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } /** * Create a document onto disk according to template module. @@ -2229,6 +2360,17 @@ class Expedition extends CommonObject */ class ExpeditionLigne extends CommonObjectLine { + public $element='expeditiondet'; + public $table_element='expeditiondet'; + + public $fk_origin_line; + + /** + * Id of shipment + * @var int + */ + public $fk_expedition; + var $db; // From llx_expeditiondet @@ -2236,6 +2378,12 @@ class ExpeditionLigne extends CommonObjectLine var $qty_shipped; var $fk_product; var $detail_batch; + /** + * Id of warehouse + * @var int + */ + public $entrepot_id; + // From llx_commandedet or llx_propaldet var $qty_asked; @@ -2252,10 +2400,7 @@ class ExpeditionLigne extends CommonObjectLine var $total_localtax1; // Total Local tax 1 var $total_localtax2; // Total Local tax 2 - public $element='expeditiondet'; - public $table_element='expeditiondet'; - public $fk_origin_line; // Deprecated /** @@ -2284,5 +2429,393 @@ class ExpeditionLigne extends CommonObjectLine $this->db=$db; } + /** + * Load line expedition + * + * @param int $rowid Id line order + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT ed.rowid, ed.fk_expedition, ed.fk_entrepot, ed.fk_origin_line, ed.qty, ed.rang'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as ed'; + $sql.= ' WHERE ed.rowid = '.$rowid; + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); + $this->id = $objp->rowid; + $this->fk_expedition = $objp->fk_expedition; + $this->entrepot_id = $objp->fk_entrepot; + $this->fk_origin_line = $objp->fk_origin_line; + $this->qty = $objp->qty; + $this->rang = $objp->rang; + + $this->db->free($result); + + return 1; + } + else + { + $this->errors[] = $this->db->lasterror(); + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Insert line into database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int <0 if KO, line id >0 if OK + */ + function insert($user=null, $notrigger=0) + { + global $langs, $conf; + + $error=0; + + // Check parameters + if (empty($this->fk_expedition) || empty($this->fk_origin_line) || ! is_numeric($this->qty)) + { + $this->error = 'ErrorMandatoryParametersNotProvided'; + return -1; + } + // Clean parameters + if (empty($this->entrepot_id)) $this->entrepot_id='null'; + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."expeditiondet ("; + $sql.= "fk_expedition"; + $sql.= ", fk_entrepot"; + $sql.= ", fk_origin_line"; + $sql.= ", qty"; + $sql.= ") VALUES ("; + $sql.= $this->fk_expedition; + $sql.= ", ".$this->entrepot_id; + $sql.= ", ".$this->fk_origin_line; + $sql.= ", ".$this->qty; + $sql.= ")"; + + dol_syslog(get_class($this)."::insert", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."expeditiondet"); + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_INSERT',$user); + if ($result < 0) + { + $error++; + } + // End call triggers + } + + if (! $error) { + $this->db->commit(); + return $this->id; + } + + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + + $this->db->rollback(); + return -1*$error; + } + else + { + $error++; + } + } + + /** + * Delete shipment line. + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int >0 if OK, <0 if KO + */ + function delete($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + $this->db->begin(); + + // delete batch expedition line + if ($conf->productbatch->enabled) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch"; + $sql.= " WHERE fk_expeditiondet = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + } + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet"; + $sql.= " WHERE rowid = ".$this->id; + + if (! $error && $this->db->query($sql)) + { + // Remove extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_DELETE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + } + else + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + + if (! $error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + /** + * Update a line in database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int < 0 if KO, > 0 if OK + */ + function update($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + dol_syslog(get_class($this)."::update id=$this->id, entrepot_id=$this->entrepot_id, product_id=$this->fk_product, qty=$this->qty"); + + $this->db->begin(); + + // Clean parameters + if (empty($this->qty)) $this->qty=0; + $qty=price2num($this->qty); + $remainingQty = 0; + $batch = null; + $batch_id = null; + $expedition_batch_id = null; + if (is_array($this->detail_batch)) // array of ExpeditionLineBatch + { + if (count($this->detail_batch) > 1) + { + dol_syslog(get_class($this).'::update only possible for one batch', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + else + { + $batch = $this->detail_batch[0]->batch; + $batch_id = $this->detail_batch[0]->fk_origin_stock; + $expedition_batch_id = $this->detail_batch[0]->id; + if ($this->entrepot_id != $this->detail_batch[0]->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch[0]->dluo_qty); + } + } + else if (! empty($this->detail_batch)) + { + $batch = $this->detail_batch->batch; + $batch_id = $this->detail_batch->fk_origin_stock; + $expedition_batch_id = $this->detail_batch->id; + if ($this->entrepot_id != $this->detail_batch->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch->dluo_qty); + } + + // check parameters + if (! isset($this->id) || ! isset($this->entrepot_id)) + { + dol_syslog(get_class($this).'::update missing line id and/or warehouse id', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + return -1; + } + + // update lot + + if (! empty($batch) && $conf->productbatch->enabled) + { + dol_syslog(get_class($this)."::update expedition batch id=$expedition_batch_id, batch_id=$batch_id, batch=$batch"); + + if (empty($batch_id) || empty($this->fk_product)) { + dol_syslog(get_class($this).'::update missing fk_origin_stock (batch_id) and/or fk_product', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + } + + // fetch remaining lot qty + require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionbatch.class.php'; + if (! $error && ($lotArray = ExpeditionLineBatch::fetchAll($this->db, $this->id)) < 0) + { + $this->errors[]=$this->db->lasterror()." - ExpeditionLineBatch::fetchAll"; + $error++; + } + else + { + // caculate new total line qty + foreach ($lotArray as $lot) + { + if ($expedition_batch_id != $lot->id) + { + $remainingQty += $lot->dluo_qty; + } + } + $qty += $remainingQty; + + //fetch lot details + + // fetch from product_lot + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; + $lot = new Productlot($this->db); + if ($lot->fetch(0,$this->fk_product,$batch) < 0) + { + $this->errors[] = $lot->errors; + $error++; + } + if (! $error && ! empty($expedition_batch_id)) + { + // delete lot expedition line + $sql = "DELETE FROM ".MAIN_DB_PREFIX."expeditiondet_batch"; + $sql.= " WHERE fk_expeditiondet = ".$this->id; + $sql.= " AND rowid = ".$expedition_batch_id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + } + if (! $error && $this->detail_batch->dluo_qty > 0) + { + // create lot expedition line + if (isset($lot->id)) + { + $shipmentLot = new ExpeditionLineBatch($this->db); + $shipmentLot->batch = $lot->batch; + $shipmentLot->eatby = $lot->eatby; + $shipmentLot->sellby = $lot->sellby; + $shipmentLot->entrepot_id = $this->detail_batch->entrepot_id; + $shipmentLot->dluo_qty = $this->detail_batch->dluo_qty; + $shipmentLot->fk_origin_stock = $batch_id; + if ($shipmentLot->create($this->id) < 0) + { + $this->errors[]=$shipmentLot->errors; + $error++; + } + } + } + } + } + if (! $error) + { + // update line + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + $sql.= " fk_entrepot = ".($this->entrepot_id > 0 ? $this->entrepot_id : 'null'); + $sql.= " , qty = ".$qty; + $sql.= " WHERE rowid = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + else + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINESHIPPING_UPDATE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + if (!$error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } } diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index a5857503c30..6fb40c12dd6 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -55,6 +55,7 @@ MemberSubscriptionAddedInDolibarr=Subscription for member %s added ShipmentValidatedInDolibarr=Shipment %s validated ShipmentClassifyClosedInDolibarr=Shipment %s classified billed ShipmentUnClassifyCloseddInDolibarr=Shipment %s classified reopened +ShipmentBackToDraftInDolibarr=Shipment %s go back to draft status ShipmentDeletedInDolibarr=Shipment %s deleted OrderCreatedInDolibarr=Order %s created OrderValidatedInDolibarr=Order %s validated diff --git a/htdocs/langs/fr_FR/agenda.lang b/htdocs/langs/fr_FR/agenda.lang index dbbf3513041..99155484d1b 100644 --- a/htdocs/langs/fr_FR/agenda.lang +++ b/htdocs/langs/fr_FR/agenda.lang @@ -55,6 +55,7 @@ MemberSubscriptionAddedInDolibarr=Souscription adhérent %s ShipmentValidatedInDolibarr=Expédition %s validée ShipmentClassifyClosedInDolibarr=Expédition %s classée payée ShipmentUnClassifyCloseddInDolibarr=Expédition %s réouverte +ShipmentBackToDraftInDolibarr=Expédition %s repassée en brouillon ShipmentDeletedInDolibarr=Expédition %s supprimée OrderCreatedInDolibarr=Commande %s créée OrderValidatedInDolibarr=Commande %s validée From 69c46ecd86c3c199bf3f6cae3bde473151694dcb Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Tue, 2 Oct 2018 16:54:20 +0200 Subject: [PATCH 02/50] set order status to valid when shipping set to draft --- htdocs/expedition/class/expedition.class.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index f5eb969149a..0db89a0a1e0 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -2284,6 +2284,13 @@ class Expedition extends CommonObject $result=$this->call_trigger('SHIPPING_UNVALIDATE',$user); if ($result < 0) $error++; } + if($this->origin == 'commande'){ + $commande = new Commande($this->db); + $commande->fetch($this->origin_id); + $commande->statut = Commande::STATUS_VALIDATED; + $commande->update(); + } + if (!$error) { $this->statut=self::STATUS_DRAFT; From 41d8cb87a3f2075088a404f7b366786303744e84 Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Wed, 3 Oct 2018 12:22:41 +0200 Subject: [PATCH 03/50] debut reception setup page --- htdocs/admin/reception_setup.php | 520 +++ htdocs/core/lib/reception.lib.php | 101 + htdocs/core/menus/init_menu_auguria.sql | 5 + htdocs/core/menus/standard/eldy.lib.php | 12 + htdocs/core/modules/modReception.class.php | 266 ++ .../doc/doc_generic_reception_odt.modules.php | 522 +++ htdocs/core/modules/reception/doc/index.html | 0 .../reception/doc/pdf_squille.modules.php | 1031 ++++++ htdocs/core/modules/reception/index.html | 0 .../modules/reception/mod_reception_beryl.php | 145 + .../reception/mod_reception_moonstone.php | 137 + .../modules/reception/modules_reception.php | 136 + .../mysql/tables/llx_reception.key.sql | 31 + htdocs/install/mysql/tables/llx_reception.sql | 62 + .../tables/llx_reception_extrafields.key.sql | 20 + .../tables/llx_reception_extrafields.sql | 26 + .../mysql/tables/llx_receptiondet.key.sql | 22 + .../install/mysql/tables/llx_receptiondet.sql | 29 + .../tables/llx_receptiondet_batch.key.sql | 20 + .../mysql/tables/llx_receptiondet_batch.sql | 27 + .../llx_receptiondet_extrafields.key.sql | 20 + .../tables/llx_receptiondet_extrafields.sql | 25 + htdocs/langs/en_US/receptions.lang | 70 + htdocs/langs/fr_FR/admin.lang | 7 + htdocs/langs/fr_FR/receptions.lang | 70 + htdocs/reception/card.php | 2754 ++++++++++++++++ .../reception/class/expeditionbatch.class.php | 223 ++ .../reception/class/expeditionstats.class.php | 142 + htdocs/reception/class/index.html | 0 htdocs/reception/class/reception.class.php | 2824 +++++++++++++++++ htdocs/reception/contact.php | 274 ++ htdocs/reception/index.php | 296 ++ htdocs/reception/list.php | 669 ++++ htdocs/reception/note.php | 164 + htdocs/reception/shipment.php | 939 ++++++ htdocs/reception/stats/index.php | 364 +++ htdocs/reception/stats/month.php | 76 + htdocs/reception/tpl/index.html | 0 .../reception/tpl/linkedobjectblock.tpl.php | 80 + 39 files changed, 12109 insertions(+) create mode 100644 htdocs/admin/reception_setup.php create mode 100644 htdocs/core/lib/reception.lib.php create mode 100644 htdocs/core/modules/modReception.class.php create mode 100644 htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php create mode 100644 htdocs/core/modules/reception/doc/index.html create mode 100644 htdocs/core/modules/reception/doc/pdf_squille.modules.php create mode 100644 htdocs/core/modules/reception/index.html create mode 100644 htdocs/core/modules/reception/mod_reception_beryl.php create mode 100644 htdocs/core/modules/reception/mod_reception_moonstone.php create mode 100644 htdocs/core/modules/reception/modules_reception.php create mode 100644 htdocs/install/mysql/tables/llx_reception.key.sql create mode 100644 htdocs/install/mysql/tables/llx_reception.sql create mode 100644 htdocs/install/mysql/tables/llx_reception_extrafields.key.sql create mode 100644 htdocs/install/mysql/tables/llx_reception_extrafields.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet.key.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet_batch.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql create mode 100644 htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql create mode 100644 htdocs/langs/en_US/receptions.lang create mode 100644 htdocs/langs/fr_FR/receptions.lang create mode 100644 htdocs/reception/card.php create mode 100644 htdocs/reception/class/expeditionbatch.class.php create mode 100644 htdocs/reception/class/expeditionstats.class.php create mode 100644 htdocs/reception/class/index.html create mode 100644 htdocs/reception/class/reception.class.php create mode 100644 htdocs/reception/contact.php create mode 100644 htdocs/reception/index.php create mode 100644 htdocs/reception/list.php create mode 100644 htdocs/reception/note.php create mode 100644 htdocs/reception/shipment.php create mode 100644 htdocs/reception/stats/index.php create mode 100644 htdocs/reception/stats/month.php create mode 100644 htdocs/reception/tpl/index.html create mode 100644 htdocs/reception/tpl/linkedobjectblock.tpl.php diff --git a/htdocs/admin/reception_setup.php b/htdocs/admin/reception_setup.php new file mode 100644 index 00000000000..710c1fb6ba1 --- /dev/null +++ b/htdocs/admin/reception_setup.php @@ -0,0 +1,520 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/admin/confexped.php + * \ingroup produit + * \brief Page to setup reception module + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; + +$langs->load("admin"); +$langs->load("receptions"); +$langs->load('other'); + + +if (!$user->admin) + accessforbidden(); + +$action=GETPOST('action','alpha'); +$value=GETPOST('value','alpha'); +$label = GETPOST('label','alpha'); +$scandir = GETPOST('scan_dir','alpha'); +$type='reception'; + + +/* + * Actions + */ + +if (! empty($conf->reception->enabled) && empty($conf->global->MAIN_SUBMODULE_RECEPTION)) +{ + // This option should always be set to on when module is on. + dolibarr_set_const($db, "MAIN_SUBMODULE_RECEPTION", "1",'chaine',0,'',$conf->entity); +} + +if (empty($conf->global->RECEPTION_ADDON_NUMBER)) +{ + $conf->global->RECEPTION_ADDON_NUMBER='mod_reception_beryl'; +} + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; + +if ($action == 'updateMask') +{ + $maskconst=GETPOST('maskconstreception','alpha'); + $maskvalue=GETPOST('maskreception','alpha'); + if (! empty($maskconst)) + $res = dolibarr_set_const($db,$maskconst,$maskvalue,'chaine',0,'',$conf->entity); + + if (isset($res)) + { + if ($res > 0) + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + else + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + +else if ($action == 'set_param') +{ + $freetext=GETPOST('RECEPTION_FREE_TEXT','none'); // No alpha here, we want exact string + $res = dolibarr_set_const($db, "RECEPTION_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity); + if ($res <= 0) + { + $error++; + setEventMessages($langs->trans("Error"), null, 'errors'); + } + + $draft=GETPOST('RECEPTION_DRAFT_WATERMARK','alpha'); + $res = dolibarr_set_const($db, "RECEPTION_DRAFT_WATERMARK",trim($draft),'chaine',0,'',$conf->entity); + if ($res <= 0) + { + $error++; + setEventMessages($langs->trans("Error"), null, 'errors'); + } + + if (! $error) + { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } +} + +else if ($action == 'specimen') +{ + $modele=GETPOST('module','alpha'); + + $exp = new Reception($db); + $exp->initAsSpecimen(); + + // Search template files + $file=''; $classname=''; $filefound=0; + $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + foreach($dirmodels as $reldir) + { + $file=dol_buildpath($reldir."core/modules/reception/doc/pdf_".$modele.".modules.php",0); + if (file_exists($file)) + { + $filefound=1; + $classname = "pdf_".$modele; + break; + } + } + + if ($filefound) + { + require_once $file; + + $module = new $classname($db); + + if ($module->write_file($exp,$langs) > 0) + { + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=reception&file=SPECIMEN.pdf"); + return; + } + else + { + setEventMessages($module->error, $module->errors, 'errors'); + dol_syslog($module->error, LOG_ERR); + } + } + else + { + setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors'); + dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR); + } +} + +// Activate a model +else if ($action == 'set') +{ + $ret = addDocumentModel($value, $type, $label, $scandir); +} + +else if ($action == 'del') +{ + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + if ($conf->global->RECEPTION_ADDON_PDF == "$value") dolibarr_del_const($db, 'RECEPTION_ADDON_PDF',$conf->entity); + } +} + +// Set default model +else if ($action == 'setdoc') +{ + if (dolibarr_set_const($db, "RECEPTION_ADDON_PDF",$value,'chaine',0,'',$conf->entity)) + { + // La constante qui a ete lue en avant du nouveau set + // on passe donc par une variable pour avoir un affichage coherent + $conf->global->RECEPTION_ADDON_PDF = $value; + } + + // On active le modele + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + $ret = addDocumentModel($value, $type, $label, $scandir); + } +} + +else if ($action == 'setmodel') +{ + dolibarr_set_const($db, "RECEPTION_ADDON_NUMBER",$value,'chaine',0,'',$conf->entity); +} + + + + +/* + * View + */ + +$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + +$form=new Form($db); + +llxHeader("",$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print '
'; +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'reception', $langs->trans("Receptions"), -1, 'reception'); + +// Reception numbering model + +print load_fiche_titre($langs->trans("ReceptionsNumberingModules")); + +print '
 '.$langs->trans("Products").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyToShip").''.$langs->trans("QtyInOtherShipments").''; + if ($object->statut <= 1) + { + print $langs->trans("QtyToShip").' - '; + } + else + { + print $langs->trans("QtyShipped").' - '; + } + if (! empty($conf->stock->enabled)) + { + print $langs->trans("WarehouseSource").' - '; + } + if (! empty($conf->productbatch->enabled)) + { + print $langs->trans("Batch"); + } + print ''.$langs->trans("QtyShipped").''.$langs->trans("QtyToShip").''.$langs->trans("QtyShipped").''.$langs->trans("WarehouseSource").''.$langs->trans("QtyInOtherShipments").''.$langs->trans("Batch").''.$langs->trans("CalculatedWeight").''.$langs->trans("CalculatedVolume").''.$langs->trans("Size").''.$langs->trans("WarehouseSource").''.$langs->trans("Batch").'
'.($i+1).'"; - if ($lines[$i]->fk_product_type==1) $text = img_object($langs->trans('Service'),'service'); + if ($lines[$i]->product_type == Product::TYPE_SERVICE) $text = img_object($langs->trans('Service'),'service'); else $text = img_object($langs->trans('Product'),'product'); if (! empty($lines[$i]->label)) { @@ -1893,9 +2255,6 @@ else if ($id || $ref) // Qty ordered print ''.$lines[$i]->qty_asked.''.$lines[$i]->qty_shipped.''; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + print ''; + $line = new ExpeditionLigne($db); + foreach ($lines[$i]->detail_batch as $detail_batch) + { + print ''; + // Qty to ship or shipped + print ''; + // Batch number managment + if ($lines[$i]->entrepot_id == 0) + { + // only show lot numbers from src warehouse when shipping from multiple warehouses + $line->fetch($detail_batch->fk_expeditiondet); + } + print ''; + print ''; + } + // add a 0 qty lot row to be able to add a lot + print ''; + // Qty to ship or shipped + print ''; + // Batch number managment + print ''; + print ''; + } + else if (! empty($conf->stock->enabled)) + { + if ($lines[$i]->fk_product > 0) + { + if ($lines[$i]->entrepot_id > 0) + { + print ''; + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + else if (count($lines[$i]->details_entrepot) > 1) + { + print ''; + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + else + { + print ''; + print ''; + } + } + else + { + print ''; + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + print '
' . '' . '' . $formproduct->selectLotStock($detail_batch->fk_origin_stock, 'batchl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->fk_origin_stock, '', 1, 0, $lines[$i]->fk_product, $line->entrepot_id). '
' . '' . '' . $formproduct->selectLotStock('', 'batchl'.$line_id.'_0', '', 1, 0, $lines[$i]->fk_product). '
' . '' . '' . $formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1). ' - ' . $langs->trans("NA") . '
' . '' . '' . $formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl'.$detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1) . ' - ' . $langs->trans("NA") . '
'.$langs->trans("NotEnoughStock").'
' . '' . '' . '' . '
'.$lines[$i]->qty_shipped.''; + if ($lines[$i]->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($lines[$i]->entrepot_id); + print $entrepot->getNomUrl(1); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + $detail = ''; + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if ($detail_entrepot->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($detail_entrepot->entrepot_id); + $detail.= $langs->trans("DetailWarehouseFormat",$entrepot->libelle,$detail_entrepot->qty_shipped).'
'; + } + } + print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"),$detail); + } + print '
'; + if ($lines[$i]->product_tobatch) + { + $detail = ''; + foreach ($lines[$i]->detail_batch as $dbatch) + { + $detail.= $langs->trans("Batch").': '.$dbatch->batch; + $detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day"); + $detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day"); + $detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty; + $detail.= '
'; + } + print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); + } + else + { + print $langs->trans("NA"); + } + print '
'; - if ($lines[$i]->fk_product_type == 0) print $lines[$i]->weight*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->weight_units,"weight"); + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->weight*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->weight_units,"weight"); else print ' '; print ''; - if ($lines[$i]->fk_product_type == 0) print $lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume"); + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume"); else print ' '; print ''.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume").''; - if ($lines[$i]->entrepot_id > 0) - { - $entrepot = new Entrepot($db); - $entrepot->fetch($lines[$i]->entrepot_id); - print $entrepot->getNomUrl(1); - } - else if (count($lines[$i]->details_entrepot) > 1) - { - $detail = ''; - foreach ($lines[$i]->details_entrepot as $detail_entrepot) - { - if ($detail_entrepot->entrepot_id > 0) - { - $entrepot = new Entrepot($db); - $entrepot->fetch($detail_entrepot->entrepot_id); - $detail.= $langs->trans("DetailWarehouseFormat",$entrepot->libelle,$detail_entrepot->qty_shipped).'
'; - } - } - print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"),$detail); - } - print '
'; + print '
'; + print '
'; } - - // Batch number managment - if (! empty($conf->productbatch->enabled)) + else if ($object->statut == 0) { - if (isset($lines[$i]->detail_batch)) + // edit-delete buttons + print '
'; + print 'id . '">' . img_edit() . ''; + print ''; + print 'id . '">' . img_delete() . ''; + print ''; - if ($lines[$i]->product_tobatch) - { - $detail = ''; - foreach ($lines[$i]->detail_batch as $dbatch) - { - $detail.= $langs->trans("DetailBatchFormat",$dbatch->batch,dol_print_date($dbatch->eatby,"day"),dol_print_date($dbatch->sellby,"day"),$dbatch->dluo_qty).'
'; - } - print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); - } - else - { - print $langs->trans("NA"); - } - print '
'; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +clearstatcache(); + +foreach ($dirmodels as $reldir) +{ + $dir = dol_buildpath($reldir."core/modules/reception/"); + + if (is_dir($dir)) + { + $handle = opendir($dir); + if (is_resource($handle)) + { + while (($file = readdir($handle))!==false) + { + if (substr($file, 0, 14) == 'mod_reception_' && substr($file, dol_strlen($file)-3, 3) == 'php') + { + $file = substr($file, 0, dol_strlen($file)-4); + + require_once $dir.$file.'.php'; + + $module = new $file; + + if ($module->isEnabled()) + { + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; + + print '\n"; + print ''; + + // Show example of numbering module + print ''."\n"; + + print ''; + + $reception=new Reception($db); + $reception->initAsSpecimen(); + + // Info + $htmltooltip=''; + $htmltooltip.=''.$langs->trans("Version").': '.$module->getVersion().'
'; + $nextval=$module->getNextValue($mysoc,$reception); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip.=''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/',$nextval) || $nextval=='NotConfigured') + $nextval = $langs->trans($nextval); + $htmltooltip.=$nextval.'
'; + } else { + $htmltooltip.=$langs->trans($module->error).'
'; + } + } + + print ''; + + print ''; + } + } + } + closedir($handle); + } + } +} + +print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->nom."'; + print $module->info(); + print ''; + $tmp=$module->getExample(); + if (preg_match('/^Error/',$tmp)) { + $langs->load("errors"); print '
'.$langs->trans($tmp).'
'; + } + elseif ($tmp=='NotConfigured') print $langs->trans($tmp); + else print $tmp; + print '
'; + if ($conf->global->RECEPTION_ADDON_NUMBER == "$file") + { + print img_picto($langs->trans("Activated"),'switch_on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'">'; + print img_picto($langs->trans("Disabled"),'switch_off'); + print ''; + } + print ''; + print $form->textwithpicto('',$htmltooltip,1,0); + print '

'; + + +/* + * Documents models for Receptions Receipt + */ +print load_fiche_titre($langs->trans("ReceptionsReceiptModel")); + +// Defini tableau def de modele invoice +$type="reception"; +$def = array(); + +$sql = "SELECT nom"; +$sql.= " FROM ".MAIN_DB_PREFIX."document_model"; +$sql.= " WHERE type = '".$type."'"; +$sql.= " AND entity = ".$conf->entity; + +$resql=$db->query($sql); +if ($resql) +{ + $i = 0; + $num_rows=$db->num_rows($resql); + while ($i < $num_rows) + { + $array = $db->fetch_array($resql); + array_push($def, $array[0]); + $i++; + } +} +else +{ + dol_print_error($db); +} + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +clearstatcache(); + +foreach ($dirmodels as $reldir) +{ + foreach (array('','/doc') as $valdir) + { + $dir = dol_buildpath($reldir."core/modules/reception".$valdir); + + if (is_dir($dir)) + { + $handle=opendir($dir); + if (is_resource($handle)) + { + while (($file = readdir($handle))!==false) + { + $filelist[]=$file; + } + closedir($handle); + arsort($filelist); + + foreach($filelist as $file) + { + if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file)) + { + + if (file_exists($dir.'/'.$file)) + { + $name = substr($file, 4, dol_strlen($file) -16); + $classname = substr($file, 0, dol_strlen($file) -12); + + require_once $dir.'/'.$file; + $module = new $classname($db); + + $modulequalified=1; + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified=0; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified=0; + + if ($modulequalified) + { + print ''; + + // Active + if (in_array($name, $def)) + { + print ''; + } + else + { + print '"; + } + + // Defaut + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); + if ($module->type == 'pdf') + { + $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); + $htmltooltip.='
'.$langs->trans("PaymentMode").': '.yn($module->option_modereg,1,1); + $htmltooltip.='
'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg,1,1); + $htmltooltip.='
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang,1,1); + $htmltooltip.='
'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark,1,1); + + print ''; + + // Preview + print ''; + + print "\n"; + } + } + } + } + } + } + } +} + +print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status").''.$langs->trans("Default").''.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'; + print (empty($module->name)?$name:$module->name); + print "\n"; + if (method_exists($module,'info')) print $module->info($langs); + else print $module->description; + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"),'switch_on'); + print ''; + print ''."\n"; + print 'scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').''; + print "'; + if ($conf->global->RECEPTION_ADDON_PDF == $name) + { + print img_picto($langs->trans("Default"),'on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; + } + print ''; + print $form->textwithpicto('',$htmltooltip,1,0); + print ''; + if ($module->type == 'pdf') + { + print 'scandir.'&label='.urlencode($module->name).'">'.img_object($langs->trans("Preview"),'reception').''; + } + else + { + print img_object($langs->trans("PreviewNotAvailable"),'generic'); + } + print '
'; +print '
'; + + +/* + * Other options + * + */ +/* +print load_fiche_titre($langs->trans("OtherOptions")); + +print ''; +print ''; +print ''; + +print ""; +print ""; +print "\n"; +print ""; + +$substitutionarray=pdf_getSubstitutionArray($langs); +$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation"); +$htmltext = ''.$langs->trans("AvailableVariables").':
'; +foreach($substitutionarray as $key => $val) $htmltext.=$key.'
'; +$htmltext.='
'; + +print '\n"; + +print '\n"; +*/ +print '
".$langs->trans("Parameter")."
'; +print $form->textwithpicto($langs->trans("FreeLegalTextOnReceptions"), $langs->trans("AddCRIfTooLong").'

'.$htmltext).'
'; +$variablename='RECEPTION_FREE_TEXT'; +if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) +{ + print ''; +} +else +{ + include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($variablename, $conf->global->$variablename,'',80,'dolibarr_notes'); + print $doleditor->Create(); +} +print "
'; +print $form->textwithpicto($langs->trans("WatermarkOnDraftContractCards"), $htmltext).'
'; +print ''; +print "
'; + +print '
'; + +print ''; + +llxFooter(); +$db->close(); diff --git a/htdocs/core/lib/reception.lib.php b/htdocs/core/lib/reception.lib.php new file mode 100644 index 00000000000..34cd46026ed --- /dev/null +++ b/htdocs/core/lib/reception.lib.php @@ -0,0 +1,101 @@ + + * Copyright (C) 2007 Rodolphe Quiedeville + * Copyright (C) 2010-2012 Regis Houssin + * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2015 Claudio Aschieri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/lib/reception.lib.php + * \brief Function for reception module + * \ingroup reception + */ + +/** + * Prepare array with list of tabs + * + * @param Reception $object Object related to tabs + * @return array Array of tabs to show + */ +function reception_prepare_head(Reception $object) +{ + global $langs, $conf, $user; + if (! empty($conf->reception->enabled)) $langs->load("receptions"); + $langs->load("orders"); + + $h = 0; + $head = array(); + $h = 0; + + $head[$h][0] = DOL_URL_ROOT."/admin/reception_setup.php"; + $head[$h][1] = $langs->trans("Setup"); + $h++; + + + + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'order','remove'); + + return $head; +} + +/** + * Return array head with list of tabs to view object informations. + * + * @return array head array with tabs + */ +function reception_admin_prepare_head() +{ + global $langs, $conf, $user; + $langs->load("receptions"); + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT."/admin/reception_setup.php"; + $head[$h][1] = $langs->trans("Reception"); + $head[$h][2] = 'reception'; + $h++; + + + if (! empty($conf->global->MAIN_SUBMODULE_RECEPTION)) + { + $head[$h][0] = DOL_URL_ROOT.'/admin/reception_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'attributes_reception'; + $h++; + } + + if (! empty($conf->global->MAIN_SUBMODULE_RECEPTION)) + { + $head[$h][0] = DOL_URL_ROOT.'/admin/receptiondet_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsLines"); + $head[$h][2] = 'attributeslines_reception'; + $h++; + } + + + + complete_head_from_modules($conf,$langs,null,$head,$h,'reception_admin','remove'); + + return $head; +} + + diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index 445ec83d58d..2d92ace947a 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -122,6 +122,11 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1301__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/card.php?action=create2&leftmenu=sendings', 'NewSending', 1, 'sendings', '$user->rights->expedition->creer', '', 2, 0, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1302__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/list.php?leftmenu=sendings', 'List', 1, 'sendings', '$user->rights->expedition->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1303__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/stats/index.php?leftmenu=sendings', 'Statistics', 1, 'sendings', '$user->rights->expedition->lire', '', 2, 2, __ENTITY__); +-- Product - Reception +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled', __HANDLER__, 'left', 1300__+MAX_llx_menu__, 'commercial', 'receptions', 3__+MAX_llx_menu__, '/reception/index.php?leftmenu=receptions', 'Receptions', 0, 'receptions', '$user->rights->reception->lire', '', 2, 6, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1301__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/card.php?action=create2&leftmenu=receptions', 'NewSending', 1, 'receptions', '$user->rights->reception->creer', '', 2, 0, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1302__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/list.php?leftmenu=receptions', 'List', 1, 'receptions', '$user->rights->reception->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1303__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/stats/index.php?leftmenu=receptions', 'Statistics', 1, 'receptions', '$user->rights->reception->lire', '', 2, 2, __ENTITY__); -- Commercial - Proposals insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 1100__+MAX_llx_menu__, 'commercial', 'propals', 5__+MAX_llx_menu__, '/comm/propal/index.php?leftmenu=propals', 'Prop', 0, 'propal', '$user->rights->propale->lire', '', 2, 4, __ENTITY__); diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index e9876b31ece..486b8bc7e9c 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1269,6 +1269,18 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu if ($usemenuhider || empty($leftmenu) || $leftmenu=="sendings") $newmenu->add("/expedition/list.php?leftmenu=sendings&viewstatut=2", $langs->trans("StatusSendingProcessedShort"), 2, $user->rights->expedition->lire); $newmenu->add("/expedition/stats/index.php?leftmenu=sendings", $langs->trans("Statistics"), 1, $user->rights->expedition->lire); } + // Receptions + if (! empty($conf->reception->enabled)) + { + $langs->load("receptions"); + $newmenu->add("/reception/index.php?leftmenu=receptions", $langs->trans("Receptions"), 0, $user->rights->reception->lire, '', $mainmenu, 'receptions'); + $newmenu->add("/reception/card.php?action=create2&leftmenu=receptions", $langs->trans("NewReception"), 1, $user->rights->reception->creer); + $newmenu->add("/reception/list.php?leftmenu=receptions", $langs->trans("List"), 1, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=0", $langs->trans("StatusReceptionDraftShort"), 2, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=1", $langs->trans("StatusReceptionValidatedShort"), 2, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=2", $langs->trans("StatusReceptionProcessedShort"), 2, $user->rights->reception->lire); + $newmenu->add("/reception/stats/index.php?leftmenu=receptions", $langs->trans("Statistics"), 1, $user->rights->reception->lire); + } } diff --git a/htdocs/core/modules/modReception.class.php b/htdocs/core/modules/modReception.class.php new file mode 100644 index 00000000000..402c1a0f8f2 --- /dev/null +++ b/htdocs/core/modules/modReception.class.php @@ -0,0 +1,266 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \defgroup reception Module reception + * \brief Module pour gerer les réceptions de produits + * \file htdocs/core/modules/modReception.class.php + * \ingroup reception + * \brief Fichier de description et activation du module Reception + */ + +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Class to describe and enable module Reception + */ +class modReception extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf, $user; + + $this->db = $db; + $this->numero = 104160; + + $this->family = "crm"; + $this->module_position = 40; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i','',get_class($this)); + $this->description = "Gestion des réceptions fournisseurs"; + + // Possible values for version are: 'development', 'experimental', 'dolibarr' or version + $this->version = 'dolibarr'; + + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + $this->special = 0; + $this->picto = "sending"; + + // Data directories to create when module is enabled + $this->dirs = array("/reception/receipt", + "/reception/receipt/temp", + "/doctemplates/reception" + ); + + // Config pages + $this->config_page_url = array("reception_setup.php"); + + // Dependencies + $this->depends = array("modFournisseur"); + $this->requiredby = array(); + $this->conflictwith = array(); + $this->langfiles = array('receptions'); + + // Constants + $this->const = array(); + $r=0; + + $this->const[$r][0] = "RECEPTION_ADDON_PDF"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "squille"; + $this->const[$r][3] = 'Nom du gestionnaire de generation des bons receptions en PDF'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "RECEPTION_ADDON_NUMBER"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "mod_reception_beryl"; + $this->const[$r][3] = 'Name for numbering manager for receptions'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "RECEPTION_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/receptions"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "MAIN_SUBMODULE_RECEPTION"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "1"; + $this->const[$r][3] = "Enable receptions"; + $this->const[$r][4] = 0; + $r++; + + // Boxes + $this->boxes = array(); + + // Permissions + $this->rights = array(); + $this->rights_class = 'reception'; + $r=0; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Lire les receptions'; + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'lire'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Creer modifier les receptions'; + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'creer'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Valider les receptions'; + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'reception_advance'; + $this->rights[$r][5] = 'validate'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; // id de la permission + $this->rights[$r][1] = 'Envoyer les receptions aux clients'; // libelle de la permission + $this->rights[$r][2] = 'd'; // 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] = 'reception_advance'; + $this->rights[$r][5] = 'send'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Exporter les receptions'; + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'reception'; + $this->rights[$r][5] = 'export'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Supprimer les receptions'; + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'supprimer'; + + + // Menus + //------- + $this->menu = 1; // This module add menu entries. They are coded into menu manager. + + + // Exports + //-------- + $r=0; +/* + include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; + $shipment=new Commande($this->db); + $contact_arrays=$shipment->liste_type_contact('external','',0,0,''); + if (is_array($contact_arrays) && count($contact_arrays)>0){ + $idcontacts=join(',',array_keys($shipment->liste_type_contact('external','',0,0,''))); + } else { + $idcontacts=0; + } + + + $r++; + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]='Shipments'; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_permission[$r]=array(array("reception","shipment","export")); + $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'ThirdParty','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','d.nom'=>'State','co.label'=>'Country','co.code'=>'CountryCode','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.idprof5'=>'ProfId5','s.idprof6'=>'ProfId6','c.rowid'=>"Id",'c.ref'=>"Ref",'c.ref_customer'=>"RefCustomer",'c.fk_soc'=>"IdCompany",'c.date_creation'=>"DateCreation",'c.date_delivery'=>"DateDeliveryPlanned",'c.tracking_number'=>"TrackingNumber",'c.height'=>"Height",'c.width'=>"Width",'c.size'=>"Depth",'c.size_units'=>'SizeUnits','c.weight'=>"Weight",'c.weight_units'=>"WeightUnits",'c.fk_statut'=>'Status','c.note_public'=>"NotePublic",'ed.rowid'=>'LineId','cd.description'=>'Description','ed.qty'=>"Qty",'p.rowid'=>'ProductId','p.ref'=>'ProductRef','p.label'=>'ProductLabel','p.weight'=>'ProductWeight','p.weight_units'=>'WeightUnits','p.volume'=>'ProductVolume','p.volume_units'=>'VolumeUnits'); + if ($idcontacts && ! empty($conf->global->SHIPMENT_ADD_CONTACTS_IN_EXPORT)) $this->export_fields_array[$r]+=array('sp.rowid'=>'IdContact','sp.lastname'=>'Lastname','sp.firstname'=>'Firstname','sp.note_public'=>'NotePublic'); + //$this->export_TypeFields_array[$r]=array('s.rowid'=>"List:societe:nom",'s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.label'=>'List:c_country:label:label','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_client'=>"Text",'c.date_creation'=>"Date",'c.date_commande'=>"Date",'c.amount_ht'=>"Numeric",'c.remise_percent'=>"Numeric",'c.total_ht'=>"Numeric",'c.total_ttc'=>"Numeric",'c.facture'=>"Boolean",'c.fk_statut'=>'Status','c.note_public'=>"Text",'c.date_livraison'=>'Date','ed.qty'=>"Text"); + $this->export_TypeFields_array[$r]=array('s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.label'=>'List:c_country:label:label','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_customer'=>"Text",'c.date_creation'=>"Date",'c.date_delivery'=>"Date",'c.tracking_number'=>"Numeric",'c.height'=>"Numeric",'c.width'=>"Numeric",'c.weight'=>"Numeric",'c.fk_statut'=>'Status','c.note_public'=>"Text",'ed.qty'=>"Numeric",'d.nom'=>'Text'); + $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','d.nom'=>'company','co.label'=>'company','co.code'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.ape'=>'company','s.siret'=>'company','s.idprof4'=>'company','s.idprof5'=>'company','s.idprof6'=>'company','c.rowid'=>"shipment",'c.ref'=>"shipment",'c.ref_customer'=>"shipment",'c.fk_soc'=>"shipment",'c.date_creation'=>"shipment",'c.date_delivery'=>"shipment",'c.tracking_number'=>'shipment','c.height'=>"shipment",'c.width'=>"shipment",'c.size'=>'shipment','c.size_units'=>'shipment','c.weight'=>"shipment",'c.weight_units'=>'shipment','c.fk_statut'=>"shipment",'c.note_public'=>"shipment",'ed.rowid'=>'shipment_line','cd.description'=>'shipment_line','ed.qty'=>"shipment_line",'p.rowid'=>'product','p.ref'=>'product','p.label'=>'product','p.weight'=>'product','p.weight_units'=>'product','p.volume'=>'product','p.volume_units'=>'product'); + if ($idcontacts && ! empty($conf->global->SHIPMENT_ADD_CONTACTS_IN_EXPORT)) $this->export_entities_array[$r]+=array('sp.rowid'=>'contact','sp.lastname'=>'contact','sp.firstname'=>'contact','sp.note_public'=>'contact'); + $this->export_dependencies_array[$r]=array('shipment_line'=>'ed.rowid','product'=>'ed.rowid'); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them + if ($idcontacts && ! empty($conf->global->SHIPMENT_ADD_CONTACTS_IN_EXPORT)) + { + $keyforselect='socpeople'; $keyforelement='contact'; $keyforaliasextra='extra3'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + } + $keyforselect='reception'; $keyforelement='shipment'; $keyforaliasextra='extra'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + $keyforselect='receptiondet'; $keyforelement='shipment_line'; $keyforaliasextra='extra2'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'reception as c'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'reception_extrafields as extra ON c.rowid = extra.fk_object,'; + $this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'societe as s'; + if(!$user->rights->societe->client->voir) $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe_commerciaux as sc ON sc.fk_soc = s.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_departements as d ON s.fk_departement = d.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON s.fk_pays = co.rowid,'; + $this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'receptiondet as ed'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'receptiondet_extrafields as extra2 ON ed.rowid = extra2.fk_object'; + $this->export_sql_end[$r] .=' , '.MAIN_DB_PREFIX.'commandedet as cd'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on cd.fk_product = p.rowid'; + if ($idcontacts && ! empty($conf->global->SHIPMENT_ADD_CONTACTS_IN_EXPORT)) + { + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'element_contact as ee ON ee.element_id = cd.fk_commande AND ee.fk_c_type_contact IN ('.$idcontacts.')'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'socpeople as sp ON sp.rowid = ee.fk_socpeople'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'socpeople_extrafields as extra3 ON sp.rowid = extra3.fk_object'; + } + $this->export_sql_end[$r] .=' WHERE c.fk_soc = s.rowid AND c.rowid = ed.fk_reception AND ed.fk_origin_line = cd.rowid'; + $this->export_sql_end[$r] .=' AND c.entity IN ('.getEntity('reception').')'; + if(!$user->rights->societe->client->voir) $this->export_sql_end[$r] .=' AND sc.fk_user = '.$user->id;*/ + } + + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function init($options='') + { + global $conf,$langs; + + // Permissions + $this->remove($options); + + //ODT template + $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/reception/template_reception.odt'; + $dirodt=DOL_DATA_ROOT.'/doctemplates/reception'; + $dest=$dirodt.'/template_reception.odt'; + + if (file_exists($src) && ! file_exists($dest)) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + dol_mkdir($dirodt); + $result=dol_copy($src,$dest,0,0); + if ($result < 0) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorFailToCopyFile',$src,$dest); + return 0; + } + } + + $sql = array(); + + $sql = array( + "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[0][2])."' AND type = 'reception' AND entity = ".$conf->entity, + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."','reception',".$conf->entity.")", + ); + + return $this->_init($sql,$options); + } +} diff --git a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php new file mode 100644 index 00000000000..4a19d82e449 --- /dev/null +++ b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php @@ -0,0 +1,522 @@ + +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* 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 . +* or see http://www.gnu.org/ +*/ + +/** + * \file htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php + * \ingroup reception + * \brief File of class to build ODT documents for reception + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php'; + + +/** + * Class to build documents using ODF templates generator + */ +class doc_generic_reception_odt extends ModelePdfReception +{ + var $emetteur; // Objet societe qui emet + + var $phpmin = array(5,2,0); // Minimum version of PHP required by module + var $version = 'dolibarr'; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + $langs->load("main"); + $langs->load("companies"); + + $this->db = $db; + $this->name = "ODT templates"; + $this->description = $langs->trans("DocumentModelOdt"); + $this->scandir = 'RECEPTION_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan + + // Dimension page pour format A4 + $this->type = 'odt'; + $this->page_largeur = 0; + $this->page_hauteur = 0; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=0; + $this->marge_droite=0; + $this->marge_haute=0; + $this->marge_basse=0; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 0; // Gere option tva RECEPTION_TVAOPTION + $this->option_modereg = 0; // Affiche mode reglement + $this->option_condreg = 0; // Affiche conditions reglement + $this->option_codeproduitservice = 0; // Affiche code produit-service + $this->option_multilang = 1; // Dispo en plusieurs langues + $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_credit_note = 0; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 0; // Support add of a watermark on drafts + + // Recupere emetteur + $this->emetteur=$mysoc; + if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default if not defined + } + + + /** + * Return description of a module + * + * @param Translate $langs Lang object to use for output + * @return string Description + */ + function info($langs) + { + global $conf,$langs; + + $langs->load("companies"); + $langs->load("errors"); + + $form = new Form($this->db); + + $texte = $this->description.".
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + // List of directories area + $texte.= ''; + + $texte.= ''; + $texte.= ''; + + $texte.= '
'; + $texttitle=$langs->trans("ListOfDirectories"); + $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->RECEPTION_ADDON_PDF_ODT_PATH))); + $listoffiles=array(); + foreach($listofdir as $key=>$tmpdir) + { + $tmpdir=trim($tmpdir); + $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir); + if (! $tmpdir) { + unset($listofdir[$key]); continue; + } + if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0); + else + { + $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.(ods|odt)'); + if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles); + } + } + $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT"); + // Add list of substitution keys + $texthelp.='
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + + // Scan directories + $nbofiles=count($listoffiles); + if (! empty($conf->global->RECEPTION_ADDON_PDF_ODT_PATH)) + { + $texte.=$langs->trans("NumberOfModelFilesFound").': '; + //$texte.=$nbofiles?'':''; + $texte.=count($listoffiles); + //$texte.=$nbofiles?'':''; + $texte.=''; + } + if ($nbofiles) + { + $texte.='
'; + $texte.= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte.= '
'; + $texte.= '
'; + + return $texte; + } + + /** + * Function to build a document on disk using the generic odt module. + * + * @param Reception $object Object source to build document + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1 if OK, <=0 if KO + */ + function write_file($object,$outputlangs,$srctemplatepath,$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$hookmanager; + + if (empty($srctemplatepath)) + { + dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); + return -1; + } + + // Add odtgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('odtgeneration')); + global $action; + + if (! is_object($outputlangs)) $outputlangs=$langs; + $sav_charset_output=$outputlangs->charset_output; + $outputlangs->charset_output='UTF-8'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + + if ($conf->reception->dir_output."/reception") + { + // If $object is id instead of object + if (! is_object($object)) + { + $id = $object; + $object = new Reception($this->db); + $result=$object->fetch($id); + if ($result < 0) + { + dol_print_error($this->db,$object->error); + return -1; + } + } + + $dir = $conf->reception->dir_output."/reception"; + $objectref = dol_sanitizeFileName($object->ref); + if (! preg_match('/specimen/i',$objectref)) $dir.= "/" . $objectref; + $file = $dir . "/" . $objectref . ".odt"; + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + if (file_exists($dir)) + { + //print "srctemplatepath=".$srctemplatepath; // Src filename + $newfile=basename($srctemplatepath); + $newfiletmp=preg_replace('/\.od(t|s)/i','',$newfile); + $newfiletmp=preg_replace('/template_/i','',$newfiletmp); + $newfiletmp=preg_replace('/modele_/i','',$newfiletmp); + $newfiletmp=$objectref.'_'.$newfiletmp; + //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + // Get extension (ods or odt) + $newfileformat=substr($newfile, strrpos($newfile, '.')+1); + if ( ! empty($conf->global->MAIN_DOC_USE_TIMING)) + { + $format=$conf->global->MAIN_DOC_USE_TIMING; + if ($format == '1') $format='%Y%m%d%H%M%S'; + $filename=$newfiletmp.'-'.dol_print_date(dol_now(),$format).'.'.$newfileformat; + } + else + { + $filename=$newfiletmp.'.'.$newfileformat; + } + $file=$dir.'/'.$filename; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->societe->dir_temp=".$conf->societe->dir_temp; + + dol_mkdir($conf->reception->dir_temp); + + + // If BILLING contact defined on invoice, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','BILLING'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + // Recipient name + if (! empty($usecontact)) + { + // On peut utiliser le nom de la societe du contact + if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact; + else $socobject = $object->thirdparty; + } + else + { + $socobject=$object->thirdparty; + } + + // Make substitution + $substitutionarray=array( + '__FROM_NAME__' => $this->emetteur->name, + '__FROM_EMAIL__' => $this->emetteur->email, + '__TOTAL_TTC__' => $object->total_ttc, + '__TOTAL_HT__' => $object->total_ht, + '__TOTAL_VAT__' => $object->total_vat + ); + complete_substitutions_array($substitutionarray, $langs, $object); + // Call the ODTSubstitution hook + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$substitutionarray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Line of free text + $newfreetext=''; + $paramfreetext='RECEPTION_FREE_TEXT'; + if (! empty($conf->global->$paramfreetext)) + { + $newfreetext=make_substitutions($conf->global->$paramfreetext,$substitutionarray); + } + + // Open and load template + require_once ODTPHP_PATH.'odf.php'; + try { + $odfHandler = new odf( + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->reception->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' + ) + ); + } + catch(Exception $e) + { + $this->error=$e->getMessage(); + return -1; + } + // After construction $odfHandler->contentXml contains content and + // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by + // [!-- BEGIN lines --]*[!-- END lines --] + //print html_entity_decode($odfHandler->__toString()); + //print exit; + + + // Make substitutions into odt of freetext + try { + $odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + + // Make substitutions into odt of user info + $tmparray=$this->get_substitutionarray_user($user,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of mysoc + $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of thirdparty + $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Replace tags of object + external modules + $tmparray=$this->get_substitutionarray_reception($object,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object); + // Call the ODTSubstitution hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Replace tags of lines + try + { + $listlines = $odfHandler->setSegment('lines'); + foreach ($object->lines as $line) + { + $tmparray=$this->get_substitutionarray_reception_lines($line,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); + // Call the ODTSubstitutionLine hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray,'line'=>$line); + $reshook=$hookmanager->executeHooks('ODTSubstitutionLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Replace labels translated + $tmparray=$outputlangs->get_translations_for_substitutions(); + foreach($tmparray as $key=>$value) + { + try { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + } + + // Call the beforeODTSave hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $reshook=$hookmanager->executeHooks('beforeODTSave',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Write new file + if (!empty($conf->global->MAIN_ODT_AS_PDF)) { + try { + $odfHandler->exportAsAttachedPDF($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + else { + try { + $odfHandler->saveToDisk($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $reshook=$hookmanager->executeHooks('afterODTCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $odfHandler=null; // Destroy object + + return 1; // Success + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + return -1; + } + +} + diff --git a/htdocs/core/modules/reception/doc/index.html b/htdocs/core/modules/reception/doc/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/core/modules/reception/doc/pdf_squille.modules.php b/htdocs/core/modules/reception/doc/pdf_squille.modules.php new file mode 100644 index 00000000000..0f1add63c44 --- /dev/null +++ b/htdocs/core/modules/reception/doc/pdf_squille.modules.php @@ -0,0 +1,1031 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/doc/pdf_squille.modules.php + * \ingroup reception + * \brief Fichier de la classe permettant de generer les bordereaux envoi au modele Squille + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Classe permettant de generer les borderaux envoi au modele Squille + */ +class pdf_squille extends ModelePdfReception +{ + var $emetteur; // Objet societe qui emet + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db=0) + { + global $conf,$langs,$mysoc; + + $this->db = $db; + $this->name = "squille"; + $this->description = $langs->trans("DocumentModelStandardPDF"); + + $this->type = 'pdf'; + $formatarray=pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10; + $this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10; + $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; + $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; + + $this->option_logo = 1; + + // Get source company + $this->emetteur=$mysoc; + if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default if not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; + $this->posxweightvol=$this->page_largeur - $this->marge_droite - 78; + $this->posxqtyordered=$this->page_largeur - $this->marge_droite - 56; + $this->posxqtytoship=$this->page_largeur - $this->marge_droite - 28; + $this->posxpuht=$this->page_largeur - $this->marge_droite; + + if (!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $this->posxweightvol=$this->page_largeur - $this->marge_droite - 118; + $this->posxqtyordered=$this->page_largeur - $this->marge_droite - 96; + $this->posxqtytoship=$this->page_largeur - $this->marge_droite - 68; + $this->posxpuht=$this->page_largeur - $this->marge_droite - 40; + $this->posxtotalht=$this->page_largeur - $this->marge_droite - 20; + } + + $this->posxpicture=$this->posxweightvol - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images + + if ($this->page_largeur < 210) // To work with US executive format + { + $this->posxweightvol-=20; + $this->posxpicture-=20; + $this->posxqtyordered-=20; + $this->posxqtytoship-=20; + } + + if (! empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $this->posxweightvol += ($this->posxqtytoship - $this->posxqtyordered); + $this->posxpicture += ($this->posxqtytoship - $this->posxqtyordered); + $this->posxqtyordered = $this->posxqtytoship; + } + } + + /** + * Function to build pdf onto disk + * + * @param Object $object Object reception to generate (or id if old method) + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$conf,$langs,$hookmanager; + + $object->fetch_thirdparty(); + + if (! is_object($outputlangs)) $outputlangs=$langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + $outputlangs->load("products"); + $outputlangs->load("propal"); + $outputlangs->load("deliveries"); + $outputlangs->load("sendings"); + $outputlangs->load("productbatch"); + + $nblignes = count($object->lines); + + // Loop on each lines to detect if there is at least one image to show + $realpatharray=array(); + if (! empty($conf->global->MAIN_GENERATE_SHIPMENT_WITH_PICTURE)) + { + $objphoto = new Product($this->db); + + for ($i = 0 ; $i < $nblignes ; $i++) + { + if (empty($object->lines[$i]->fk_product)) continue; + + $objphoto = new Product($this->db); + $objphoto->fetch($object->lines[$i]->fk_product); + + $pdir = get_exdir($object->lines[$i]->fk_product,2,0,0,$objphoto,'product') . $object->lines[$i]->fk_product ."/photos/"; + $dir = $conf->product->dir_output.'/'.$pdir; + + $realpath=''; + + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo + { + if ($obj['photo_vignette']) + { + $filename= $obj['photo_vignette']; + } + else + { + $filename=$obj['photo']; + } + } + else + { + $filename=$obj['photo']; + } + + $realpath = $dir.$filename; + break; + } + + if ($realpath) $realpatharray[$i]=$realpath; + } + } + + if (count($realpatharray) == 0) $this->posxpicture=$this->posxweightvol; + + if ($conf->reception->dir_output) + { + // Definition de $dir et $file + if ($object->specimen) + { + $dir = $conf->reception->dir_output."/sending"; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $expref = dol_sanitizeFileName($object->ref); + $dir = $conf->reception->dir_output."/sending/" . $expref; + $file = $dir . "/" . $expref . ".pdf"; + } + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + + // Set nblignes with the new facture lines content after hook + $nblignes = count($object->lines); + + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); + $heightforinfotot = 8; // Height reserved to output the info and total part + $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin) + $pdf->SetAutoPageBreak(1,0); + + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + // Set path to the background PDF File + if (empty($conf->global->MAIN_DISABLE_FPDI) && ! empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb=0; + $pdf->SetDrawColor(128,128,128); + + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("Reception")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Reception")); + if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + $this->_pagehead($pdf, $object, 1, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0,0,0); + + $tab_top = 90; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42:10); + $tab_height = 130; + $tab_height_newpage = 150; + + // Incoterm + $height_incoterms = 0; + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top = 88; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = $pdf->GetY(); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + $height_incoterms += 4; + } + } + + if (! empty($object->note_public) || ! empty($object->tracking_number)) + { + $tab_top = 88 + $height_incoterms; + $tab_top_alt = $tab_top; + + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->writeHTMLCell(60, 4, $this->posxdesc-1, $tab_top-1, $outputlangs->transnoentities("TrackingNumber")." : " . $object->tracking_number, 0, 1, false, true, 'L'); + + $tab_top_alt = $pdf->GetY(); + //$tab_top_alt += 1; + + // Tracking number + if (! empty($object->tracking_number)) + { + $object->GetUrlTrackingStatus($object->tracking_number); + if (! empty($object->tracking_url)) + { + if ($object->reception_method_id > 0) + { + // Get code using getLabelFromKey + $code=$outputlangs->getLabelFromKey($this->db,$object->reception_method_id,'c_shipment_mode','rowid','code'); + $label=''; + if ($object->tracking_url != $object->tracking_number) $label.=$outputlangs->trans("LinkToTrackYourPackage")."
"; + $label.=$outputlangs->trans("SendingMethod").": ".$outputlangs->trans("SendingMethod".strtoupper($code)); + //var_dump($object->tracking_url != $object->tracking_number);exit; + if ($object->tracking_url != $object->tracking_number) + { + $label.=" : "; + $label.=$object->tracking_url; + } + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->writeHTMLCell(60, 4, $this->posxdesc-1, $tab_top_alt, $label, 0, 1, false, true, 'L'); + + $tab_top_alt = $pdf->GetY(); + } + } + } + + // Notes + if (! empty($object->note_public)) + { + $pdf->SetFont('','', $default_font_size - 1); // Dans boucle pour gerer multi-page + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top_alt, dol_htmlentitiesbr($object->note_public), 0, 1); + } + + $nexY = $pdf->GetY(); + $height_note=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_note+1); + + $tab_height = $tab_height - $height_note; + $tab_top = $nexY+6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 7; + $curY = $tab_top + 7; + $nexY = $tab_top + 7; + + // Loop on each lines + for ($i = 0; $i < $nblignes; $i++) + { + $curY = $nexY; + $pdf->SetFont('','', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0,0,0); + + // Define size of image if we need it + $imglinesize=array(); + if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]); + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore=$pdf->getPage(); + + $showpricebeforepagebreak=1; + $posYAfterImage=0; + $posYAfterDescription=0; + + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot))) // If photo too high, we moved completely on new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposbefore+1); + + $curY = $tab_top_newpage; + $showpricebeforepagebreak=0; + } + + if (isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $curX = $this->posxpicture-1; + $pdf->Image($realpatharray[$i], $curX + (($this->posxweightvol-$this->posxpicture-$imglinesize['width'])/2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage=$curY+$imglinesize['height']; + } + + // Description of product line + $curX = $this->posxdesc-1; + + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxpicture-$curX,3,$curX,$curY,$hideref,$hidedesc); + + $pageposafter=$pdf->getPage(); + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pageposafter=$pageposbefore; + //print $pageposafter.'-'.$pageposbefore;exit; + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxpicture-$curX,3,$curX,$curY,$hideref,$hidedesc); + + $pageposafter=$pdf->getPage(); + $posyafter=$pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblignes-1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposafter+1); + } + } + else + { + // We found a page break + $showpricebeforepagebreak=0; + } + } + else // No pagebreak + { + $pdf->commitTransaction(); + } + $posYAfterDescription=$pdf->GetY(); + + $nexY = $pdf->GetY(); + $pageposafter=$pdf->getPage(); + + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + // We suppose that a too long description is moved completely on next page + if ($pageposafter > $pageposbefore) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + $pdf->SetXY($this->posxweightvol, $curY); + $weighttxt=''; + if ($object->lines[$i]->fk_product_type == 0 && $object->lines[$i]->weight) + { + $weighttxt=round($object->lines[$i]->weight * $object->lines[$i]->qty_shipped, 5).' '.measuring_units_string($object->lines[$i]->weight_units,"weight"); + } + $voltxt=''; + if ($object->lines[$i]->fk_product_type == 0 && $object->lines[$i]->volume) + { + $voltxt=round($object->lines[$i]->volume * $object->lines[$i]->qty_shipped, 5).' '.measuring_units_string($object->lines[$i]->volume_units?$object->lines[$i]->volume_units:0,"volume"); + } + + $pdf->writeHTMLCell($this->posxqtyordered - $this->posxweightvol + 2, 3, $this->posxweightvol - 1, $curY, $weighttxt.(($weighttxt && $voltxt)?'
':'').$voltxt, 0, 0, false, true, 'C'); + //$pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), 3, $weighttxt.(($weighttxt && $voltxt)?'
':'').$voltxt,'','C'); + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->SetXY($this->posxqtyordered, $curY); + $pdf->MultiCell(($this->posxqtytoship - $this->posxqtyordered), 3, $object->lines[$i]->qty_asked,'','C'); + } + + $pdf->SetXY($this->posxqtytoship, $curY); + $pdf->MultiCell(($this->posxpuht - $this->posxqtytoship), 3, $object->lines[$i]->qty_shipped,'','C'); + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) + { + $pdf->SetXY($this->posxpuht, $curY); + $pdf->MultiCell(($this->posxtotalht - $this->posxpuht-1), 3, price($object->lines[$i]->subprice, 0, $outputlangs),'','R'); + + $pdf->SetXY($this->posxtotalht, $curY); + $pdf->MultiCell(($this->page_largeur - $this->marge_droite - $this->posxtotalht), 3, price($object->lines[$i]->total_ht, 0, $outputlangs),'','R'); + } + + $nexY+=3; + if ($weighttxt && $voltxt) $nexY+=2; + + // Add line + if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) + { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY-1, $this->page_largeur - $this->marge_droite, $nexY-1); + $pdf->SetLineStyle(array('dash'=>0)); + } + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) + { + $pdf->setPage($pagenb); + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + } + if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak) + { + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + } + } + + // Show square + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs); + + // Pied de page + $this->_pagefoot($pdf,$object,$outputlangs); + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->Close(); + + $pdf->Output($file,'F'); + + // Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + return 1; // No error + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->transnoentities("ErrorConstantNotDefined","EXP_OUTPUTDIR"); + return 0; + } + } + + /** + * Show total to pay + * + * @param PDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Montant deja regle + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + global $conf,$mysoc; + + $sign=1; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','B', $default_font_size - 1); + + // Tableau total + $col1x = $this->posxweightvol-50; $col2x = $this->posxweightvol; + /*if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + }*/ + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) $largcol2 = ($this->posxqtyordered - $this->posxweightvol); + else $largcol2 = ($this->posxqtytoship - $this->posxweightvol); + + $useborder=0; + $index = 0; + + $totalWeighttoshow=''; + $totalVolumetoshow=''; + + // Load dim data + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + $totalOrdered=$tmparray['ordered']; + $totalToShip=$tmparray['toship']; + // Set trueVolume and volume_units not currently stored into database + if ($object->trueWidth && $object->trueHeight && $object->trueDepth) + { + $object->trueVolume=price(($object->trueWidth * $object->trueHeight * $object->trueDepth), 0, $outputlangs, 0, 0); + $object->volume_units=$object->size_units * 3; + } + + if ($totalWeight!='') $totalWeighttoshow=showDimensionInBestUnit($totalWeight, 0, "weight", $outputlangs); + if ($totalVolume!='') $totalVolumetoshow=showDimensionInBestUnit($totalVolume, 0, "volume", $outputlangs); + if ($object->trueWeight) $totalWeighttoshow=showDimensionInBestUnit($object->trueWeight, $object->weight_units, "weight", $outputlangs); + if ($object->trueVolume) $totalVolumetoshow=showDimensionInBestUnit($object->trueVolume, $object->volume_units, "volume", $outputlangs); + + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("Total"), 0, 'L', 1); + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->SetXY($this->posxqtyordered, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxqtytoship - $this->posxqtyordered, $tab2_hl, $totalOrdered, 0, 'C', 1); + } + + $pdf->SetXY($this->posxqtytoship, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxpuht - $this->posxqtytoship, $tab2_hl, $totalToShip, 0, 'C', 1); + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $pdf->SetXY($this->posxpuht, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxtotalht - $this->posxpuht, $tab2_hl, '', 0, 'C', 1); + + $pdf->SetXY($this->posxtotalht, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->posxtotalht, $tab2_hl, price($object->total_ht, 0, $outputlangs), 0, 'C', 1); + + } + + // Total Weight + if ($totalWeighttoshow) + { + $pdf->SetXY($this->posxweightvol, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), $tab2_hl, $totalWeighttoshow, 0, 'C', 1); + + $index++; + } + if ($totalVolumetoshow) + { + $pdf->SetXY($this->posxweightvol, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), $tab2_hl, $totalVolumetoshow, 0, 'C', 1); + + $index++; + } + if (! $totalWeighttoshow && ! $totalVolumetoshow) $index++; + + $pdf->SetTextColor(0,0,0); + + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * Show table for lines + * + * @param PDF $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y + * @param Translate $outputlangs Langs object + * @param int $hidetop Hide top bar of array + * @param int $hidebottom Hide bottom bar of array + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0) + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','',$default_font_size - 2); + + // Output Rect + $this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect prend une longueur en 3eme param et 4eme param + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','', $default_font_size - 1); + + if (empty($hidetop)) + { + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); + + $pdf->SetXY($this->posxdesc-1, $tab_top+1); + $pdf->MultiCell($this->posxqtyordered - $this->posxdesc, 2, $outputlangs->transnoentities("Description"), '', 'L'); + } + + $pdf->line($this->posxweightvol-1, $tab_top, $this->posxweightvol-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxweightvol-1, $tab_top+1); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), 2, $outputlangs->transnoentities("WeightVolShort"),'','C'); + } + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->line($this->posxqtyordered-1, $tab_top, $this->posxqtyordered-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxqtyordered-1, $tab_top+1); + $pdf->MultiCell(($this->posxqtytoship - $this->posxqtyordered), 2, $outputlangs->transnoentities("QtyOrdered"),'','C'); + } + } + + $pdf->line($this->posxqtytoship-1, $tab_top, $this->posxqtytoship-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxqtytoship, $tab_top+1); + $pdf->MultiCell(($this->posxpuht - $this->posxqtytoship), 2, $outputlangs->transnoentities("QtyToShip"),'','C'); + } + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $pdf->line($this->posxpuht-1, $tab_top, $this->posxpuht-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxpuht-1, $tab_top+1); + $pdf->MultiCell(($this->posxtotalht - $this->posxpuht), 2, $outputlangs->transnoentities("PriceUHT"),'','C'); + } + + $pdf->line($this->posxtotalht-1, $tab_top, $this->posxtotalht-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxtotalht-1, $tab_top+1); + $pdf->MultiCell(($this->page_largeur - $this->marge_droite - $this->posxtotalht), 2, $outputlangs->transnoentities("TotalHT"),'','C'); + } + + } + + } + + /** + * Show top header of page. + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @return void + */ + function _pagehead(&$pdf, $object, $showaddress, $outputlangs) + { + global $conf,$langs,$mysoc; + + $langs->load("orders"); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==0 && (! empty($conf->global->RECEPTION_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->RECEPTION_DRAFT_WATERMARK); + } + + //Prepare la suite + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $w = 110; + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-$w; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $height=pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + // Show barcode + if (! empty($conf->barcode->enabled)) + { + $posx=105; + } + else + { + $posx=$this->marge_gauche+3; + } + //$pdf->Rect($this->marge_gauche, $this->marge_haute, $this->page_largeur-$this->marge_gauche-$this->marge_droite, 30); + if (! empty($conf->barcode->enabled)) + { + // TODO Build code bar with function writeBarCode of barcode module for sending ref $object->ref + //$pdf->SetXY($this->marge_gauche+3, $this->marge_haute+3); + //$pdf->Image($logo,10, 5, 0, 24); + } + + $pdf->SetDrawColor(128,128,128); + if (! empty($conf->barcode->enabled)) + { + // TODO Build code bar with function writeBarCode of barcode module for sending ref $object->ref + //$pdf->SetXY($this->marge_gauche+3, $this->marge_haute+3); + //$pdf->Image($logo,10, 5, 0, 24); + } + + + $posx=$this->page_largeur - $w - $this->marge_droite; + $posy=$this->marge_haute; + + $pdf->SetFont('','B', $default_font_size + 2); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("SendingSheet"); + $pdf->MultiCell($w, 4, $title, '', 'R'); + + $pdf->SetFont('','', $default_font_size + 1); + + $posy+=5; + + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 4, $outputlangs->transnoentities("RefSending") ." : ".$object->ref, '', 'R'); + + // Date planned delivery + if (! empty($object->date_delivery)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 4, $outputlangs->transnoentities("DateDeliveryPlanned")." : ".dol_print_date($object->date_delivery,"day",false,$outputlangs,true), '', 'R'); + } + + if (! empty($object->thirdparty->code_client)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + } + + + $pdf->SetFont('','', $default_font_size + 3); + $Yoff=25; + + // Add list of linked orders + $origin = $object->origin; + $origin_id = $object->origin_id; + + // TODO move to external function + if (! empty($conf->$origin->enabled)) // commonly $origin='commande' + { + $outputlangs->load('orders'); + + $classname = ucfirst($origin); + $linkedobject = new $classname($this->db); + $result=$linkedobject->fetch($origin_id); + if ($result >= 0) + { + //$linkedobject->fetchObjectLinked() Get all linked object to the $linkedobject (commonly order) into $linkedobject->linkedObjects + + $pdf->SetFont('','', $default_font_size - 2); + $text=$linkedobject->ref; + if ($linkedobject->ref_client) $text.=' ('.$linkedobject->ref_client.')'; + $Yoff = $Yoff+8; + $pdf->SetXY($this->page_largeur - $this->marge_droite - $w,$Yoff); + $pdf->MultiCell($w, 2, $outputlangs->transnoentities("RefOrder") ." : ".$outputlangs->transnoentities($text), 0, 'R'); + $Yoff = $Yoff+3; + $pdf->SetXY($this->page_largeur - $this->marge_droite - $w,$Yoff); + $pdf->MultiCell($w, 2, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($linkedobject->date,"day",false,$outputlangs,true), 0, 'R'); + } + } + + if ($showaddress) + { + // Sender properties + $carac_emetteur=''; + // Add internal contact of origin element if defined + $arrayidcontact=array(); + if (! empty($origin) && is_object($object->$origin)) $arrayidcontact=$object->$origin->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $object->fetch_user(reset($arrayidcontact)); + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Name").": ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n"; + } + + $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty); + + // Show sender + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + + $hautcadre=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40; + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82; + + // Show sender frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("Sender").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(255,255,255); + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B',$default_font_size); + $pdf->MultiCell($widthrecbox-2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy=$pdf->getY(); + + // Show sender information + $pdf->SetXY($posx+2,$posy); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell($widthrecbox-2, 4, $carac_emetteur, 0, 'L'); + + + // If RECEPTION contact defined, we use it + $usecontact=false; + $arrayidcontact=$object->$origin->getIdContact('external','RECEPTION'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,(!empty($object->contact)?$object->contact:null),$usecontact,'targetwithdetails',$object); + + // Show recipient + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posx=$this->page_largeur - $this->marge_droite - $widthrecbox; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche; + + // Show recipient frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx+2,$posy-5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("Recipient").":", 0, 'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0,0,0); + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param PDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'RECEPTION_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + +} + diff --git a/htdocs/core/modules/reception/index.html b/htdocs/core/modules/reception/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/core/modules/reception/mod_reception_beryl.php b/htdocs/core/modules/reception/mod_reception_beryl.php new file mode 100644 index 00000000000..2b17d5ee0f0 --- /dev/null +++ b/htdocs/core/modules/reception/mod_reception_beryl.php @@ -0,0 +1,145 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/mod_reception_beryl.php + * \ingroup reception + * \brief File of class to manage shipments numbering rules Beryl + */ +require_once DOL_DOCUMENT_ROOT .'/core/modules/reception/modules_reception.php'; + +/** + * Class to manage reception numbering rules Beryl + */ +class mod_reception_beryl extends ModelNumRefReception +{ + var $version='dolibarr'; + var $prefix='RCP'; + var $error=''; + var $nom='Beryl'; + + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc",$this->prefix); + } + + + /** + * Return numbering example + * + * @return string Example + */ + function getExample() + { + return $this->prefix."0501-0001"; + } + + + /** + * Test if existing numbers make problems with numbering + * + * @return boolean false if conflit, true if ok + */ + function canBeActivated() + { + global $conf,$langs,$db; + + $coyymm=''; $max=''; + + $posindice=8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql.= " FROM ".MAIN_DB_PREFIX."reception"; + $sql.= " WHERE ref LIKE '".$this->prefix."____-%'"; + $sql.= " AND entity = ".$conf->entity; + + $resql=$db->query($sql); + if ($resql) + { + $row = $db->fetch_row($resql); + if ($row) { $coyymm = substr($row[0],0,6); $max=$row[0]; } + } + if ($coyymm && ! preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i',$coyymm)) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorNumRefModel', $max); + return false; + } + + return true; + } + + /** + * Return next value + * + * @param Societe $objsoc Third party object + * @param Object $shipment Shipment object + * @return string Value if OK, 0 if KO + */ + function getNextValue($objsoc,$shipment) + { + global $db,$conf; + + $posindice=8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql.= " FROM ".MAIN_DB_PREFIX."reception"; + $sql.= " WHERE ref like '".$this->prefix."____-%'"; + $sql.= " AND entity = ".$conf->entity; + + $resql=$db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + if ($obj) $max = intval($obj->max); + else $max=0; + } + else + { + dol_syslog("mod_reception_beryl::getNextValue", LOG_DEBUG); + return -1; + } + + $date=time(); + $yymm = strftime("%y%m",$date); + + if ($max >= (pow(10, 4) - 1)) $num=$max+1; // If counter > 9999, we do not format on 4 chars, we take number as it is + else $num = sprintf("%04s",$max+1); + + dol_syslog("mod_reception_beryl::getNextValue return ".$this->prefix.$yymm."-".$num); + return $this->prefix.$yymm."-".$num; + } + + /** + * Return next free value + * + * @param Societe $objsoc Third party object + * @param Object $objforref Shipment object + * @return string Next free value + */ + function reception_get_num($objsoc,$objforref) + { + return $this->getNextValue($objsoc,$objforref); + } + +} diff --git a/htdocs/core/modules/reception/mod_reception_moonstone.php b/htdocs/core/modules/reception/mod_reception_moonstone.php new file mode 100644 index 00000000000..0c661e12cbe --- /dev/null +++ b/htdocs/core/modules/reception/mod_reception_moonstone.php @@ -0,0 +1,137 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/mod_reception_moonstone.php + * \ingroup reception + * \brief File of class to manage reception numbering rules Moonstone + */ + +require_once DOL_DOCUMENT_ROOT .'/core/modules/reception/modules_reception.php'; + +/** + * Class to manage reception numbering rules Moonstone + */ +class mod_reception_moonstone extends ModelNumRefReception +{ + var $version='dolibarr'; + var $error = ''; + var $nom = 'Moonstone'; + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $conf,$langs; + + $langs->load("bills"); + + $form = new Form($this->db); + + $texte = $langs->trans('GenericNumRefModelDesc')."
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + $tooltip=$langs->trans("GenericMaskCodes",$langs->transnoentities("Reception"),$langs->transnoentities("Reception")); + $tooltip.=$langs->trans("GenericMaskCodes2"); + $tooltip.=$langs->trans("GenericMaskCodes3"); + $tooltip.=$langs->trans("GenericMaskCodes4a",$langs->transnoentities("Reception"),$langs->transnoentities("Reception")); + $tooltip.=$langs->trans("GenericMaskCodes5"); + + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '
'.$langs->trans("Mask").':'.$form->textwithpicto('',$tooltip,1,1).' 
'; + $texte.= '
'; + + return $texte; + } + + /** + * Return numbering example + * + * @return string Example + */ + function getExample() + { + global $conf,$langs,$mysoc; + + $old_code_client=$mysoc->code_client; + $old_code_type=$mysoc->typent_code; + $mysoc->code_client='CCCCCCCCCC'; + $mysoc->typent_code='TTTTTTTTTT'; + $numExample = $this->getNextValue($mysoc,''); + $mysoc->code_client=$old_code_client; + $mysoc->typent_code=$old_code_type; + + if (! $numExample) + { + $numExample = $langs->trans('NotConfigured'); + } + return $numExample; + } + + /** + * Return next value + * + * @param Societe $objsoc Third party object + * @param Object $reception Reception object + * @return string Value if OK, 0 if KO + */ + function getNextValue($objsoc,$reception) + { + global $db,$conf; + + require_once DOL_DOCUMENT_ROOT .'/core/lib/functions2.lib.php'; + + $mask=$conf->global->RECEPTION_MOONSTONE_MASK; + + if (! $mask) + { + $this->error='NotConfigured'; + return 0; + } + + $date = $reception->date_reception; + + $numFinal=get_next_value($db,$mask,'reception','ref','',$objsoc,$date); + + return $numFinal; + } + + /** + * Return next free value + * + * @param Societe $objsoc Third party object + * @param Object $objforref Reception object + * @return string Next free value + */ + function reception_get_num($objsoc,$objforref) + { + return $this->getNextValue($objsoc,$objforref); + } + +} + diff --git a/htdocs/core/modules/reception/modules_reception.php b/htdocs/core/modules/reception/modules_reception.php new file mode 100644 index 00000000000..609e5e315ad --- /dev/null +++ b/htdocs/core/modules/reception/modules_reception.php @@ -0,0 +1,136 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/modules_reception.php + * \ingroup reception + * \brief File that contains parent class for sending receipts models + * and parent class for sending receipts numbering models + */ + require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php'; + +/** + * Parent class of sending receipts models + */ +abstract class ModelePdfReception extends CommonDocGenerator +{ + var $error=''; + + + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param integer $maxfilenamelength Max length of value to show + * @return array List of templates + */ + static function liste_modeles($db,$maxfilenamelength=0) + { + global $conf; + + $type='reception'; + $liste=array(); + + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $liste=getListOfModels($db,$type,$maxfilenamelength); + + return $liste; + } +} + + +/** + * Parent Class of numbering models of sending receipts references + */ +abstract class ModelNumRefReception +{ + var $error=''; + + /** Return if a model can be used or not + * + * @return boolean true if model can be used + */ + function isEnabled() + { + return true; + } + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $langs; + $langs->load("reception"); + return $langs->trans("NoDescription"); + } + + /** + * Returns numbering example + * + * @return string Example + */ + function getExample() + { + global $langs; + $langs->load("reception"); + return $langs->trans("NoExample"); + } + + /** + * Test if existing numbers make problems with numbering + * + * @return boolean false if conflit, true if ok + */ + function canBeActivated() + { + return true; + } + + /** + * Returns next value assigned + * + * @param Societe $objsoc Third party object + * @param Object $shipment Shipment object + * @return string Value + */ + function getNextValue($objsoc, $shipment) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Returns version of the numbering model + * + * @return string Value + */ + function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') return $langs->trans("VersionDevelopment"); + if ($this->version == 'experimental') return $langs->trans("VersionExperimental"); + if ($this->version == 'dolibarr') return DOL_VERSION; + if ($this->version) return $this->version; + return $langs->trans("NotAvailable"); + } +} diff --git a/htdocs/install/mysql/tables/llx_reception.key.sql b/htdocs/install/mysql/tables/llx_reception.key.sql new file mode 100644 index 00000000000..736945193ff --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception.key.sql @@ -0,0 +1,31 @@ +-- =================================================================== +-- Copyright (C) 2005 Laurent Destailleur +-- Copyright (C) 2008-2010 Regis Houssin +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_expedition ADD UNIQUE INDEX idx_expedition_uk_ref (ref, entity); + +ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_soc (fk_soc); +ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_user_author (fk_user_author); +ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_user_valid (fk_user_valid); +ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_shipping_method (fk_shipping_method); + +ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); +ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_user_valid FOREIGN KEY (fk_user_valid) REFERENCES llx_user (rowid); +ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_shipping_method FOREIGN KEY (fk_shipping_method) REFERENCES llx_c_shipment_mode (rowid); diff --git a/htdocs/install/mysql/tables/llx_reception.sql b/htdocs/install/mysql/tables/llx_reception.sql new file mode 100644 index 00000000000..088e4893c06 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception.sql @@ -0,0 +1,62 @@ +-- =================================================================== +-- Copyright (C) 2003-2010 Rodolphe Quiedeville +-- Copyright (C) 2008-2010 Regis Houssin +-- Copyright (C) 2011-2012 Laurent Destailleur +-- Copyright (C) 2012 Juanjo Menent +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + +create table llx_expedition +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + ref varchar(30) NOT NULL, + entity integer DEFAULT 1 NOT NULL, -- multi company id + fk_soc integer NOT NULL, + fk_projet integer DEFAULT NULL, + + ref_ext varchar(30), -- reference into an external system (not used by dolibarr) + ref_int varchar(30), -- reference into an internal system (used by dolibarr to store extern id like paypal info) + ref_customer varchar(30), -- customer number + + date_creation datetime, -- date de creation + fk_user_author integer, -- author of creation + fk_user_modif integer, -- author of last change + date_valid datetime, -- date de validation + fk_user_valid integer, -- valideur + date_delivery datetime DEFAULT NULL, -- date planned of delivery + date_expedition datetime, -- not used (deprecated) + fk_address integer DEFAULT NULL, -- delivery address (deprecated) + fk_shipping_method integer, + tracking_number varchar(50), + fk_statut smallint DEFAULT 0, -- 0 = draft, 1 = validated, 2 = billed or closed depending on WORKFLOW_BILL_ON_SHIPMENT option + billed smallint DEFAULT 0, + + height float, -- height + width float, -- with + size_units integer, -- unit of all sizes (height, width, depth) + size float, -- depth + weight_units integer, -- unit of weight + weight float, -- weight + note_private text, + note_public text, + model_pdf varchar(255), + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms + + import_key varchar(14), + extraparams varchar(255) -- for other parameters with json format +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql new file mode 100644 index 00000000000..b539f460a08 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_expedition_extrafields ADD INDEX idx_expedition_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.sql new file mode 100644 index 00000000000..eff8465fbf6 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.sql @@ -0,0 +1,26 @@ +-- ======================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- ======================================================================== + +create table llx_expedition_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + diff --git a/htdocs/install/mysql/tables/llx_receptiondet.key.sql b/htdocs/install/mysql/tables/llx_receptiondet.key.sql new file mode 100644 index 00000000000..5f5b6a08183 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet.key.sql @@ -0,0 +1,22 @@ +-- =================================================================== +-- Copyright (C) 2005 Laurent Destailleur +-- Copyright (C) 2008 Regis Houssin +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_expeditiondet ADD INDEX idx_expeditiondet_fk_expedition (fk_expedition); +ALTER TABLE llx_expeditiondet ADD CONSTRAINT fk_expeditiondet_fk_expedition FOREIGN KEY (fk_expedition) REFERENCES llx_expedition (rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet.sql b/htdocs/install/mysql/tables/llx_receptiondet.sql new file mode 100644 index 00000000000..bd05bd08898 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet.sql @@ -0,0 +1,29 @@ +-- =================================================================== +-- Copyright (C) 2003 Rodolphe Quiedeville +-- Copyright (C) 2008 Regis Houssin +-- Copyright (C) 2011 Laurent Destailleur +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + +create table llx_expeditiondet +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_expedition integer NOT NULL, + fk_origin_line integer, -- Correspondance de la ligne avec le document d'origine (propal, commande) + fk_entrepot integer, -- Entrepot de depart du produit + qty real, -- Quantity + rang integer DEFAULT 0 +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql new file mode 100644 index 00000000000..70bfe974f34 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql @@ -0,0 +1,20 @@ +-- ============================================================================ +-- Copyright (C) 2014 Cédric GROSS +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- ============================================================================ + +ALTER TABLE llx_expeditiondet_batch ADD INDEX idx_fk_expeditiondet (fk_expeditiondet); +ALTER TABLE llx_expeditiondet_batch ADD CONSTRAINT fk_expeditiondet_batch_fk_expeditiondet FOREIGN KEY (fk_expeditiondet) REFERENCES llx_expeditiondet(rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql new file mode 100644 index 00000000000..2a1234d9342 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql @@ -0,0 +1,27 @@ +-- ============================================================================ +-- Copyright (C) 2014 Cédric GROSS +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- ============================================================================ +CREATE TABLE llx_expeditiondet_batch ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + fk_expeditiondet int NOT NULL, + eatby date DEFAULT NULL, + sellby date DEFAULT NULL, + batch varchar(30) DEFAULT NULL, + qty double NOT NULL DEFAULT '0', + fk_origin_stock integer NOT NULL +) ENGINE=InnoDB; + diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql new file mode 100644 index 00000000000..11e133442d5 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_expeditiondet_extrafields ADD INDEX idx_expeditiondet_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql new file mode 100644 index 00000000000..e27c7f3e505 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql @@ -0,0 +1,25 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- 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 . +-- +-- =================================================================== + +create table llx_expeditiondet_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, -- object id + import_key varchar(14) -- import key +)ENGINE=innodb; diff --git a/htdocs/langs/en_US/receptions.lang b/htdocs/langs/en_US/receptions.lang new file mode 100644 index 00000000000..51e6ab06e89 --- /dev/null +++ b/htdocs/langs/en_US/receptions.lang @@ -0,0 +1,70 @@ +# Dolibarr language file - Source file is en_US - receptions +RefReception=Ref. reception +Reception=Reception +Receptions=Receptions +AllReceptions=All Receptions +Reception=Reception +Receptions=Receptions +ShowReception=Show Receptions +Receivings=Delivery Receipts +ReceptionsArea=Receptions area +ListOfReceptions=List of receptions +ReceptionMethod=Shipping method +LastReceptions=Latest %s receptions +StatisticsOfReceptions=Statistics for receptions +NbOfReceptions=Number of receptions +NumberOfReceptionsByMonth=Number of receptions by month +ReceptionCard=Reception card +NewReception=New reception +CreateReception=Create reception +QtyShipped=Qty shipped +QtyPreparedOrShipped=Qty prepared or shipped +QtyToShip=Qty to ship +QtyReceived=Qty received +QtyInOtherReceptions=Qty in other receptions +KeepToShip=Remain to ship +OtherReceptionsForSameOrder=Other receptions for this order +ReceptionsAndReceivingForSameOrder=Receptions and receipts for this order +ReceptionsToValidate=Receptions to validate +StatusReceptionCanceled=Canceled +StatusReceptionDraft=Draft +StatusReceptionValidated=Validated (products to ship or already shipped) +StatusReceptionProcessed=Processed +StatusReceptionDraftShort=Draft +StatusReceptionValidatedShort=Validated +StatusReceptionProcessedShort=Processed +ReceptionSheet=Reception sheet +ConfirmDeleteReception=Are you sure you want to delete this reception? +ConfirmValidateReception=Are you sure you want to validate this reception with reference %s? +ConfirmCancelReception=Are you sure you want to cancel this reception? +DocumentModelMerou=Merou A5 model +WarningNoQtyLeftToSend=Warning, no products waiting to be shipped. +StatsOnReceptionsOnlyValidated=Statistics conducted on receptions only validated. Date used is date of validation of reception (planed delivery date is not always known). +DateDeliveryPlanned=Planned date of delivery +RefDeliveryReceipt=Ref delivery receipt +StatusReceipt=Status delivery receipt +DateReceived=Date delivery received +SendShippingByEMail=Send reception by EMail +SendShippingRef=Submission of reception %s +ActionsOnShipping=Events on reception +LinkToTrackYourPackage=Link to track your package +ReceptionCreationIsDoneFromOrder=For the moment, creation of a new reception is done from the order card. +ReceptionLine=Reception line +ProductQtyInCustomersOrdersRunning=Product quantity into open customers orders +ProductQtyInSuppliersOrdersRunning=Product quantity into open suppliers orders +ProductQtyInReceptionAlreadySent=Product quantity from open customer order already sent +ProductQtyInSuppliersReceptionAlreadyRecevied=Product quantity from open supplier order already received +NoProductToShipFoundIntoStock=No product to ship found into warehouse %s. Correct stock or go back to choose another warehouse. +WeightVolShort=Weight/Vol. +ValidateOrderFirstBeforeReception=You must first validate the order before being able to make receptions. + +# Reception methods +# ModelDocument +DocumentModelTyphon=More complete document model for delivery receipts (logo...) +Error_EXPEDITION_ADDON_NUMBER_NotDefined=Constant EXPEDITION_ADDON_NUMBER not defined +SumOfProductVolumes=Sum of product volumes +SumOfProductWeights=Sum of product weights + +# warehouse details +DetailWarehouseNumber= Warehouse details +DetailWarehouseFormat= W:%s (Qty : %d) diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index a5338997eb2..bfe6e81858c 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -1438,6 +1438,13 @@ SendingsNumberingModules=Modèles de numérotation des expéditions SendingsAbility=Prise en charge des bons d'expédition pour les livraisons clients NoNeedForDeliveryReceipts=Dans le plupart des cas, la fiche expédition est utilisée en tant que bon d'expédition (liste des produits expédiés) et bon de livraison (signée par le client). Le bon de réception est un doublon de fonctionnalité et est rarement utilisé. FreeLegalTextOnShippings=Mention complémentaire sur les expéditions +##### Reception ##### +ReceptionsSetup=Configuration du module Réception/Livraison +ReceptionsReceiptModel=Modèles de bordereau de réception +ReceptionsNumberingModules=Modèles de numérotation des réceptions +ReceptionsAbility=Prise en charge des bons d'réception pour les livraisons clients +NoNeedForDeliveryReceipts=Dans le plupart des cas, la fiche réception est utilisée en tant que bon d'réception (liste des produits expédiés) et bon de livraison (signée par le client). Le bon de réception est un doublon de fonctionnalité et est rarement utilisé. +FreeLegalTextOnShippings=Mention complémentaire sur les réceptions ##### Deliveries ##### DeliveryOrderNumberingModules=Modèle de numérotation des bons de réception client DeliveryOrderModel=Modèle de bon de réception client diff --git a/htdocs/langs/fr_FR/receptions.lang b/htdocs/langs/fr_FR/receptions.lang new file mode 100644 index 00000000000..7522dc6eb51 --- /dev/null +++ b/htdocs/langs/fr_FR/receptions.lang @@ -0,0 +1,70 @@ +# Dolibarr language file - Source file is en_US - sendings +RefReception=Réf. réception +Reception=Réception +Receptions=Réceptions +AllReceptions=Toutes les réceptions +Shipment=Réception +Shipments=Réceptions +ShowReception=Afficher Réceptions +Receivings=Bons de réceptions +ReceptionsArea=Espace réceptions +ListOfReceptions=Liste des réceptions +ReceptionMethod=Méthode d'réception +LastReceptions=Les %s dernières réceptions +StatisticsOfReceptions=Statistiques des réceptions +NbOfReceptions=Nombre d'réceptions +NumberOfShipmentsByMonth=Nombre d'réceptions par mois +ReceptionCard=Fiche réception +NewReception=Nouvelle réception +CreateShipment=Créer réception +QtyShipped=Qté. expédiée +QtyPreparedOrShipped=Quantité préparée ou envoyée +QtyToShip=Qté. à expédier +QtyReceived=Qté. reçue +QtyInOtherShipments=Qté dans les autres réceptions +KeepToShip=Reste à expédier +OtherReceptionsForSameOrder=Autres réceptions pour cette commande +ReceptionsAndReceivingForSameOrder=Réceptions et réceptions pour cette commande +ReceptionsToValidate=Réceptions à valider +StatusReceptionCanceled=Annulée +StatusReceptionDraft=Brouillon +StatusReceptionValidated=Validée (produits à envoyer ou envoyés) +StatusReceptionProcessed=Traitée +StatusReceptionDraftShort=Brouillon +StatusReceptionValidatedShort=Validée +StatusReceptionProcessedShort=Traitée +ReceptionSheet=Fiche réception +ConfirmDeleteReception=Êtes-vous sûr de vouloir supprimer cette réception ? +ConfirmValidateReception=Êtes-vous sûr de vouloir valider cette réception sous la référence %s? +ConfirmCancelReception=Êtes-vous sûr de vouloir annuler cette réception ? +DocumentModelMerou=Modèle Merou A5 +WarningNoQtyLeftToSend=Alerte, aucun produit en attente d'réception. +StatsOnShipmentsOnlyValidated=Statistiques effectuées sur les réceptions validées uniquement. La date prise en compte est la date de validation (la date de prévision de livraison n'étant pas toujours renseignée). +DateDeliveryPlanned=Date prévue de livraison +RefDeliveryReceipt=Ref bon de réception +StatusReceipt=Status du bon de réception +DateReceived=Date de réception réelle +SendShippingByEMail=Envoyer bon d'réception par email +SendShippingRef=Envoi du bordereau d'réception %s +ActionsOnShipping=Événements sur l'réception +LinkToTrackYourPackage=Lien pour le suivi de votre colis +ShipmentCreationIsDoneFromOrder=Pour le moment, la création d'une nouvelle réception se fait depuis la fiche commande. +ShipmentLine=Ligne d'réception +ProductQtyInCustomersOrdersRunning=Quantité de produit en commandes client ouvertes +ProductQtyInSuppliersOrdersRunning=Quantité de produit en commandes fournisseur ouvertes +ProductQtyInShipmentAlreadySent=Quantité de produit en commande client ouverte déjà expédiée +ProductQtyInSuppliersShipmentAlreadyRecevied=Quantité de produit déjà reçu en commandes fournisseur ouvertes +NoProductToShipFoundIntoStock=Aucun produit à expédier n'a été trouver dans l'entrepôt %s. Corrigez l'inventaire ou retourner choisir un autre entrepôt. +WeightVolShort=Poids/vol. +ValidateOrderFirstBeforeShipment=Vous devez d'abord valider la commande pour pouvoir créer une réception. + +# Reception methods +# ModelDocument +DocumentModelTyphon=Modèle de bon de réception/livraison complet (logo…) +Error_EXPEDITION_ADDON_NUMBER_NotDefined=Constante EXPEDITION_ADDON_NUMBER non définie +SumOfProductVolumes=Somme des volumes des produits +SumOfProductWeights=Somme des poids des produits + +# warehouse details +DetailWarehouseNumber= Détail de l'entrepôt +DetailWarehouseFormat= W:%s (Qté : %d) diff --git a/htdocs/reception/card.php b/htdocs/reception/card.php new file mode 100644 index 00000000000..fbe7d81622c --- /dev/null +++ b/htdocs/reception/card.php @@ -0,0 +1,2754 @@ + + * Copyright (C) 2005-2016 Laurent Destailleur + * Copyright (C) 2005 Simon TOSSER + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2011-2017 Juanjo Menent + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2013 Marcos García + * Copyright (C) 2014 Cedric GROSS + * Copyright (C) 2014-2017 Francis Appels + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2016 Ferran Marcet + * Copyright (C) 2016 Yasser Carreón + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/card.php + * \ingroup expedition + * \brief Card of a shipment + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; +if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php'; +if (! empty($conf->projet->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; +} + +$langs->loadLangs(array("sendings","companies","bills",'deliveries','orders','stocks','other','propal')); + +if (!empty($conf->incoterm->enabled)) $langs->load('incoterm'); +if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); + +$origin = GETPOST('origin','alpha')?GETPOST('origin','alpha'):'expedition'; // Example: commande, propal +$origin_id = GETPOST('id','int')?GETPOST('id','int'):''; +$id = $origin_id; +if (empty($origin_id)) $origin_id = GETPOST('origin_id','int'); // Id of order or propal +if (empty($origin_id)) $origin_id = GETPOST('object_id','int'); // Id of order or propal +$ref=GETPOST('ref','alpha'); +$line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; + +// Security check +$socid=''; +if ($user->societe_id) $socid=$user->societe_id; + +if ($origin == 'expedition') $result=restrictedArea($user, $origin, $id); +else { + $result=restrictedArea($user, 'expedition'); + if (empty($user->rights->{$origin}->lire) && empty($user->rights->{$origin}->read)) accessforbidden(); +} + +$action = GETPOST('action','alpha'); +$confirm = GETPOST('confirm','alpha'); +$cancel = GETPOST('cancel','alpha'); + +//PDF +$hidedetails = (GETPOST('hidedetails','int') ? GETPOST('hidedetails','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0)); +$hidedesc = (GETPOST('hidedesc','int') ? GETPOST('hidedesc','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0)); +$hideref = (GETPOST('hideref','int') ? GETPOST('hideref','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0)); + +$object = new Expedition($db); +$extrafields = new ExtraFields($db); +$extrafieldsline = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + +// fetch optionals attributes lines and labels +$extralabelslines=$extrafieldsline->fetch_name_optionals_label($object->table_element_line); + + +// Load object. Make an object->fetch +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('expeditioncard','globalcard')); + +$permissiondellink=$user->rights->expedition->livraison->creer; // Used by the include of actions_dellink.inc.php +//var_dump($object->lines[0]->detail_batch); + + +/* + * Actions + */ + +$parameters=array(); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + if ($cancel) + { + $action = ''; + $object->fetch($id); // show shipment also after canceling modification + } + + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once + + // Reopen + if ($action == 'reopen' && $user->rights->expedition->creer) + { + $object->fetch($id); + $result = $object->reOpen(); + } + + // Confirm back to draft status + if ($action == 'modif' && $user->rights->expedition->creer) + { + $result = $object->set_draft($user); + if ($result >= 0) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + } + + // Set incoterm + if ($action == 'set_incoterms' && !empty($conf->incoterm->enabled)) + { + $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha')); + } + + if ($action == 'setref_customer') + { + $result = $object->fetch($id); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + + $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer','alpha'), '', null, 'text', '', $user, 'SHIPMENT_MODIFY'); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'editref_customer'; + } else { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + } + + if ($action == 'update_extras') + { + // Fill array 'array_options' with data from update form + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute')); + if ($ret < 0) $error++; + + if (! $error) + { + // Actions on extra fields (by external module or standard code) + // TODO le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('expeditiondao')); + $parameters = array('id' => $object->id); + $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) { + $result = $object->insertExtraFields(); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } else if ($reshook < 0) + $error++; + } + + if ($error) + $action = 'edit_extras'; + } + + // Create shipment + if ($action == 'add' && $user->rights->expedition->creer) + { + $error=0; + $predef=''; + + $db->begin(); + + $object->note = GETPOST('note','alpha'); + $object->origin = $origin; + $object->origin_id = $origin_id; + $object->fk_project = GETPOST('projectid','int'); + $object->weight = GETPOST('weight','int')==''?"NULL":GETPOST('weight','int'); + $object->sizeH = GETPOST('sizeH','int')==''?"NULL":GETPOST('sizeH','int'); + $object->sizeW = GETPOST('sizeW','int')==''?"NULL":GETPOST('sizeW','int'); + $object->sizeS = GETPOST('sizeS','int')==''?"NULL":GETPOST('sizeS','int'); + $object->size_units = GETPOST('size_units','int'); + $object->weight_units = GETPOST('weight_units','int'); + + $date_delivery = dol_mktime(GETPOST('date_deliveryhour','int'), GETPOST('date_deliverymin','int'), 0, GETPOST('date_deliverymonth','int'), GETPOST('date_deliveryday','int'), GETPOST('date_deliveryyear','int')); + + // On va boucler sur chaque ligne du document d'origine pour completer objet expedition + // avec info diverses + qte a livrer + $classname = ucfirst($object->origin); + $objectsrc = new $classname($db); + $objectsrc->fetch($object->origin_id); + + $object->socid = $objectsrc->socid; + $object->ref_customer = GETPOST('ref_customer','alpha'); + $object->model_pdf = GETPOST('model'); + $object->date_delivery = $date_delivery; // Date delivery planed + $object->fk_delivery_address = $objectsrc->fk_delivery_address; + $object->shipping_method_id = GETPOST('shipping_method_id','int'); + $object->tracking_number = GETPOST('tracking_number','alpha'); + $object->ref_int = GETPOST('ref_int','alpha'); + $object->note_private = GETPOST('note_private','none'); + $object->note_public = GETPOST('note_public','none'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); + + $batch_line = array(); + $stockLine = array(); + $array_options=array(); + + $num=count($objectsrc->lines); + $totalqty=0; + + for ($i = 0; $i < $num; $i++) + { + $idl="idl".$i; + + $sub_qty=array(); + $subtotalqty=0; + + $j=0; + $batch="batchl".$i."_0"; + $stockLocation="ent1".$i."_0"; + $qty = "qtyl".$i; + + if ($objectsrc->lines[$i]->product_tobatch) // If product need a batch number + { + if (isset($_POST[$batch])) + { + //shipment line with batch-enable product + $qty .= '_'.$j; + while (isset($_POST[$batch])) + { + // save line of detail into sub_qty + $sub_qty[$j]['q']=GETPOST($qty,'int'); // the qty we want to move for this stock record + $sub_qty[$j]['id_batch']=GETPOST($batch,'int'); // the id into llx_product_batch of stock record to move + $subtotalqty+=$sub_qty[$j]['q']; + + //var_dump($qty);var_dump($batch);var_dump($sub_qty[$j]['q']);var_dump($sub_qty[$j]['id_batch']); + + $j++; + $batch="batchl".$i."_".$j; + $qty = "qtyl".$i.'_'.$j; + } + + $batch_line[$i]['detail']=$sub_qty; // array of details + $batch_line[$i]['qty']=$subtotalqty; + $batch_line[$i]['ix_l']=GETPOST($idl,'int'); + + $totalqty+=$subtotalqty; + } + else + { + // No detail were provided for lots + if (! empty($_POST[$qty])) + { + // We try to set an amount + // Case we dont use the list of available qty for each warehouse/lot + // GUI does not allow this yet + setEventMessage('StockIsRequiredToChooseWhichLotToUse', 'errors'); + } + } + } + else if (isset($_POST[$stockLocation])) + { + //shipment line from multiple stock locations + $qty .= '_'.$j; + while (isset($_POST[$stockLocation])) + { + // save sub line of warehouse + $stockLine[$i][$j]['qty']=GETPOST($qty,'int'); + $stockLine[$i][$j]['warehouse_id']=GETPOST($stockLocation,'int'); + $stockLine[$i][$j]['ix_l']=GETPOST($idl,'int'); + + $totalqty+=GETPOST($qty,'int'); + + $j++; + $stockLocation="ent1".$i."_".$j; + $qty = "qtyl".$i.'_'.$j; + } + } + else + { + //var_dump(GETPOST($qty,'int')); var_dump($_POST); var_dump($batch);exit; + //shipment line for product with no batch management and no multiple stock location + if (GETPOST($qty,'int') > 0) $totalqty+=GETPOST($qty,'int'); + } + + // Extrafields + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $array_options[$i] = $extrafieldsline->getOptionalsFromPost($extralabelsline, $i); + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + + } + + //var_dump($batch_line[2]); + + if ($totalqty > 0) // There is at least one thing to ship + { + //var_dump($_POST);exit; + for ($i = 0; $i < $num; $i++) + { + $qty = "qtyl".$i; + if (! isset($batch_line[$i])) + { + // not batch mode + if (isset($stockLine[$i])) + { + //shipment from multiple stock locations + $nbstockline = count($stockLine[$i]); + for($j = 0; $j < $nbstockline; $j++) + { + if ($stockLine[$i][$j]['qty']>0) + { + $ret=$object->addline($stockLine[$i][$j]['warehouse_id'], $stockLine[$i][$j]['ix_l'], $stockLine[$i][$j]['qty'], $array_options[$i]); + if ($ret < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + } + else + { + if (GETPOST($qty,'int') > 0 || (GETPOST($qty,'int') == 0 && $conf->global->SHIPMENT_GETS_ALL_ORDER_PRODUCTS)) + { + $ent = "entl".$i; + $idl = "idl".$i; + $entrepot_id = is_numeric(GETPOST($ent,'int'))?GETPOST($ent,'int'):GETPOST('entrepot_id','int'); + if ($entrepot_id < 0) $entrepot_id=''; + if (! ($objectsrc->lines[$i]->fk_product > 0)) $entrepot_id = 0; + + $ret=$object->addline($entrepot_id, GETPOST($idl,'int'), GETPOST($qty,'int'), $array_options[$i]); + if ($ret < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + } + else + { + // batch mode + if ($batch_line[$i]['qty']>0) + { + $ret=$object->addline_batch($batch_line[$i],$array_options[$i]); + if ($ret < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + } + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) $error++; + + if (! $error) + { + $ret=$object->create($user); // This create shipment (like Odoo picking) and line of shipments. Stock movement will when validating shipment. + if ($ret <= 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + else + { + setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("QtyToShip").'/'.$langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); + $error++; + } + + if (! $error) + { + $db->commit(); + header("Location: card.php?id=".$object->id); + exit; + } + else + { + $db->rollback(); + $_GET["commande_id"]=GETPOST('commande_id','int'); + $action='create'; + } + } + + /* + * Build a receiving receipt + */ + else if ($action == 'create_delivery' && $conf->livraison_bon->enabled && $user->rights->expedition->livraison->creer) + { + $result = $object->create_delivery($user); + if ($result > 0) + { + header("Location: ".DOL_URL_ROOT.'/livraison/card.php?action=create_delivery&id='.$result); + exit; + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + else if ($action == 'confirm_valid' && $confirm == 'yes' && + ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate))) + ) + { + $object->fetch_thirdparty(); + + $result = $object->valid($user); + + if ($result < 0) + { + $langs->load("errors"); + setEventMessages($langs->trans($object->error), null, 'errors'); + } + else + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + + $result=$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result < 0) dol_print_error($db,$result); + } + } + } + + else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->expedition->supprimer) + { + $result = $object->delete(); + if ($result > 0) + { + header("Location: ".DOL_URL_ROOT.'/expedition/index.php'); + exit; + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + // TODO add alternative status + /*else if ($action == 'reopen' && (! empty($user->rights->expedition->creer) || ! empty($user->rights->expedition->shipping_advance->validate))) + { + $result = $object->setStatut(0); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + } + }*/ + + else if ($action == 'setdate_livraison' && $user->rights->expedition->creer) + { + //print "x ".$_POST['liv_month'].", ".$_POST['liv_day'].", ".$_POST['liv_year']; + $datedelivery=dol_mktime(GETPOST('liv_hour','int'), GETPOST('liv_min','int'), 0, GETPOST('liv_month','int'), GETPOST('liv_day','int'), GETPOST('liv_year','int')); + + $object->fetch($id); + $result=$object->set_date_livraison($user,$datedelivery); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + // Action update + else if ($action == 'settracking_number' || $action == 'settracking_url' + || $action == 'settrueWeight' + || $action == 'settrueWidth' + || $action == 'settrueHeight' + || $action == 'settrueDepth' + || $action == 'setshipping_method_id') + { + $error=0; + + if ($action == 'settracking_number') $object->tracking_number = trim(GETPOST('tracking_number','alpha')); + if ($action == 'settracking_url') $object->tracking_url = trim(GETPOST('tracking_url','int')); + if ($action == 'settrueWeight') { + $object->trueWeight = trim(GETPOST('trueWeight','int')); + $object->weight_units = GETPOST('weight_units','int'); + } + if ($action == 'settrueWidth') $object->trueWidth = trim(GETPOST('trueWidth','int')); + if ($action == 'settrueHeight'){ + $object->trueHeight = trim(GETPOST('trueHeight','int')); + $object->size_units = GETPOST('size_units','int'); + } + if ($action == 'settrueDepth') $object->trueDepth = trim(GETPOST('trueDepth','int')); + if ($action == 'setshipping_method_id') $object->shipping_method_id = trim(GETPOST('shipping_method_id','int')); + + if (! $error) + { + if ($object->update($user) >= 0) + { + header("Location: card.php?id=".$object->id); + exit; + } + setEventMessages($object->error, $object->errors, 'errors'); + } + + $action=""; + } + + // Build document + else if ($action == 'builddoc') // En get ou en post + { + // Save last template used to generate document + if (GETPOST('model')) $object->setDocModel($user, GETPOST('model','alpha')); + + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$shipment->thirdparty->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + $result = $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $action=''; + } + } + + // Delete file in doc form + elseif ($action == 'remove_file') + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $upload_dir = $conf->expedition->dir_output . "/sending"; + $file = $upload_dir . '/' . GETPOST('file'); + $ret=dol_delete_file($file,0,0,0,$object); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } + + elseif ($action == 'classifybilled') + { + $object->fetch($id); + $result = $object->set_billed(); + if($result >= 0) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + } + + elseif ($action == 'classifyclosed') + { + $object->fetch($id); + $result = $object->setClosed(); + if($result >= 0) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + } + + /* + * delete a line + */ + elseif ($action == 'deleteline' && ! empty($line_id)) + { + $object->fetch($id); + $lines = $object->lines; + $line = new ExpeditionLigne($db); + + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) + { + if (count($lines[$i]->details_entrepot) > 1) + { + // delete multi warehouse lines + foreach ($lines[$i]->details_entrepot as $details_entrepot) { + $line->id = $details_entrepot->line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + else + { + // delete single warehouse line + $line->id = $line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + } + } + unset($_POST["lineid"]); + } + + if(! $error) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + } + } + + /* + * Update a line + */ + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('save')) + { + // Clean parameters + $qty=0; + $entrepot_id = 0; + $batch_id = 0; + + $lines = $object->lines; + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) // we have found line to update + { + $line = new ExpeditionLigne($db); + // Extrafields Lines + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $line->array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline); + // Unset extrafield POST Data + if (is_array($extralabelsline)) { + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + $line->fk_product = $lines[$i]->fk_product; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + // line with lot + foreach ($lines[$i]->detail_batch as $detail_batch) + { + $lotStock = new Productbatch($db); + $batch="batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock; + $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id; + $batch_id = GETPOST($batch,'int'); + $batch_qty = GETPOST($qty, 'int'); + if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->dluo_qty)) + { + if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) // $line is ExpeditionLine + { + if ($lines[$i]->entrepot_id != 0) + { + // allow update line entrepot_id if not multi warehouse shipping + $line->entrepot_id = $lotStock->warehouseid; + } + + // detail_batch can be an object with keys, or an array of ExpeditionLineBatch + if (empty($line->detail_batch)) $line->detail_batch=new stdClass(); + + $line->detail_batch->fk_origin_stock = $batch_id; + $line->detail_batch->batch = $lotStock->batch; + $line->detail_batch->id = $detail_batch->id; + $line->detail_batch->entrepot_id = $lotStock->warehouseid; + $line->detail_batch->dluo_qty = $batch_qty; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + setEventMessages($lotStock->error, $lotStock->errors, 'errors'); + $error++; + } + } + unset($_POST[$batch]); + unset($_POST[$qty]); + } + // add new batch + $lotStock = new Productbatch($db); + $batch="batchl".$line_id."_0"; + $qty = "qtyl".$line_id."_0"; + $batch_id = GETPOST($batch,'int'); + $batch_qty = GETPOST($qty, 'int'); + $lineIdToAddLot = 0; + if ($batch_qty > 0 && ! empty($batch_id)) + { + if ($lotStock->fetch($batch_id) > 0) + { + // check if lotStock warehouse id is same as line warehouse id + if ($lines[$i]->entrepot_id > 0) + { + // single warehouse shipment line + if ($lines[i]->entrepot_id == $lotStock->warehouseid) + { + $lineIdToAddLot = $line_id; + } + } + else if (count($lines[$i]->details_entrepot) > 1) + { + // multi warehouse shipment lines + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) + { + $lineIdToAddLot = $detail_entrepot->line_id; + } + } + } + if ($lineIdToAddLot) + { + // add lot to existing line + if ($line->fetch($lineIdToAddLot) > 0) + { + $line->detail_batch->fk_origin_stock = $batch_id; + $line->detail_batch->batch = $lotStock->batch; + $line->detail_batch->entrepot_id = $lotStock->warehouseid; + $line->detail_batch->dluo_qty = $batch_qty; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + else + { + // create new line with new lot + $line->origin_line_id = $lines[$i]->origin_line_id; + $line->entrepot_id = $lotStock->warehouseid; + $line->detail_batch[0] = new ExpeditionLineBatch($db); + $line->detail_batch[0]->fk_origin_stock = $batch_id; + $line->detail_batch[0]->batch = $lotStock->batch; + $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid; + $line->detail_batch[0]->dluo_qty = $batch_qty; + if ($object->create_line_batch($line, $line->array_options) < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + else + { + setEventMessages($lotStock->error, $lotStock->errors, 'errors'); + $error++; + } + } + } + else + { + if ($lines[$i]->fk_product > 0) + { + // line without lot + if ($lines[$i]->entrepot_id > 0) + { + // single warehouse shipment line + $stockLocation="entl".$line_id; + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->entrepot_id = GETPOST($stockLocation,'int'); + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + // multi warehouse shipment lines + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if (! $error) { + $stockLocation="entl".$detail_entrepot->line_id; + $qty = "qtyl".$detail_entrepot->line_id; + $warehouse = GETPOST($stockLocation,'int'); + if (!empty ($warehouse)) + { + $line->id = $detail_entrepot->line_id; + $line->entrepot_id = $warehouse; + $line->qty = GETPOST($qty, 'int'); + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + } + unset($_POST[$stockLocation]); + unset($_POST[$qty]); + } + } + } + } + else // Product no predefined + { + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->qty = GETPOST($qty, 'int'); + $line->entrepot_id = 0; + if ($line->update($user) < 0) { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$qty]); + } + } + } + } + + unset($_POST["lineid"]); + + if (! $error) { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) + $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + $ret = $object->fetch($object->id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + } + + else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + // Actions to send emails + if (empty($id)) $id=$facid; + $trigger_name='SHIPPING_SENTBYMAIL'; + $paramname='id'; + $mode='emailfromshipment'; + $trackid='shi'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + +} + + +/* + * View + */ + +llxHeader('',$langs->trans('Shipment'),'Expedition'); + +$form = new Form($db); +$formfile = new FormFile($db); +$formproduct = new FormProduct($db); +if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } + +$product_static = new Product($db); +$shipment_static = new Expedition($db); +$warehousestatic = new Entrepot($db); + +if ($action == 'create2') +{ + print load_fiche_titre($langs->trans("CreateShipment")).'
'; + print $langs->trans("ShipmentCreationIsDoneFromOrder"); + $action=''; $id=''; $ref=''; +} + +// Mode creation. +if ($action == 'create') +{ + $expe = new Expedition($db); + + print load_fiche_titre($langs->trans("CreateShipment")); + if (! $origin) + { + setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors'); + } + + if ($origin) + { + $classname = ucfirst($origin); + + $object = new $classname($db); + if ($object->fetch($origin_id)) // This include the fetch_lines + { + $soc = new Societe($db); + $soc->fetch($object->socid); + + $author = new User($db); + $author->fetch($object->user_author_id); + + if (! empty($conf->stock->enabled)) $entrepot = new Entrepot($db); + + print '
'; + print ''; + print ''; + print ''; + print ''; + print ''; + if (GETPOST('entrepot_id','int')) + { + print ''; + } + + dol_fiche_head(''); + + print ''; + + // Ref + print ''; + print "\n"; + + // Ref client + print ''; + print ''; + + // Tiers + print ''; + print ''; + print ''; + + // Project + if (! empty($conf->projet->enabled)) + { + $projectid = GETPOST('projectid','int')?GETPOST('projectid','int'):0; + if(empty($projectid) && ! empty($object->fk_project)) $projectid = $object->fk_project; + if ($origin == 'project') $projectid = ($originid ? $originid : 0); + + $langs->load("projects"); + print ''; + print ''; + print ''; + } + + // Date delivery planned + print ''; + print '\n"; + print ''; + + // Note Public + print ''; + print '"; + + // Note Private + if ($object->note_private && ! $user->societe_id) + { + print ''; + print '"; + } + + // Weight + print ''; + // Dim + print ''; + + // Delivery method + print ""; + print '\n"; + + // Tracking number + print ""; + print '\n"; + + // Other attributes + $parameters = array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"', 'socid'=>$socid); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$expe,$action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + + if (empty($reshook) && ! empty($extrafields->attribute_label)) { + // copy from order + $orderExtrafields = new Extrafields($db); + $orderExtrafieldLabels = $orderExtrafields->fetch_name_optionals_label($object->table_element); + if ($object->fetch_optionals($object->id, $orderExtrafieldLabels) > 0) { + $expe->array_options = array_merge($expe->array_options, $object->array_options); + } + print $object->showOptionals($extrafields, 'edit'); + } + + + // Incoterms + if (!empty($conf->incoterm->enabled)) + { + print ''; + print ''; + print ''; + } + + // Document model + include_once DOL_DOCUMENT_ROOT . '/core/modules/expedition/modules_expedition.php'; + $liste = ModelePdfExpedition::liste_modeles($db); + if (count($liste) > 1) + { + print ""; + print '\n"; + } + + print "
'; + if ($origin == 'commande' && ! empty($conf->commande->enabled)) + { + print $langs->trans("RefOrder").''.img_object($langs->trans("ShowOrder"),'order').' '.$object->ref; + } + if ($origin == 'propal' && ! empty($conf->propal->enabled)) + { + print $langs->trans("RefProposal").''.img_object($langs->trans("ShowProposal"),'propal').' '.$object->ref; + } + print '
'; + if ($origin == 'commande') print $langs->trans('RefCustomerOrder'); + else if ($origin == 'propal') print $langs->trans('RefCustomerOrder'); + else print $langs->trans('RefCustomer'); + print ''; + print ''; + print '
'.$langs->trans('Company').''.$soc->getNomUrl(1).'
' . $langs->trans("Project") . ''; + $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0); + print '   id).'">' . $langs->trans("AddProject") . ''; + print '
'.$langs->trans("DateDeliveryPlanned").''; + //print dol_print_date($object->date_livraison,"day"); // date_livraison come from order and will be stored into date_delivery planed. + $date_delivery = ($date_delivery?$date_delivery:$object->date_livraison); // $date_delivery comes from GETPOST + print $form->select_date($date_delivery?$date_delivery:-1,'date_delivery',1,1,1); + print "
'.$langs->trans("NotePublic").''; + $doleditor = new DolEditor('note_public', $object->note_public, '', 60, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + print "
'.$langs->trans("NotePrivate").''; + $doleditor = new DolEditor('note_private', $object->note_private, '', 60, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + print "
'; + print $langs->trans("Weight"); + print ' '; + $text=$formproduct->select_measuring_units("weight_units","weight",GETPOST('weight_units','int')); + $htmltext=$langs->trans("KeepEmptyForAutoCalculation"); + print $form->textwithpicto($text, $htmltext); + print '
'; + print $langs->trans("Width").' x '.$langs->trans("Height").' x '.$langs->trans("Depth"); + print ' '; + print ' x '; + print ' x '; + print ' '; + $text=$formproduct->select_measuring_units("size_units","size"); + $htmltext=$langs->trans("KeepEmptyForAutoCalculation"); + print $form->textwithpicto($text, $htmltext); + print '
".$langs->trans("DeliveryMethod")."'; + $expe->fetch_delivery_methods(); + print $form->selectarray("shipping_method_id", $expe->meths, GETPOST('shipping_method_id','int'),1,0,0,"",1); + if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); + print "
".$langs->trans("TrackingNumber")."'; + print ''; + print "
'; + print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms)?$object->location_incoterms:'')); + print '
".$langs->trans("DefaultModel")."'; + print $form->selectarray('model', $liste, $conf->global->EXPEDITION_ADDON_PDF); + print "
"; + + dol_fiche_end(); + + + // Shipment lines + + $numAsked = count($object->lines); + + print ''; + + + print '
'; + + + print ''; + + + // Load shipments already done for same order + $object->loadExpeditions(); + + if ($numAsked) + { + print ''; + print ''; + print ''; + print ''; + print ''; + if (! empty($conf->stock->enabled)) + { + if (empty($conf->productbatch->enabled)) + { + print ''; + } + else + { + print ''; + } + } + print "\n"; + } + + $var=true; + $indiceAsked = 0; + while ($indiceAsked < $numAsked) + { + $product = new Product($db); + + $line = $object->lines[$indiceAsked]; + + + // Show product and description + $type=$line->product_type?$line->product_type:$line->fk_product_type; + // Try to enhance type detection using date_start and date_end for free lines where type + // was not saved. + if (! empty($line->date_start)) $type=1; + if (! empty($line->date_end)) $type=1; + + print ''."\n"; + print ''."\n"; + + // Product label + if ($line->fk_product > 0) // If predefined product + { + $product->fetch($line->fk_product); + $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch + //var_dump($product->stock_warehouse[1]); + + print ''; + } + else + { + print "\n"; + } + + // Qty + print ''; + $qtyProdCom=$line->qty; + + // Qty already shipped + print ''; + + // Qty to ship + $quantityAsked = $line->qty; + if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $quantityToBeDelivered = 0; + } + else + { + $quantityToBeDelivered = $quantityAsked - $quantityDelivered; + } + $warehouse_id = GETPOST('entrepot_id','int'); + + $warehouseObject = null; + if ($warehouse_id > 0 || ! ($line->fk_product > 0) || empty($conf->stock->enabled)) // If warehouse was already selected or if product is not a predefined, we go into this part with no multiwarehouse selection + { + print ''; + //ship from preselected location + $stock = + $product->stock_warehouse[$warehouse_id]->real; // Convert to number + $deliverableQty=min($quantityToBeDelivered, $stock); + if ($deliverableQty < 0) $deliverableQty = 0; + if (empty($conf->productbatch->enabled) || ! $product->hasbatch()) + { + // Quantity to send + print ''; + + // Stock + if (! empty($conf->stock->enabled)) + { + print ''; + } + + print "\n"; + + // Show subproducts of product + if (! empty($conf->global->PRODUIT_SOUSPRODUITS) && $line->fk_product > 0) + { + $product->get_sousproduits_arbo(); + $prods_arbo = $product->get_arbo_each_prod($qtyProdCom); + if(count($prods_arbo) > 0) + { + foreach($prods_arbo as $key => $value) + { + //print $value[0]; + $img=''; + if ($value['stock'] < $value['stock_alert']) + { + $img=img_warning($langs->trans("StockTooLow")); + } + print " + "; + } + } + } + } + else + { + // Product need lot + print ''; // end line and start a new one for lot/serial + + $staticwarehouse=new Entrepot($db); + if ($warehouse_id > 0) $staticwarehouse->fetch($warehouse_id); + + $subj=0; + // Define nb of lines suggested for this order line + $nbofsuggested=0; + if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) + { + foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) + { + $nbofsuggested++; + } + } + print ''; + if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch)) + { + foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch) + { + //var_dump($dbatch); + $batchStock = + $dbatch->qty; // To get a numeric + $deliverableQty = min($quantityToBeDelivered,$batchStock); + print ''; + print ''; + + print ''; + print ''; + } + } + else + { + print ''; + print ''; + + print ''; + } + } + } + else + { + // ship from multiple locations + if (empty($conf->productbatch->enabled) || ! $product->hasbatch()) + { + print ''; + print ''."\n"; // end line and start a new one for each warehouse + + print ''; + $subj=0; + // Define nb of lines suggested for this order line + $nbofsuggested=0; + foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) + { + if ($stock_warehouse->real > 0) + { + $nbofsuggested++; + } + } + $tmpwarehouseObject=new Entrepot($db); + foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) // $stock_warehouse is product_stock + { + $tmpwarehouseObject->fetch($warehouse_id); + if ($stock_warehouse->real > 0) + { + $stock = + $stock_warehouse->real; // Convert it to number + $deliverableQty = min($quantityToBeDelivered,$stock); + $deliverableQty = max(0, $deliverableQty); + // Quantity to send + print ''; + print ''; + + // Stock + if (! empty($conf->stock->enabled)) + { + print ''; + } + $quantityToBeDelivered -= $deliverableQty; + if ($quantityToBeDelivered < 0) + { + $quantityToBeDelivered = 0; + } + $subj++; + print "\n"; + } + } + // Show subproducts of product (not recommanded) + if (! empty($conf->global->PRODUIT_SOUSPRODUITS) && $line->fk_product > 0) + { + $product->get_sousproduits_arbo(); + $prods_arbo = $product->get_arbo_each_prod($qtyProdCom); + if (count($prods_arbo) > 0) + { + foreach($prods_arbo as $key => $value) + { + //print $value[0]; + $img=''; + if ($value['stock'] < $value['stock_alert']) + { + $img=img_warning($langs->trans("StockTooLow")); + } + print ' + "; + print ""; + } + } + } + } + else + { + print ''; + print ''; // end line and start a new one for lot/serial + + $subj=0; + print ''; + + $tmpwarehouseObject=new Entrepot($db); + $productlotObject=new Productlot($db); + // Define nb of lines suggested for this order line + $nbofsuggested=0; + foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) + { + if (($stock_warehouse->real > 0) && (count($stock_warehouse->detail_batch))) { + foreach ($stock_warehouse->detail_batch as $dbatch) + { + $nbofsuggested++; + } + } + } + foreach ($product->stock_warehouse as $warehouse_id=>$stock_warehouse) + { + $tmpwarehouseObject->fetch($warehouse_id); + if (($stock_warehouse->real > 0) && (count($stock_warehouse->detail_batch))) { + foreach ($stock_warehouse->detail_batch as $dbatch) + { + //var_dump($dbatch); + $batchStock = + $dbatch->qty; // To get a numeric + $deliverableQty = min($quantityToBeDelivered,$batchStock); + if ($deliverableQty < 0) $deliverableQty = 0; + print ''; + + print ''; + } + } + } + + } + if ($subj == 0) // Line not shown yet, we show it + { + print ''; + print ''; + + print ''; + print ''; + } + } + + + //Display lines extrafields + if (is_array($extralabelslines) && count($extralabelslines)>0) + { + $colspan=5; + $orderLineExtrafields = new Extrafields($db); + $orderLineExtrafieldLabels = $orderLineExtrafields->fetch_name_optionals_label($object->table_element_line); + $srcLine = new OrderLine($db); + $srcLine->fetch_optionals($line->id,$orderLineExtrafieldLabels); // fetch extrafields also available in orderline + $line = new ExpeditionLigne($db); + $line->fetch_optionals($object->id,$extralabelslines); + $line->array_options = array_merge($line->array_options, $srcLine->array_options); + print ''; + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + print ''; + } + + $indiceAsked++; + } + + print "
'.$langs->trans("Description").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyShipped").''.$langs->trans("QtyToShip"); + if (empty($conf->productbatch->enabled)) + { + print '
('.$langs->trans("Fill").''; + print ' / '.$langs->trans("Reset").')'; + } + print '
'.$langs->trans("Warehouse").' ('.$langs->trans("Stock").')'.$langs->trans("Warehouse").' / '.$langs->trans("Batch").' ('.$langs->trans("Stock").')
'; + print ''; // ancre pour retourner sur la ligne + + // Show product and description + $product_static->type=$line->fk_product_type; + $product_static->id=$line->fk_product; + $product_static->ref=$line->ref; + $product_static->status_batch=$line->product_tobatch; + $text=$product_static->getNomUrl(1); + $text.= ' - '.(! empty($line->label)?$line->label:$line->product_label); + $description=($conf->global->PRODUIT_DESC_IN_FORM?'':dol_htmlentitiesbr($line->desc)); + print $form->textwithtooltip($text,$description,3,'','',$i); + + // Show range + print_date_range($db->jdate($line->date_start),$db->jdate($line->date_end)); + + // Add description in form + if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) + { + print ($line->desc && $line->desc!=$line->product_label)?'
'.dol_htmlentitiesbr($line->desc):''; + } + + print '
"; + if ($type==1) $text = img_object($langs->trans('Service'),'service'); + else $text = img_object($langs->trans('Product'),'product'); + + if (! empty($line->label)) { + $text.= ' '.$line->label.''; + print $form->textwithtooltip($text,$line->desc,3,'','',$i); + } else { + print $text.' '.nl2br($line->desc); + } + + // Show range + print_date_range($db->jdate($line->date_start),$db->jdate($line->date_end)); + print "'.$line->qty; + print ''; + print ''; + $quantityDelivered = $object->expeditions[$line->id]; + print $quantityDelivered; + print ''; + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + if (GETPOST('qtyl'.$indiceAsked, 'int')) $defaultqty=GETPOST('qtyl'.$indiceAsked, 'int'); + print ''; + print ''; + } + else print $langs->trans("NA"); + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) // Type of product need stock change ? + { + // Show warehouse combo list + $ent = "entl".$indiceAsked; + $idl = "idl".$indiceAsked; + $tmpentrepot_id = is_numeric(GETPOST($ent,'int'))?GETPOST($ent,'int'):$warehouse_id; + if ($line->fk_product > 0) + { + print ''; + print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 1, 0, $line->fk_product, '', 1); + if ($tmpentrepot_id > 0 && $tmpentrepot_id == $warehouse_id) + { + //print $stock.' '.$quantityToBeDelivered; + if ($stock < $quantityToBeDelivered) + { + print ' '.img_warning($langs->trans("StockTooLow")); // Stock too low for this $warehouse_id but you can change warehouse + } + } + } + } + else + { + print $langs->trans("Service"); + } + print '
      -> + ".$value['fullpath']." + (".$value['nb'].") ".$value['nb_total']."  ".$value['stock']." ".$img."
'; + print ''; + print ''; + + print $staticwarehouse->getNomUrl(0).' / '; + + print ''; + + $detail=''; + $detail.= $langs->trans("Batch").': '.$dbatch->batch; + $detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day"); + $detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day"); + $detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty; + $detail.= '
'; + print $detail; + + $quantityToBeDelivered -= $deliverableQty; + if ($quantityToBeDelivered < 0) + { + $quantityToBeDelivered = 0; + } + $subj++; + print '
'; + print ' '; + print ''; + print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $staticwarehouse->libelle); + print '
'; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + print ''; + print ''; + } + else print $langs->trans("NA"); + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + print $tmpwarehouseObject->getNomUrl(0).' '; + + print ''; + print '('.$stock.')'; + + } + else + { + print $langs->trans("Service"); + } + print '
'; + print "      -> + ".$value['fullpath']." + (".$value['nb'].") ".$value['nb_total']."  ".$value['stock']." ".$img."
'; + print ''; + print ''; + + print $tmpwarehouseObject->getNomUrl(0).' / '; + + print ''; + print ''; + + //print $line->fk_product.' - '.$dbatch->batch; + print $langs->trans("Batch").': '; + $result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch); + if ($result > 0) print $productlotObject->getNomUrl(1); + else print 'TableLotIncompleteRunRepair'; + print ' ('.$dbatch->qty.')'; + $quantityToBeDelivered -= $deliverableQty; + if ($quantityToBeDelivered < 0) + { + $quantityToBeDelivered = 0; + } + //dol_syslog('deliverableQty = '.$deliverableQty.' batchStock = '.$batchStock); + $subj++; + print '
'; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $disabled=''; + if (! empty($conf->productbatch->enabled) && $product->hasbatch()) + { + $disabled='disabled="disabled"'; + } + print ' '; + } + else + { + print $langs->trans("NA"); + } + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $warehouse_selected_id = GETPOST('entrepot_id','int'); + if ($warehouse_selected_id > 0) + { + $warehouseObject=new Entrepot($db); + $warehouseObject->fetch($warehouse_selected_id); + print img_warning().' '.$langs->trans("NoProductToShipFoundIntoStock", $warehouseObject->libelle); + } + else + { + if ($line->fk_product) print img_warning().' '.$langs->trans("StockTooLow"); + else print ''; + } + } + else + { + print $langs->trans("Service"); + } + print '
"; + + print '
'; + + print '
'; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
'; + + print '
'; + + print '
'; + } + else + { + dol_print_error($db); + } + } +} +else if ($id || $ref) +/* *************************************************************************** */ +/* */ +/* Edit and view mode */ +/* */ +/* *************************************************************************** */ +{ + $lines = $object->lines; + + $num_prod = count($lines); + + if ($object->id > 0) + { + if (!empty($object->origin) && $object->origin_id > 0) + { + $typeobject = $object->origin; + $origin = $object->origin; + $origin_id = $object->origin_id; + $object->fetch_origin(); // Load property $object->commande, $object->propal, ... + } + + $soc = new Societe($db); + $soc->fetch($object->socid); + + $res = $object->fetch_optionals($object->id, $extralabels); + + $head=shipping_prepare_head($object); + dol_fiche_head($head, 'shipping', $langs->trans("Shipment"), -1, 'sending'); + + $formconfirm=''; + + // Confirm deleteion + if ($action == 'delete') + { + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('DeleteSending'),$langs->trans("ConfirmDeleteSending",$object->ref),'confirm_delete','',0,1); + } + + // Confirmation validation + if ($action == 'valid') + { + $objectref = substr($object->ref, 1, 4); + if ($objectref == 'PROV') + { + $numref = $object->getNextNumRef($soc); + } + else + { + $numref = $object->ref; + } + + $text = $langs->trans("ConfirmValidateSending",$numref); + + if (! empty($conf->notification->enabled)) + { + require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; + $notify=new Notify($db); + $text.='
'; + $text.=$notify->confirmMessage('SHIPPING_VALIDATE',$object->socid, $object); + } + + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('ValidateSending'),$text,'confirm_valid','',0,1); + + } + // Confirm cancelation + if ($action == 'annuler') + { + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('CancelSending'),$langs->trans("ConfirmCancelSending",$object->ref),'confirm_cancel','',0,1); + + } + + if (! $formconfirm) { + $parameters = array(); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Calculate totalWeight and totalVolume for all products + // by adding weight and volume of each product line. + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + + + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } + + // Shipment card + $linkback = ''.$langs->trans("BackToList").''; + $morehtmlref='
'; + // Ref customer shipment + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_customer', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on shipment + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on shipment, so we will use the project or source object instead + // TODO Add project on shipment + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + print '
'; + print '
'; + + print ''; + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + print ''; + print '\n"; + print ''; + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + print ''; + print '\n"; + print ''; + } + + // Date creation + print ''; + print '\n"; + print ''; + + // Delivery date planned + print ''; + print ''; + + // Weight + print ''; + + // Width + print ''; + + // Height + print ''; + + // Depth + print ''; + + // Volume + print ''; + print '\n"; + print ''; + + // Other attributes + $cols = 2; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
'; + print $langs->trans("RefOrder").''; + print $objectsrc->getNomUrl(1,'commande'); + print "
'; + print $langs->trans("RefProposal").''; + print $objectsrc->getNomUrl(1,'expedition'); + print "
'.$langs->trans("DateCreation").''.dol_print_date($object->date_creation,"dayhour")."
'; + print ''; + + if ($action != 'editdate_livraison') print ''; + print '
'; + print $langs->trans('DateDeliveryPlanned'); + print 'id.'">'.img_edit($langs->trans('SetDeliveryDate'),1).'
'; + print '
'; + if ($action == 'editdate_livraison') + { + print '
'; + print ''; + print ''; + print $form->select_date($object->date_delivery?$object->date_delivery:-1,'liv_',1,1,'',"setdate_livraison",1,0,1); + print ''; + print '
'; + } + else + { + print $object->date_delivery ? dol_print_date($object->date_delivery,'dayhour') : ' '; + } + print '
'; + print $form->editfieldkey("Weight",'trueWeight',$object->trueWeight,$object,$user->rights->expedition->creer); + print ''; + + if ($action=='edittrueWeight') + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print $formproduct->select_measuring_units("weight_units","weight",$object->weight_units); + print ' '; + print ' '; + print '
'; + + } + else + { + print $object->trueWeight; + print ($object->trueWeight && $object->weight_units!='')?' '.measuring_units_string($object->weight_units,"weight"):''; + } + + // Calculated + if ($totalWeight > 0) + { + if (!empty($object->trueWeight)) print ' ('.$langs->trans("SumOfProductWeights").': '; + //print $totalWeight.' '.measuring_units_string(0,"weight"); + print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND)?$conf->global->MAIN_WEIGHT_DEFAULT_ROUND:-1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT)?$conf->global->MAIN_WEIGHT_DEFAULT_UNIT:'no'); + //if (empty($object->trueWeight)) print ' ('.$langs->trans("Calculated").')'; + if (!empty($object->trueWeight)) print ')'; + } + print '
'.$form->editfieldkey("Width",'trueWidth',$object->trueWidth,$object,$user->rights->expedition->creer).''; + print $form->editfieldval("Width",'trueWidth',$object->trueWidth,$object,$user->rights->expedition->creer); + print ($object->trueWidth && $object->width_units!='')?' '.measuring_units_string($object->width_units,"size"):''; + print '
'.$form->editfieldkey("Height",'trueHeight',$object->trueHeight,$object,$user->rights->expedition->creer).''; + if($action=='edittrueHeight') + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print $formproduct->select_measuring_units("size_units","size",$object->size_units); + print ' '; + print ' '; + print '
'; + + } + else + { + print $object->trueHeight; + print ($object->trueHeight && $object->height_units!='')?' '.measuring_units_string($object->height_units,"size"):''; + } + + print '
'.$form->editfieldkey("Depth",'trueDepth',$object->trueDepth,$object,$user->rights->expedition->creer).''; + print $form->editfieldval("Depth",'trueDepth',$object->trueDepth,$object,$user->rights->expedition->creer); + print ($object->trueDepth && $object->depth_units!='')?' '.measuring_units_string($object->depth_units,"size"):''; + print '
'; + print $langs->trans("Volume"); + print ''; + $calculatedVolume=0; + $volumeUnit=0; + if ($object->trueWidth && $object->trueHeight && $object->trueDepth) + { + $calculatedVolume=($object->trueWidth * $object->trueHeight * $object->trueDepth); + $volumeUnit=$object->size_units * 3; + } + // If sending volume not defined we use sum of products + if ($calculatedVolume > 0) + { + if ($volumeUnit < 50) + { + //print $calculatedVolume.' '.measuring_units_string($volumeUnit,"volume"); + print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + } + else print $calculatedVolume.' '.measuring_units_string($volumeUnit,"volume"); + } + if ($totalVolume > 0) + { + if ($calculatedVolume) print ' ('.$langs->trans("SumOfProductVolumes").': '; + //print $totalVolume.' '.measuring_units_string(0,"volume"); + print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')'; + if ($calculatedVolume) print ')'; + } + print "
'; + + print '
'; + print '
'; + print '
'; + print '
'; + + print ''; + + // Sending method + print ''; + print ''; + + // Tracking Number + print ''; + + // Incoterms + if (!empty($conf->incoterm->enabled)) + { + print ''; + print ''; + } + + print "
'; + print ''; + + if ($action != 'editshipping_method_id') print ''; + print '
'; + print $langs->trans('SendingMethod'); + print 'id.'">'.img_edit($langs->trans('SetSendingMethod'),1).'
'; + print '
'; + if ($action == 'editshipping_method_id') + { + print '
'; + print ''; + print ''; + $object->fetch_delivery_methods(); + print $form->selectarray("shipping_method_id",$object->meths,$object->shipping_method_id,1,0,0,"",1); + if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); + print ''; + print '
'; + } + else + { + if ($object->shipping_method_id > 0) + { + // Get code using getLabelFromKey + $code=$langs->getLabelFromKey($db,$object->shipping_method_id,'c_shipment_mode','rowid','code'); + print $langs->trans("SendingMethod".strtoupper($code)); + } + } + print '
'.$form->editfieldkey("TrackingNumber",'tracking_number',$object->tracking_number,$object,$user->rights->expedition->creer).''; + print $form->editfieldval("TrackingNumber",'tracking_number',$object->tracking_url,$object,$user->rights->expedition->creer,'string',$object->tracking_number); + print '
'; + print '
'; + print $langs->trans('IncotermLabel'); + print ''; + if ($user->rights->expedition->creer) print ''.img_edit().''; + else print ' '; + print '
'; + print '
'; + if ($action != 'editincoterm') + { + print $form->textwithpicto($object->display_incoterms(), $object->libelle_incoterms, 1); + } + else + { + print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms)?$object->location_incoterms:''), $_SERVER['PHP_SELF'].'?id='.$object->id); + } + print '
"; + + print '
'; + print '
'; + print '
'; + + print '
'; + + + // Lines of products + + if ($action == 'editline') + { + print '
+ + + + + '; + } + print '
'; + + print '
'; + print ''; + print ''; + // # + if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) + { + print ''; + } + // Product/Service + print ''; + // Qty + print ''; + if ($origin && $origin_id > 0) + { + print ''; + } + if ($action == 'editline') + { + $editColspan = 3; + if (empty($conf->stock->enabled)) $editColspan--; + if (empty($conf->productbatch->enabled)) $editColspan--; + print ''; + } + else + { + if ($object->statut <= 1) + { + print ''; + } + else + { + print ''; + } + if (! empty($conf->stock->enabled)) + { + print ''; + } + + if (! empty($conf->productbatch->enabled)) + { + print ''; + } + } + print ''; + print ''; + //print ''; + if ($object->statut == 0) + { + print ''; + print ''; + } + print "\n"; + + $var=false; + + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $object->fetch_thirdparty(); + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); + if (empty($newlang)) $newlang=$object->thirdparty->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + } + + // Get list of products already sent for same source object into $alreadysent + $alreadysent = array(); + if ($origin && $origin_id > 0) + { + $sql = "SELECT obj.rowid, obj.fk_product, obj.label, obj.description, obj.product_type as fk_product_type, obj.qty as qty_asked, obj.date_start, obj.date_end"; + $sql.= ", ed.rowid as shipmentline_id, ed.qty as qty_shipped, ed.fk_expedition as expedition_id, ed.fk_origin_line, ed.fk_entrepot"; + $sql.= ", e.rowid as shipment_id, e.ref as shipment_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_expedition"; + //if ($conf->livraison_bon->enabled) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received"; + $sql.= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tobatch as product_tobatch'; + $sql.= ', p.description as product_desc'; + $sql.= " FROM ".MAIN_DB_PREFIX."expeditiondet as ed"; + $sql.= ", ".MAIN_DB_PREFIX."expedition as e"; + $sql.= ", ".MAIN_DB_PREFIX.$origin."det as obj"; + //if ($conf->livraison_bon->enabled) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.fk_expedition = e.rowid LEFT JOIN ".MAIN_DB_PREFIX."livraisondet as ld ON ld.fk_livraison = l.rowid AND obj.rowid = ld.fk_origin_line"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON obj.fk_product = p.rowid"; + $sql.= " WHERE e.entity IN (".getEntity('expedition').")"; + $sql.= " AND obj.fk_".$origin." = ".$origin_id; + $sql.= " AND obj.rowid = ed.fk_origin_line"; + $sql.= " AND ed.fk_expedition = e.rowid"; + //if ($filter) $sql.= $filter; + $sql.= " ORDER BY obj.fk_product"; + + dol_syslog("get list of shipment lines", LOG_DEBUG); + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + + while($i < $num) + { + $obj = $db->fetch_object($resql); + if ($obj) + { + // $obj->rowid is rowid in $origin."det" table + $alreadysent[$obj->rowid][$obj->shipmentline_id]=array('shipment_ref'=>$obj->shipment_ref, 'shipment_id'=>$obj->shipment_id, 'warehouse'=>$obj->fk_entrepot, 'qty_shipped'=>$obj->qty_shipped, 'date_valid'=>$obj->date_valid, 'date_delivery'=>$obj->date_delivery); + } + $i++; + } + } + //var_dump($alreadysent); + } + + // Loop on each product to send/sent + for ($i = 0 ; $i < $num_prod ; $i++) + { + print ''; // id of order line + print ''; + + // # + if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) + { + print ''; + } + + // Predefined product or service + if ($lines[$i]->fk_product > 0) + { + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $prod = new Product($db); + $prod->fetch($lines[$i]->fk_product); + $label = ( ! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product_label; + } + else + $label = (! empty($lines[$i]->label)?$lines[$i]->label:$lines[$i]->product_label); + + print '\n"; + } + else + { + print "\n"; + } + + // Qty ordered + print ''; + + // Qty in other shipments (with shipment and warehouse used) + if ($origin && $origin_id > 0) + { + print ''; + + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + // edit mode + print ''; + } + else + { + // Qty to ship or shipped + print ''; + + // Warehouse source + if (! empty($conf->stock->enabled)) + { + print ''; + } + + // Batch number managment + if (! empty($conf->productbatch->enabled)) + { + if (isset($lines[$i]->detail_batch)) + { + print ''; + print ''; + } else { + print ''; + } + } + } + + // Weight + print ''; + + // Volume + print ''; + + // Size + //print ''; + + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print ''; + print ''; + + // Display lines extrafields + if (! empty($rowExtrafieldsStart)) + { + print $rowExtrafieldsStart; + print $rowExtrafieldsView; + print $rowEnd; + } + } + print ""; + + // Display lines extrafields + if (is_array($extralabelslines) && count($extralabelslines)>0) { + $colspan= empty($conf->productbatch->enabled) ? 5 : 6; + $line = new ExpeditionLigne($db); + $line->fetch_optionals($lines[$i]->id,$extralabelslines); + print ''; + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + else + { + print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + print ''; + } + } + + // TODO Show also lines ordered but not delivered + + print "
 '.$langs->trans("Products").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyInOtherShipments").''; + if ($object->statut <= 1) + { + print $langs->trans("QtyToShip").' - '; + } + else + { + print $langs->trans("QtyShipped").' - '; + } + if (! empty($conf->stock->enabled)) + { + print $langs->trans("WarehouseSource").' - '; + } + if (! empty($conf->productbatch->enabled)) + { + print $langs->trans("Batch"); + } + print ''.$langs->trans("QtyToShip").''.$langs->trans("QtyShipped").''.$langs->trans("WarehouseSource").''.$langs->trans("Batch").''.$langs->trans("CalculatedWeight").''.$langs->trans("CalculatedVolume").''.$langs->trans("Size").'
'.($i+1).''; + + // Show product and description + $product_static->type=$lines[$i]->fk_product_type; + $product_static->id=$lines[$i]->fk_product; + $product_static->ref=$lines[$i]->ref; + $product_static->status_batch=$lines[$i]->product_tobatch; + $text=$product_static->getNomUrl(1); + $text.= ' - '.$label; + $description=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($lines[$i]->description)); + print $form->textwithtooltip($text,$description,3,'','',$i); + print_date_range($lines[$i]->date_start,$lines[$i]->date_end); + if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) + { + print (! empty($lines[$i]->description) && $lines[$i]->description!=$lines[$i]->product)?'
'.dol_htmlentitiesbr($lines[$i]->description):''; + } + print "
"; + if ($lines[$i]->product_type == Product::TYPE_SERVICE) $text = img_object($langs->trans('Service'),'service'); + else $text = img_object($langs->trans('Product'),'product'); + + if (! empty($lines[$i]->label)) { + $text.= ' '.$lines[$i]->label.''; + print $form->textwithtooltip($text,$lines[$i]->description,3,'','',$i); + } else { + print $text.' '.nl2br($lines[$i]->description); + } + + print_date_range($lines[$i]->date_start,$lines[$i]->date_end); + print "'.$lines[$i]->qty_asked.''; + foreach ($alreadysent as $key => $val) + { + if ($lines[$i]->fk_origin_line == $key) + { + $j = 0; + foreach($val as $shipmentline_id=> $shipmentline_var) + { + if ($shipmentline_var['shipment_id'] == $lines[$i]->fk_expedition) continue; // We want to show only "other shipments" + + $j++; + if ($j > 1) print '
'; + $shipment_static->fetch($shipmentline_var['shipment_id']); + print $shipment_static->getNomUrl(1); + print ' - '.$shipmentline_var['qty_shipped']; + $htmltext=$langs->trans("DateValidation").' : '.(empty($shipmentline_var['date_valid'])?$langs->trans("Draft"):dol_print_date($shipmentline_var['date_valid'], 'dayhour')); + if (! empty($conf->stock->enabled) && $shipmentline_var['warehouse'] > 0) + { + $warehousestatic->fetch($shipmentline_var['warehouse']); + $htmltext .= '
'.$langs->trans("From").' : '.$warehousestatic->getNomUrl(1); + } + print ' '.$form->textwithpicto('', $htmltext, 1); + } + } + } + } + print '
'; + if (is_array($lines[$i]->detail_batch) && count($lines[$i]->detail_batch) > 0) + { + print ''; + $line = new ExpeditionLigne($db); + foreach ($lines[$i]->detail_batch as $detail_batch) + { + print ''; + // Qty to ship or shipped + print ''; + // Batch number managment + if ($lines[$i]->entrepot_id == 0) + { + // only show lot numbers from src warehouse when shipping from multiple warehouses + $line->fetch($detail_batch->fk_expeditiondet); + } + print ''; + print ''; + } + // add a 0 qty lot row to be able to add a lot + print ''; + // Qty to ship or shipped + print ''; + // Batch number managment + print ''; + print ''; + } + else if (! empty($conf->stock->enabled)) + { + if ($lines[$i]->fk_product > 0) + { + if ($lines[$i]->entrepot_id > 0) + { + print ''; + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + else if (count($lines[$i]->details_entrepot) > 1) + { + print ''; + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + else + { + print ''; + print ''; + } + } + else + { + print ''; + print ''; + // Qty to ship or shipped + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + print '
' . '' . '' . $formproduct->selectLotStock($detail_batch->fk_origin_stock, 'batchl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->fk_origin_stock, '', 1, 0, $lines[$i]->fk_product, $line->entrepot_id). '
' . '' . '' . $formproduct->selectLotStock('', 'batchl'.$line_id.'_0', '', 1, 0, $lines[$i]->fk_product). '
' . '' . '' . $formproduct->selectWarehouses($lines[$i]->entrepot_id, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1). ' - ' . $langs->trans("NA") . '
' . '' . '' . $formproduct->selectWarehouses($detail_entrepot->entrepot_id, 'entl'.$detail_entrepot->line_id, '', 1, 0, $lines[$i]->fk_product, '', 1) . ' - ' . $langs->trans("NA") . '
'.$langs->trans("NotEnoughStock").'
' . '' . '' . '' . '
'.$lines[$i]->qty_shipped.''; + if ($lines[$i]->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($lines[$i]->entrepot_id); + print $entrepot->getNomUrl(1); + } + else if (count($lines[$i]->details_entrepot) > 1) + { + $detail = ''; + foreach ($lines[$i]->details_entrepot as $detail_entrepot) + { + if ($detail_entrepot->entrepot_id > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($detail_entrepot->entrepot_id); + $detail.= $langs->trans("DetailWarehouseFormat",$entrepot->libelle,$detail_entrepot->qty_shipped).'
'; + } + } + print $form->textwithtooltip(img_picto('', 'object_stock').' '.$langs->trans("DetailWarehouseNumber"),$detail); + } + print '
'; + if ($lines[$i]->product_tobatch) + { + $detail = ''; + foreach ($lines[$i]->detail_batch as $dbatch) + { + $detail.= $langs->trans("Batch").': '.$dbatch->batch; + $detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day"); + $detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day"); + $detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty; + $detail.= '
'; + } + print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); + } + else + { + print $langs->trans("NA"); + } + print '
'; + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->weight*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->weight_units,"weight"); + else print ' '; + print ''; + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume"); + else print ' '; + print ''.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume").''; + print '
'; + print '
'; + } + else if ($object->statut == 0) + { + // edit-delete buttons + print '
'; + print 'id . '">' . img_edit() . ''; + print ''; + print 'id . '">' . img_delete() . ''; + print '
\n"; + print '
'; + } + + + dol_fiche_end(); + + + $object->fetchObjectLinked($object->id,$object->element); + + + /* + * Boutons actions + */ + + if (($user->societe_id == 0) && ($action!='presend')) + { + print '
'; + + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been + // modified by hook + if (empty($reshook)) + { + + if ($object->statut == Expedition::STATUS_DRAFT && $num_prod > 0) + { + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate))) + { + print ''.$langs->trans("Validate").''; + } + else + { + print ''.$langs->trans("Validate").''; + } + } + // Edit + if ($object->statut == Expedition::STATUS_VALIDATED && $user->rights->expedition->creer) { + print ''; + } + + // TODO add alternative status + // 0=draft, 1=validated, 2=billed, we miss a status "delivered" (only available on order) + if ($object->statut == Expedition::STATUS_CLOSED && $user->rights->expedition->creer) + { + if (! empty($conf->facture->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + { + print ''.$langs->trans("ClassifyUnbilled").''; + } + else + { + print ''.$langs->trans("ReOpen").''; + } + } + + // Send + if ($object->statut > 0) + { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->expedition->shipping_advance->send) + { + print ''.$langs->trans('SendByMail').''; + } + else print ''.$langs->trans('SendByMail').''; + } + + // Create bill + if (! empty($conf->facture->enabled) && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED)) + { + if ($user->rights->facture->creer) + { + // TODO show button only if (! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) + // If we do that, we must also make this option official. + print ''.$langs->trans("CreateBill").''; + } + } + + // This is just to generate a delivery receipt + //var_dump($object->linkedObjectsIds['delivery']); + if ($conf->livraison_bon->enabled && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED) && $user->rights->expedition->livraison->creer && count($object->linkedObjectsIds['delivery']) == 0) + { + print ''.$langs->trans("CreateDeliveryOrder").''; + } + // Close + if ($object->statut == Expedition::STATUS_VALIDATED) + { + if ($user->rights->expedition->creer && $object->statut > 0 && ! $object->billed) + { + $label="Close"; $paramaction='classifyclosed'; // = Transferred/Received + // Label here should be "Close" or "ClassifyBilled" if we decided to make bill on shipments instead of orders + if (! empty($conf->facture->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + { + $label="ClassifyBilled"; + $paramaction='classifybilled'; + } + print ''.$langs->trans($label).''; + } + } + + if ($user->rights->expedition->supprimer) + { + print ''.$langs->trans("Delete").''; + } + + } + + print '
'; + } + + + /* + * Documents generated + */ + + if ($action != 'presend' && $action != 'editline') + { + print '
'; + + $objectref = dol_sanitizeFileName($object->ref); + $filedir = $conf->expedition->dir_output . "/sending/" .$objectref; + + $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; + + $genallowed=$user->rights->expedition->lire; + $delallowed=$user->rights->expedition->creer; + + print $formfile->showdocuments('expedition',$objectref,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'','','',$soc->default_lang); + + + // Show links to link elements + //$linktoelem = $form->showLinkToObjectBlock($object, null, array('order')); + $somethingshown = $form->showLinkedObjectBlock($object, ''); + + + print '
'; + + } + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } + if ($action == 'presend') + { + $ref = dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + $fileparams = dol_most_recent_file($conf->expedition->dir_output . '/sending/' . $ref, preg_quote($ref, '/').'[^\-]+'); + $file=$fileparams['fullname']; + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) + $newlang = $_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (!empty($newlang)) + { + $outputlangs = new Translate('', $conf); + $outputlangs->setDefaultLang($newlang); + $outputlangs->load('sendings'); + } + // Build document if it not exists + if (! $file || ! is_readable($file)) + { + $result = $object->generateDocument(GETPOST('model')?GETPOST('model'):$object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + dol_print_error($db,$object->error,$object->errors); + exit; + } + $fileparams = dol_most_recent_file($conf->expedition->dir_output . '/sending/' . $ref, preg_quote($ref, '/').'[^\-]+'); + $file=$fileparams['fullname']; + } + print '
'; + print '
'; + print '
'; + print load_fiche_titre($langs->trans('SendShippingByEMail')); + dol_fiche_head(''); + // Cree l'objet formulaire mail + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + $formmail->param['langsmodels']=(empty($newlang)?$langs->defaultlang:$newlang); + $formmail->fromtype = (GETPOST('fromtype')?GETPOST('fromtype'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user')); + if($formmail->fromtype === 'user'){ + $formmail->fromid = $user->id; + } + $formmail->trackid='shi'.$object->id; + if (! empty($conf->global->MAIN_EMAIL_ADD_TRACK_ID) && ($conf->global->MAIN_EMAIL_ADD_TRACK_ID & 2)) // If bit 2 is set + { + include DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $formmail->frommail=dolAddEmailTrackId($formmail->frommail, 'shi'.$object->id); + } + $formmail->withfrom=1; + $liste=array(); + foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key=>$value) $liste[$key]=$value; + $formmail->withto=GETPOST("sendto")?GETPOST("sendto"):$liste; + $formmail->withtocc=$liste; + $formmail->withtoccc=$conf->global->MAIN_EMAIL_USECCC; + $formmail->withtopic=$outputlangs->trans('SendShippingRef','__SHIPPINGREF__'); + $formmail->withfile=2; + $formmail->withbody=1; + $formmail->withdeliveryreceipt=1; + $formmail->withcancel=1; + // Tableau des substitutions + $formmail->setSubstitFromObject($object); + $formmail->substit['__SHIPPINGREF__']=$object->ref; + $formmail->substit['__SHIPPINGTRACKNUM__']=$object->tracking_number; + $formmail->substit['__SHIPPINGTRACKNUMURL__']=$object->tracking_url; + //Find the good contact adress + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } + $custcontact=''; + $contactarr=array(); + if (is_object($objectsrc)) // For the case the shipment was created without orders + { + $contactarr=$objectsrc->liste_contact(-1,'external'); + } + if (is_array($contactarr) && count($contactarr)>0) { + foreach($contactarr as $contact) { + if ($contact['libelle']==$langs->trans('TypeContact_commande_external_CUSTOMER')) { + require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; + $contactstatic=new Contact($db); + $contactstatic->fetch($contact['id']); + $custcontact=$contactstatic->getFullName($langs,1); + } + } + if (!empty($custcontact)) { + $formmail->substit['__CONTACTCIVNAME__']=$custcontact; + } + } + // Tableau des parametres complementaires + $formmail->param['action']='send'; + $formmail->param['models']='shipping_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); + $formmail->param['shippingid']=$object->id; + $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; + // Init list of files + if (GETPOST("mode")=='init') + { + $formmail->clear_attached_files(); + $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); + } + // Show form + print $formmail->get_form(); + dol_fiche_end(); + } + + + +} + + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/class/expeditionbatch.class.php b/htdocs/reception/class/expeditionbatch.class.php new file mode 100644 index 00000000000..5253156e32a --- /dev/null +++ b/htdocs/reception/class/expeditionbatch.class.php @@ -0,0 +1,223 @@ + + * Copyright (C) 2013-2014 Cedric GROSS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file expedition/class/expeditionbatch.class.php + * \ingroup productbatch + * \brief This file implements CRUD method for managing shipment batch lines + * with batch record + */ + +/** + * CRUD class for batch number management within shipment + */ +class ExpeditionLineBatch extends CommonObject +{ + var $element='expeditionlignebatch'; //!< Id that identify managed objects + private static $_table_element='expeditiondet_batch'; //!< Name of table without prefix where object is stored + + var $sellby; + var $eatby; + var $batch; + var $dluo_qty; + var $entrepot_id; + var $fk_origin_stock; + var $fk_expeditiondet; + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + function __construct($db) + { + $this->db = $db; + return 1; + } + + /** + * Fill object based on a product-warehouse-batch's record + * + * @param int $id_stockdluo Rowid in product_batch table + * @return int -1 if KO, 1 if OK + */ + function fetchFromStock($id_stockdluo) + { + $sql = "SELECT"; + $sql.= " t.sellby,"; + $sql.= " t.eatby,"; + $sql.= " t.batch,"; + $sql.= " e.fk_entrepot"; + + $sql.= " FROM ".MAIN_DB_PREFIX."product_batch as t inner join "; + $sql.= MAIN_DB_PREFIX."product_stock as e on t.fk_product_stock=e.rowid "; + $sql.= " WHERE t.rowid = ".(int) $id_stockdluo; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->sellby = $this->db->jdate($obj->sellby); + $this->eatby = $this->db->jdate($obj->eatby); + $this->batch = $obj->batch; + $this->entrepot_id= $obj->fk_entrepot; + $this->fk_origin_stock=(int) $id_stockdluo; + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + return -1; + } + } + + /** + * Create an expeditiondet_batch DB record link to an expedtiondet record + * + * @param int $id_line_expdet rowid of expedtiondet record + * @return int <0 if KO, Id of record (>0) if OK + */ + function create($id_line_expdet) + { + $error = 0; + + $id_line_expdet = (int) $id_line_expdet; + + $sql = "INSERT INTO ".MAIN_DB_PREFIX.self::$_table_element." ("; + $sql.= "fk_expeditiondet"; + $sql.= ", sellby"; + $sql.= ", eatby"; + $sql.= ", batch"; + $sql.= ", qty"; + $sql.= ", fk_origin_stock"; + $sql.= ") VALUES ("; + $sql.= $id_line_expdet.","; + $sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':("'".$this->db->idate($this->sellby))."'").","; + $sql.= " ".(! isset($this->eatby) || dol_strlen($this->eatby)==0?'NULL':("'".$this->db->idate($this->eatby))."'").","; + $sql.= " ".(! isset($this->batch)?'NULL':("'".$this->db->escape($this->batch)."'")).","; + $sql.= " ".(! isset($this->dluo_qty)?'NULL':$this->dluo_qty).","; + $sql.= " ".(! isset($this->fk_origin_stock)?'NULL':$this->fk_origin_stock); + $sql.= ")"; + + dol_syslog(__METHOD__, LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + + if (! $error) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.self::$_table_element); + $this->fk_expeditiondet=$id_line_expdet; + return $this->id; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + /** + * Delete batch record attach to a shipment + * + * @param DoliDB $db Database object + * @param int $id_expedition rowid of shipment + * @return int -1 if KO, 1 if OK + */ + static function deletefromexp($db,$id_expedition) + { + $id_expedition = (int) $id_expedition; + + $sql="DELETE FROM ".MAIN_DB_PREFIX.self::$_table_element; + $sql.=" WHERE fk_expeditiondet in (SELECT rowid FROM ".MAIN_DB_PREFIX."expeditiondet WHERE fk_expedition=".$id_expedition.")"; + + dol_syslog(__METHOD__, LOG_DEBUG); + if ($db->query($sql)) + { + return 1; + } + else + { + return -1; + } + } + + /** + * Retrieve all batch number details link to a shipment line + * + * @param DoliDB $db Database object + * @param int $id_line_expdet id of shipment line + * @return variant -1 if KO, array of ExpeditionLineBatch if OK + */ + static function fetchAll($db,$id_line_expdet) + { + $sql="SELECT rowid,"; + $sql.= "fk_expeditiondet"; + $sql.= ", sellby"; + $sql.= ", eatby"; + $sql.= ", batch"; + $sql.= ", qty"; + $sql.= ", fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX.self::$_table_element; + $sql.= " WHERE fk_expeditiondet=".(int) $id_line_expdet; + + dol_syslog(__METHOD__ ."", LOG_DEBUG); + $resql=$db->query($sql); + if ($resql) + { + $num=$db->num_rows($resql); + $i=0; + $ret = array(); + while ($i<$num) + { + $tmp=new self($db); + + $obj = $db->fetch_object($resql); + + $tmp->sellby = $db->jdate($obj->sellby); + $tmp->eatby = $db->jdate($obj->eatby); + $tmp->batch = $obj->batch; + $tmp->id = $obj->rowid; + $tmp->fk_origin_stock = $obj->fk_origin_stock; + $tmp->fk_expeditiondet = $obj->fk_expeditiondet; + $tmp->dluo_qty = $obj->qty; + + $ret[]=$tmp; + $i++; + } + $db->free($resql); + return $ret; + } + else + { + return -1; + } + } + +} diff --git a/htdocs/reception/class/expeditionstats.class.php b/htdocs/reception/class/expeditionstats.class.php new file mode 100644 index 00000000000..7fa16f4210f --- /dev/null +++ b/htdocs/reception/class/expeditionstats.class.php @@ -0,0 +1,142 @@ + + * Copyright (c) 2005-2013 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2011 Juanjo Menent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/class/expeditionstats.class.php + * \ingroup expedition + * \brief File of class fo tmanage shipment statistics + */ + +include_once DOL_DOCUMENT_ROOT . '/core/class/stats.class.php'; +include_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php'; +include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + + +/** + * Class to manage shipment statistics + */ +class ExpeditionStats extends Stats +{ + public $table_element; + + var $socid; + var $userid; + + var $from; + var $field; + var $where; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party for filter + * @param string $mode Option (not used) + * @param int $userid Id user for filter (creation user) + */ + function __construct($db, $socid, $mode, $userid=0) + { + global $user, $conf; + + $this->db = $db; + + $this->socid = ($socid > 0 ? $socid : 0); + $this->userid = $userid; + $this->cachefilesuffix = $mode; + + $object=new Expedition($this->db); + $this->from = MAIN_DB_PREFIX.$object->table_element." as c"; + //$this->from.= ", ".MAIN_DB_PREFIX."societe as s"; + $this->field='weight'; // Warning, unit of weight is NOT USED AND MUST BE + $this->where.= " c.fk_statut > 0"; // Not draft and not cancelled + + //$this->where.= " AND c.fk_soc = s.rowid AND c.entity = ".$conf->entity; + $this->where.= " AND c.entity = ".$conf->entity; + if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($this->socid) + { + $this->where.=" AND c.fk_soc = ".$this->socid; + } + if ($this->userid > 0) $this->where.=' AND c.fk_user_author = '.$this->userid; + } + + /** + * Return shipment number by month for a year + * + * @param int $year Year to scan + * @return array Array with number by month + */ + function getNbByMonth($year) + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%m') as dm, COUNT(*) as nb"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.date_valid BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; + $sql.= " AND ".$this->where; + $sql.= " GROUP BY dm"; + $sql.= $this->db->order('dm','DESC'); + + $res=$this->_getNbByMonth($year, $sql); + return $res; + } + + /** + * Return shipments number per year + * + * @return array Array with number by year + * + */ + function getNbByYear() + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%Y') as dm, COUNT(*) as nb, SUM(c.".$this->field.")"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE ".$this->where; + $sql.= " GROUP BY dm"; + $sql.= $this->db->order('dm','DESC'); + + return $this->_getNbByYear($sql); + } + + /** + * Return nb, total and average + * + * @return array Array of values + */ + function getAllByYear() + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%Y') as year, COUNT(*) as nb, SUM(c.".$this->field.") as total, AVG(".$this->field.") as avg"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE ".$this->where; + $sql.= " GROUP BY year"; + $sql.= $this->db->order('year','DESC'); + + return $this->_getAllByYear($sql); + } +} + diff --git a/htdocs/reception/class/index.html b/htdocs/reception/class/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php new file mode 100644 index 00000000000..324714fee7c --- /dev/null +++ b/htdocs/reception/class/reception.class.php @@ -0,0 +1,2824 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2007 Franky Van Liedekerke + * Copyright (C) 2006-2012 Laurent Destailleur + * Copyright (C) 2011-2017 Juanjo Menent + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2014 Cedric GROSS + * Copyright (C) 2014-2015 Marcos García + * Copyright (C) 2014-2015 Francis Appels + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2016 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/reception/class/reception.class.php + * \ingroup reception + * \brief Fichier de la classe de gestion des receptions + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php"; +if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionbatch.class.php'; + + +/** + * Class to manage receptions + */ +class Reception extends CommonObject +{ + public $element="reception"; + public $fk_element="fk_reception"; + public $table_element="reception"; + public $table_element_line="receptiondet"; + protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + public $picto = 'reception'; + + var $socid; + var $ref_customer; + var $ref_int; + var $brouillon; + var $entrepot_id; + var $lines=array(); + var $tracking_number; + var $tracking_url; + var $billed; + var $model_pdf; + + var $trueWeight; + var $weight_units; + var $trueWidth; + var $width_units; + var $trueHeight; + var $height_units; + var $trueDepth; + var $depth_units; + // A denormalized value + var $trueSize; + + var $date_delivery; // Date delivery planed + /** + * @deprecated + * @see date_reception + */ + var $date; + + /** + * Effective delivery date + * @var int + */ + public $date_reception; + var $date_creation; + var $date_valid; + + var $meths; + var $listmeths; // List of carriers + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CLOSED = 2; + + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db = $db; + $this->lines = array(); + $this->products = array(); + + // List of long language codes for status + $this->statuts = array(); + $this->statuts[-1] = 'StatusReceptionCanceled'; + $this->statuts[0] = 'StatusReceptionDraft'; + $this->statuts[1] = 'StatusReceptionValidated'; + $this->statuts[2] = 'StatusReceptionProcessed'; + } + + /** + * Return next contract ref + * + * @param Societe $soc Thirdparty object + * @return string Free reference for contract + */ + function getNextNumRef($soc) + { + global $langs, $conf; + $langs->load("receptions"); + + if (!empty($conf->global->RECEPTION_ADDON_NUMBER)) + { + $mybool = false; + + $file = $conf->global->RECEPTION_ADDON_NUMBER.".php"; + $classname = $conf->global->RECEPTION_ADDON_NUMBER; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + + foreach ($dirmodels as $reldir) { + + $dir = dol_buildpath($reldir."core/modules/reception/"); + + // Load file with numbering class (if found) + $mybool|=@include_once $dir.$file; + } + + if (! $mybool) + { + dol_print_error('',"Failed to include file ".$file); + return ''; + } + + $obj = new $classname(); + $numref = ""; + $numref = $obj->getNextValue($soc,$this); + + if ( $numref != "") + { + return $numref; + } + else + { + dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } + else + { + print $langs->trans("Error")." ".$langs->trans("Error_RECEPTION_ADDON_NUMBER_NotDefined"); + return ""; + } + } + + /** + * Create reception en base + * + * @param User $user Objet du user qui cree + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <0 si erreur, id reception creee si ok + */ + function create($user, $notrigger=0) + { + global $conf, $hookmanager; + + $now=dol_now(); + + require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php'; + $error = 0; + + // Clean parameters + $this->brouillon = 1; + $this->tracking_number = dol_sanitizeFileName($this->tracking_number); + if (empty($this->fk_project)) $this->fk_project = 0; + + $this->user = $user; + + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."reception ("; + $sql.= "ref"; + $sql.= ", entity"; + $sql.= ", ref_customer"; + $sql.= ", ref_int"; + $sql.= ", date_creation"; + $sql.= ", fk_user_author"; + $sql.= ", date_reception"; + $sql.= ", date_delivery"; + $sql.= ", fk_soc"; + $sql.= ", fk_projet"; + $sql.= ", fk_address"; + $sql.= ", fk_reception_method"; + $sql.= ", tracking_number"; + $sql.= ", weight"; + $sql.= ", size"; + $sql.= ", width"; + $sql.= ", height"; + $sql.= ", weight_units"; + $sql.= ", size_units"; + $sql.= ", note_private"; + $sql.= ", note_public"; + $sql.= ", model_pdf"; + $sql.= ", fk_incoterms, location_incoterms"; + $sql.= ") VALUES ("; + $sql.= "'(PROV)'"; + $sql.= ", ".$conf->entity; + $sql.= ", ".($this->ref_customer?"'".$this->db->escape($this->ref_customer)."'":"null"); + $sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null"); + $sql.= ", '".$this->db->idate($now)."'"; + $sql.= ", ".$user->id; + $sql.= ", ".($this->date_reception>0?"'".$this->db->idate($this->date_reception)."'":"null"); + $sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null"); + $sql.= ", ".$this->socid; + $sql.= ", ".$this->fk_project; + $sql.= ", ".($this->fk_delivery_address>0?$this->fk_delivery_address:"null"); + $sql.= ", ".($this->reception_method_id>0?$this->reception_method_id:"null"); + $sql.= ", '".$this->db->escape($this->tracking_number)."'"; + $sql.= ", ".$this->weight; + $sql.= ", ".$this->sizeS; // TODO Should use this->trueDepth + $sql.= ", ".$this->sizeW; // TODO Should use this->trueWidth + $sql.= ", ".$this->sizeH; // TODO Should use this->trueHeight + $sql.= ", ".$this->weight_units; + $sql.= ", ".$this->size_units; + $sql.= ", ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null"); + $sql.= ", ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null"); + $sql.= ", ".(!empty($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null"); + $sql.= ", ".(int) $this->fk_incoterms; + $sql.= ", '".$this->db->escape($this->location_incoterms)."'"; + $sql.= ")"; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."reception"); + + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET ref = '(PROV".$this->id.")'"; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + if ($this->db->query($sql)) + { + // Insertion des lignes + $num=count($this->lines); + for ($i = 0; $i < $num; $i++) + { + if (! isset($this->lines[$i]->detail_batch)) + { // no batch management + if (! $this->create_line($this->lines[$i]->entrepot_id, $this->lines[$i]->origin_line_id, $this->lines[$i]->qty, $this->lines[$i]->array_options) > 0) + { + $error++; + } + } + else + { // with batch management + if (! $this->create_line_batch($this->lines[$i],$this->lines[$i]->array_options) > 0) + { + $error++; + } + } + } + + if (! $error && $this->id && $this->origin_id) + { + $ret = $this->add_object_linked(); + if (!$ret) + { + $error++; + } + } + + // Actions on extra fields (by external module or standard code) + // TODO le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('receptiondao')); + $parameters=array('socid'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_CREATE',$user); + if ($result < 0) { $error++; } + // End call triggers + + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + + } + else + { + $error++; + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -3; + } + } + else + { + $error++; + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -2; + } + } + else + { + $error++; + $this->error=$this->db->error()." - sql=$sql"; + $this->db->rollback(); + return -1; + } + } + + /** + * Create a reception line + * + * @param int $entrepot_id Id of warehouse + * @param int $origin_line_id Id of source line + * @param int $qty Quantity + * @param array $array_options extrafields array + * @return int <0 if KO, line_id if OK + */ + function create_line($entrepot_id, $origin_line_id, $qty,$array_options=0) + { + global $conf; + $error = 0; + $line_id = 0; + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."receptiondet ("; + $sql.= "fk_reception"; + $sql.= ", fk_entrepot"; + $sql.= ", fk_origin_line"; + $sql.= ", qty"; + $sql.= ") VALUES ("; + $sql.= $this->id; + $sql.= ", ".($entrepot_id?$entrepot_id:'null'); + $sql.= ", ".$origin_line_id; + $sql.= ", ".$qty; + $sql.= ")"; + + dol_syslog(get_class($this)."::create_line", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $line_id = $this->db->last_insert_id(MAIN_DB_PREFIX."receptiondet"); + } + else + { + $error++; + } + + if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used + { + $receptionline = new ReceptionLigne($this->db); + $receptionline->array_options=$array_options; + $receptionline->id= $this->db->last_insert_id(MAIN_DB_PREFIX.$receptionline->table_element); + $result=$receptionline->insertExtraFields(); + if ($result < 0) + { + $this->error[]=$receptionline->error; + $error++; + } + } + + if (! $error) return $line_id; + else return -1; + } + + + /** + * Create the detail (eat-by date) of the reception line + * + * @param object $line_ext full line informations + * @param array $array_options extrafields array + * @return int <0 if KO, >0 if OK + */ + function create_line_batch($line_ext,$array_options=0) + { + $error = 0; + $stockLocationQty = array(); // associated array with batch qty in stock location + + $tab=$line_ext->detail_batch; + // create stockLocation Qty array + foreach ($tab as $detbatch) + { + if ($detbatch->entrepot_id) + { + $stockLocationQty[$detbatch->entrepot_id] += $detbatch->dluo_qty; + } + } + // create reception lines + foreach ($stockLocationQty as $stockLocation => $qty) + { + if (($line_id = $this->create_line($stockLocation,$line_ext->origin_line_id,$qty,$array_options)) < 0) + { + $error++; + } + else + { + // create reception batch lines for stockLocation + foreach ($tab as $detbatch) + { + if ($detbatch->entrepot_id == $stockLocation){ + if (! ($detbatch->create($line_id) >0)) // Create an receptionlinebatch + { + $error++; + } + } + } + } + } + + if (! $error) return 1; + else return -1; + } + + /** + * Get object and lines from database + * + * @param int $id Id of object to load + * @param string $ref Ref of object + * @param string $ref_ext External reference of object + * @param string $ref_int Internal reference of other object + * @return int >0 if OK, 0 if not found, <0 if KO + */ + function fetch($id, $ref='', $ref_ext='', $ref_int='') + { + global $conf; + + // Check parameters + if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; + + $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut"; + $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height"; + $sql.= ", e.date_reception as date_reception, e.model_pdf, e.fk_address, e.date_delivery"; + $sql.= ", e.fk_reception_method, e.tracking_number"; + $sql.= ", el.fk_source as origin_id, el.sourcetype as origin"; + $sql.= ", e.note_private, e.note_public"; + $sql.= ', e.fk_incoterms, e.location_incoterms'; + $sql.= ', i.libelle as libelle_incoterms'; + $sql.= " FROM ".MAIN_DB_PREFIX."reception as e"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'"; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid'; + $sql.= " WHERE e.entity IN (".getEntity('reception').")"; + if ($id) $sql.= " AND e.rowid=".$id; + if ($ref) $sql.= " AND e.ref='".$this->db->escape($ref)."'"; + if ($ref_ext) $sql.= " AND e.ref_ext='".$this->db->escape($ref_ext)."'"; + if ($ref_int) $sql.= " AND e.ref_int='".$this->db->escape($ref_int)."'"; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + $this->ref = $obj->ref; + $this->socid = $obj->socid; + $this->ref_customer = $obj->ref_customer; + $this->ref_ext = $obj->ref_ext; + $this->ref_int = $obj->ref_int; + $this->statut = $obj->fk_statut; + $this->user_author_id = $obj->fk_user_author; + $this->date_creation = $this->db->jdate($obj->date_creation); + $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated + $this->date_reception = $this->db->jdate($obj->date_reception); // TODO deprecated + $this->date_reception = $this->db->jdate($obj->date_reception); // Date real + $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed + $this->fk_delivery_address = $obj->fk_address; + $this->modelpdf = $obj->model_pdf; + $this->reception_method_id = $obj->fk_reception_method; + $this->tracking_number = $obj->tracking_number; + $this->origin = ($obj->origin?$obj->origin:'commande'); // For compatibility + $this->origin_id = $obj->origin_id; + $this->billed = ($obj->fk_statut==2?1:0); + + $this->trueWeight = $obj->weight; + $this->weight_units = $obj->weight_units; + + $this->trueWidth = $obj->width; + $this->width_units = $obj->size_units; + $this->trueHeight = $obj->height; + $this->height_units = $obj->size_units; + $this->trueDepth = $obj->size; + $this->depth_units = $obj->size_units; + + $this->note_public = $obj->note_public; + $this->note_private = $obj->note_private; + + // A denormalized value + $this->trueSize = $obj->size."x".$obj->width."x".$obj->height; + $this->size_units = $obj->size_units; + + //Incoterms + $this->fk_incoterms = $obj->fk_incoterms; + $this->location_incoterms = $obj->location_incoterms; + $this->libelle_incoterms = $obj->libelle_incoterms; + + $this->db->free($result); + + if ($this->statut == 0) $this->brouillon = 1; + + $file = $conf->reception->dir_output . "/" .get_exdir($this->id, 2, 0, 0, $this, 'reception') . "/" . $this->id.".pdf"; + $this->pdf_filename = $file; + + // Tracking url + $this->GetUrlTrackingStatus($obj->tracking_number); + + /* + * Thirparty + */ + $result=$this->fetch_thirdparty(); + + // Retrieve all extrafields for reception + // fetch optionals attributes and labels + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true); + $this->fetch_optionals($this->id,$extralabels); + + /* + * Lines + */ + $result=$this->fetch_lines(); + if ($result < 0) + { + return -3; + } + + return 1; + } + else + { + dol_syslog(get_class($this).'::Fetch no reception found', LOG_ERR); + $this->error='Delivery with id '.$id.' not found'; + return 0; + } + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Validate object and update stock if option enabled + * + * @param User $user Object user that validate + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <0 if OK, >0 if KO + */ + function valid($user, $notrigger=0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + dol_syslog(get_class($this)."::valid"); + + // Protection + if ($this->statut) + { + dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING); + return 0; + } + + if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate)))) + { + $this->error='Permission denied'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + } + + $this->db->begin(); + + $error = 0; + + // Define new ref + $soc = new Societe($this->db); + $soc->fetch($this->socid); + + // Class of company linked to order + $result=$soc->set_as_client(); + + // Define new ref + if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life + { + $numref = $this->getNextNumRef($soc); + } + else { + $numref = $this->ref; + } + $this->newref = $numref; + + $now=dol_now(); + + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET"; + $sql.= " ref='".$numref."'"; + $sql.= ", fk_statut = 1"; + $sql.= ", date_valid = '".$this->db->idate($now)."'"; + $sql.= ", fk_user_valid = ".$user->id; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::valid update reception", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $error++; + } + + // If stock increment is done on reception (recommanded choice) + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO in future, reception lines may not be linked to order line + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."receptiondet as ed"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."receptiondet_batch as edb on edb.fk_receptiondet = ed.rowid"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) + { + $qty = $obj->qty; + } + else + { + $qty = $obj->edbqty; + } + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->edbrowid)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr",$numref)); + if ($result < 0) { + $error++; + $this->errors[]=$mouvS->error; + $this->errors = array_merge($this->errors, $mouvS->errors); + break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. + // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version) + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $error++; + $this->errors[]=$mouvS->error; + $this->errors = array_merge($this->errors, $mouvS->errors); + break; + } + } + } + } + else + { + $this->db->rollback(); + $this->error=$this->db->error(); + return -2; + } + + } + + // Change status of order to "reception in process" + $ret = $this->setStatut(Commande::STATUS_RECEPTIONONPROCESS, $this->origin_id, $this->origin); + + if (! $ret) + { + $error++; + } + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_VALIDATE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + if (! $error) + { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) + { + // On renomme repertoire ($this->ref = ancienne ref, $numfa = nouvelle ref) + // in order not to lose the attached files + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($numref); + $dirsource = $conf->reception->dir_output.'/reception/'.$oldref; + $dirdest = $conf->reception->dir_output.'/reception/'.$newref; + if (file_exists($dirsource)) + { + dol_syslog(get_class($this)."::valid rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) + { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles=dol_dir_list($conf->reception->dir_output.'/reception/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/')); + foreach($listoffiles as $fileentry) + { + $dirsource=$fileentry['name']; + $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource); + $dirsource=$fileentry['path'].'/'.$dirsource; + $dirdest=$fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + } + + // Set new ref and current status + if (! $error) + { + $this->ref = $numref; + $this->statut = 1; + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + + /** + * Create a delivery receipt from a reception + * + * @param User $user User + * @return int <0 if KO, >=0 if OK + */ + function create_delivery($user) + { + global $conf; + + if ($conf->livraison_bon->enabled) + { + if ($this->statut == 1 || $this->statut == 2) + { + // Reception validee + include_once DOL_DOCUMENT_ROOT.'/livraison/class/livraison.class.php'; + $delivery = new Livraison($this->db); + $result=$delivery->create_from_reception($user, $this->id); + if ($result > 0) + { + return $result; + } + else + { + $this->error=$delivery->error; + return $result; + } + } + else return 0; + } + else return 0; + } + + /** + * Add an reception line. + * If STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS is set, you can add a reception line, with no stock source defined + * If STOCK_MUST_BE_ENOUGH_FOR_RECEPTION is not set, you can add a reception line, even if not enough into stock + * + * @param int $entrepot_id Id of warehouse + * @param int $id Id of source line (order line) + * @param int $qty Quantity + * @param array $array_options extrafields array + * @return int <0 if KO, >0 if OK + */ + function addline($entrepot_id, $id, $qty,$array_options=0) + { + global $conf, $langs; + + $num = count($this->lines); + $line = new ReceptionLigne($this->db); + + $line->entrepot_id = $entrepot_id; + $line->origin_line_id = $id; + $line->qty = $qty; + + $orderline = new OrderLine($this->db); + $orderline->fetch($id); + + if (! empty($conf->stock->enabled) && ! empty($orderline->fk_product)) + { + $fk_product = $orderline->fk_product; + + if (! ($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS)) + { + $langs->load("errors"); + $this->error=$langs->trans("ErrorWarehouseRequiredIntoReceptionLine"); + return -1; + } + + if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_RECEPTION) + { + // Check must be done for stock of product into warehouse if $entrepot_id defined + $product=new Product($this->db); + $result=$product->fetch($fk_product); + + if ($entrepot_id > 0) { + $product->load_stock('warehouseopen'); + $product_stock = $product->stock_warehouse[$entrepot_id]->real; + } + else + $product_stock = $product->stock_reel; + + $product_type=$product->type; + if ($product_type == 0 && $product_stock < $qty) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorStockIsNotEnoughToAddProductOnReception', $product->ref); + $this->db->rollback(); + return -3; + } + } + } + + // If product need a batch number, we should not have called this function but addline_batch instead. + if (! empty($conf->productbatch->enabled) && ! empty($orderline->fk_product) && ! empty($orderline->product_tobatch)) + { + $this->error='ADDLINE_WAS_CALLED_INSTEAD_OF_ADDLINEBATCH'; + return -4; + } + + // extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used + $line->array_options = $array_options; + + $this->lines[$num] = $line; + } + + /** + * Add a reception line with batch record + * + * @param array $dbatch Array of value (key 'detail' -> Array, key 'qty' total quantity for line, key ix_l : original line index) + * @param array $array_options extrafields array + * @return int <0 if KO, >0 if OK + */ + function addline_batch($dbatch,$array_options=0) + { + global $conf,$langs; + + $num = count($this->lines); + if ($dbatch['qty']>0) + { + $line = new ReceptionLigne($this->db); + $tab=array(); + foreach ($dbatch['detail'] as $key=>$value) + { + if ($value['q']>0) + { + // $value['q']=qty to move + // $value['id_batch']=id into llx_product_batch of record to move + //var_dump($value); + + $linebatch = new ReceptionLineBatch($this->db); + $ret=$linebatch->fetchFromStock($value['id_batch']); // load serial, sellby, eatby + if ($ret<0) + { + $this->error=$linebatch->error; + return -1; + } + $linebatch->dluo_qty=$value['q']; + $tab[]=$linebatch; + + if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_RECEPTION) + { + require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php'; + $prod_batch = new Productbatch($this->db); + $prod_batch->fetch($value['id_batch']); + + if ($prod_batch->qty < $linebatch->dluo_qty) + { + $langs->load("errors"); + $this->errors[]=$langs->trans('ErrorStockIsNotEnoughToAddProductOnReception', $prod_batch->fk_product); + dol_syslog(get_class($this)."::addline_batch error=Product ".$prod_batch->batch.": ".$this->errorsToString(), LOG_ERR); + $this->db->rollback(); + return -1; + } + } + + //var_dump($linebatch); + } + } + $line->entrepot_id = $linebatch->entrepot_id; + $line->origin_line_id = $dbatch['ix_l']; + $line->qty = $dbatch['qty']; + $line->detail_batch=$tab; + + // extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used + $line->array_options = $array_options; + + //var_dump($line); + $this->lines[$num] = $line; + return 1; + } + } + + /** + * Update database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user=null, $notrigger=0) + { + global $conf; + $error=0; + + // Clean parameters + + if (isset($this->ref)) $this->ref=trim($this->ref); + if (isset($this->entity)) $this->entity=trim($this->entity); + if (isset($this->ref_customer)) $this->ref_customer=trim($this->ref_customer); + if (isset($this->socid)) $this->socid=trim($this->socid); + if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author); + if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid); + if (isset($this->fk_delivery_address)) $this->fk_delivery_address=trim($this->fk_delivery_address); + if (isset($this->reception_method_id)) $this->reception_method_id=trim($this->reception_method_id); + if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number); + if (isset($this->statut)) $this->statut=(int) $this->statut; + if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth); + if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth); + if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight); + if (isset($this->size_units)) $this->size_units=trim($this->size_units); + if (isset($this->weight_units)) $this->weight_units=trim($this->weight_units); + if (isset($this->trueWeight)) $this->weight=trim($this->trueWeight); + if (isset($this->note_private)) $this->note=trim($this->note_private); + if (isset($this->note_public)) $this->note=trim($this->note_public); + if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf); + + + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET"; + + $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').","; + $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").","; + $sql.= " ref_customer=".(isset($this->ref_customer)?"'".$this->db->escape($this->ref_customer)."'":"null").","; + $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").","; + $sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').","; + $sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").","; + $sql.= " date_valid=".(dol_strlen($this->date_valid)!=0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').","; + $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").","; + $sql.= " date_reception=".(dol_strlen($this->date_reception)!=0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').","; + $sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').","; + $sql.= " fk_address=".(isset($this->fk_delivery_address)?$this->fk_delivery_address:"null").","; + $sql.= " fk_reception_method=".((isset($this->reception_method_id) && $this->reception_method_id > 0)?$this->reception_method_id:"null").","; + $sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").","; + $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").","; + $sql.= " height=".(($this->trueHeight != '')?$this->trueHeight:"null").","; + $sql.= " width=".(($this->trueWidth != '')?$this->trueWidth:"null").","; + $sql.= " size_units=".(isset($this->size_units)?$this->size_units:"null").","; + $sql.= " size=".(($this->trueDepth != '')?$this->trueDepth:"null").","; + $sql.= " weight_units=".(isset($this->weight_units)?$this->weight_units:"null").","; + $sql.= " weight=".(($this->trueWeight != '')?$this->trueWeight:"null").","; + $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").","; + $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").","; + $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").","; + $sql.= " entity=".$conf->entity; + + $sql.= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + + if (! $error) + { + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_MODIFY',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + /** + * Delete reception. + * Warning, do not delete a reception if a delivery is linked to (with table llx_element_element) + * + * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO + */ + function delete() + { + global $conf, $langs, $user; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + if ($conf->productbatch->enabled) + { + require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionbatch.class.php'; + } + $error=0; + $this->error=''; + + // Add a protection to refuse deleting if reception has at least one delivery + $this->fetchObjectLinked($this->id, 'reception', 0, 'delivery'); // Get deliveries linked to this reception + if (count($this->linkedObjectsIds) > 0) + { + $this->error='ErrorThereIsSomeDeliveries'; + return -1; + } + + $this->db->begin(); + // Stock control + if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_RECEPTION && $this->statut > 0) + { + require_once(DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php"); + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.rowid as receptiondet_id"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."receptiondet as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::delete select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + dol_syslog(get_class($this)."::delete movement index ".$i); + $obj = $this->db->fetch_object($resql); + + $mouvS = new MouvementStock($this->db); + // we do not log origin because it will be deleted + $mouvS->origin = null; + // get lot/serial + $lotArray = null; + if ($conf->productbatch->enabled) + { + $lotArray = ReceptionLineBatch::fetchAll($this->db,$obj->receptiondet_id); + if (! is_array($lotArray)) + { + $error++;$this->errors[]="Error ".$this->db->lasterror(); + } + } + if (empty($lotArray)) { + // no lot/serial + // We increment stock of product (and sub-products) + // We use warehouse selected for each line + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref)); // Price is set to 0, because we don't want to see WAP changed + if ($result < 0) + { + $error++;$this->errors=$this->errors + $mouvS->errors; + break; + } + } + else + { + // We increment stock of batches + // We use warehouse selected for each line + foreach($lotArray as $lot) + { + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->dluo_qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, $lot->batch); // Price is set to 0, because we don't want to see WAP changed + if ($result < 0) + { + $error++;$this->errors=$this->errors + $mouvS->errors; + break; + } + } + if ($error) break; // break for loop incase of error + } + } + } + else + { + $error++;$this->errors[]="Error ".$this->db->lasterror(); + } + } + + // delete batch reception line + if (! $error && $conf->productbatch->enabled) + { + if (ReceptionLineBatch::deletefromexp($this->db,$this->id) < 0) + { + $error++;$this->errors[]="Error ".$this->db->lasterror(); + } + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."receptiondet"; + $sql.= " WHERE fk_reception = ".$this->id; + + if ( $this->db->query($sql) ) + { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."reception"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_DELETE',$user); + if ($result < 0) { $error++; } + // End call triggers + + if (! empty($this->origin) && $this->origin_id > 0) + { + $this->fetch_origin(); + $origin=$this->origin; + if ($this->$origin->statut == Commande::STATUS_RECEPTIONONPROCESS) // If order source of reception is "reception in progress" + { + // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress" + $this->$origin->loadReceptions(); + //var_dump($this->$origin->receptions);exit; + if (count($this->$origin->receptions) <= 0) + { + $this->$origin->setStatut(Commande::STATUS_VALIDATED); + } + } + } + + if (! $error) + { + $this->db->commit(); + + // We delete PDFs + $ref = dol_sanitizeFileName($this->ref); + if (! empty($conf->reception->dir_output)) + { + $dir = $conf->reception->dir_output . '/reception/' . $ref ; + $file = $dir . '/' . $ref . '.pdf'; + if (file_exists($file)) + { + if (! dol_delete_file($file)) + { + return 0; + } + } + if (file_exists($dir)) + { + if (!dol_delete_dir_recursive($dir)) + { + $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir); + return 0; + } + } + } + + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -3; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -1; + } + } + else + { + $this->db->rollback(); + return -1; + } + + } + + /** + * Load lines + * + * @return int >0 if OK, Otherwise if KO + */ + function fetch_lines() + { + global $conf, $mysoc; + // TODO: recuperer les champs du document associe a part + + $sql = "SELECT cd.rowid, cd.fk_product, cd.label as custom_label, cd.description, cd.qty as qty_asked, cd.product_type"; + $sql.= ", cd.total_ht, cd.total_localtax1, cd.total_localtax2, cd.total_ttc, cd.total_tva"; + $sql.= ", cd.vat_src_code, cd.tva_tx, cd.localtax1_tx, cd.localtax2_tx, cd.localtax1_type, cd.localtax2_type, cd.price, cd.subprice, cd.remise_percent,cd.buy_price_ht as pa_ht"; + $sql.= ", cd.fk_multicurrency, cd.multicurrency_code, cd.multicurrency_subprice, cd.multicurrency_total_ht, cd.multicurrency_total_tva, cd.multicurrency_total_ttc"; + $sql.= ", ed.rowid as line_id, ed.qty as qty_shipped, ed.fk_origin_line, ed.fk_entrepot"; + $sql.= ", p.ref as product_ref, p.label as product_label, p.fk_product_type"; + $sql.= ", p.weight, p.weight_units, p.length, p.length_units, p.surface, p.surface_units, p.volume, p.volume_units, p.tobatch as product_tobatch"; + $sql.= " FROM (".MAIN_DB_PREFIX."receptiondet as ed,"; + $sql.= " ".MAIN_DB_PREFIX."commandedet as cd)"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = cd.fk_product"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND ed.fk_origin_line = cd.rowid"; + $sql.= " ORDER BY cd.rang, ed.fk_origin_line"; + + dol_syslog(get_class($this)."::fetch_lines", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + $num = $this->db->num_rows($resql); + $i = 0; + $lineindex = 0; + $originline = 0; + + $this->total_ht = 0; + $this->total_tva = 0; + $this->total_ttc = 0; + $this->total_localtax1 = 0; + $this->total_localtax2 = 0; + + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + if ($originline == $obj->fk_origin_line) { + $line->entrepot_id = 0; // entrepod_id in details_entrepot + $line->qty_shipped += $obj->qty_shipped; + } else { + $line = new ReceptionLigne($this->db); + $line->entrepot_id = $obj->fk_entrepot; + $line->qty_shipped = $obj->qty_shipped; + } + + $detail_entrepot = new stdClass; + $detail_entrepot->entrepot_id = $obj->fk_entrepot; + $detail_entrepot->qty_shipped = $obj->qty_shipped; + $line->details_entrepot[] = $detail_entrepot; + + $line->line_id = $obj->line_id; + $line->rowid = $obj->line_id; // TODO deprecated + $line->id = $obj->line_id; + + $line->fk_origin = 'orderline'; + $line->fk_origin_line = $obj->fk_origin_line; + $line->origin_line_id = $obj->fk_origin_line; // TODO deprecated + + $line->fk_reception = $this->id; // id of parent + + $line->product_type = $obj->product_type; + $line->fk_product = $obj->fk_product; + $line->fk_product_type = $obj->fk_product_type; + $line->ref = $obj->product_ref; // TODO deprecated + $line->product_ref = $obj->product_ref; + $line->product_label = $obj->product_label; + $line->libelle = $obj->product_label; // TODO deprecated + $line->product_tobatch = $obj->product_tobatch; + $line->label = $obj->custom_label; + $line->description = $obj->description; + $line->qty_asked = $obj->qty_asked; + $line->weight = $obj->weight; + $line->weight_units = $obj->weight_units; + $line->length = $obj->length; + $line->length_units = $obj->length_units; + $line->surface = $obj->surface; + $line->surface_units = $obj->surface_units; + $line->volume = $obj->volume; + $line->volume_units = $obj->volume_units; + + $line->pa_ht = $obj->pa_ht; + + // Local taxes + $localtax_array=array(0=>$obj->localtax1_type, 1=>$obj->localtax1_tx, 2=>$obj->localtax2_type, 3=>$obj->localtax2_tx); + $localtax1_tx = get_localtax($obj->tva_tx, 1, $this->thirdparty); + $localtax2_tx = get_localtax($obj->tva_tx, 2, $this->thirdparty); + + // For invoicing + $tabprice = calcul_price_total($obj->qty_shipped, $obj->subprice, $obj->remise_percent, $obj->tva_tx, $localtax1_tx, $localtax2_tx, 0, 'HT', $obj->info_bits, $obj->fk_product_type, $mysoc, $localtax_array); // We force type to 0 + $line->desc = $obj->description; // We need ->desc because some code into CommonObject use desc (property defined for other elements) + $line->qty = $line->qty_shipped; + $line->total_ht = $tabprice[0]; + $line->total_localtax1 = $tabprice[9]; + $line->total_localtax2 = $tabprice[10]; + $line->total_ttc = $tabprice[2]; + $line->total_tva = $tabprice[1]; + $line->vat_src_code = $obj->vat_src_code; + $line->tva_tx = $obj->tva_tx; + $line->localtax1_tx = $obj->localtax1_tx; + $line->localtax2_tx = $obj->localtax2_tx; + $line->price = $obj->price; + $line->subprice = $obj->subprice; + $line->remise_percent = $obj->remise_percent; + + $this->total_ht+= $tabprice[0]; + $this->total_tva+= $tabprice[1]; + $this->total_ttc+= $tabprice[2]; + $this->total_localtax1+= $tabprice[9]; + $this->total_localtax2+= $tabprice[10]; + + // Multicurrency + $this->fk_multicurrency = $obj->fk_multicurrency; + $this->multicurrency_code = $obj->multicurrency_code; + $this->multicurrency_subprice = $obj->multicurrency_subprice; + $this->multicurrency_total_ht = $obj->multicurrency_total_ht; + $this->multicurrency_total_tva = $obj->multicurrency_total_tva; + $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc; + + if ($originline != $obj->fk_origin_line) + { + $line->detail_batch = array(); + } + // Eat-by date + if (! empty($conf->productbatch->enabled) && $obj->line_id > 0) + { + require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionbatch.class.php'; + + $newdetailbatch = ReceptionLineBatch::fetchAll($this->db,$obj->line_id); + if (is_array($newdetailbatch)) + { + if ($originline != $obj->fk_origin_line) + { + $line->detail_batch = $newdetailbatch; + } + else + { + $line->detail_batch = array_merge($line->detail_batch, $newdetailbatch); + } + } + } + + if ($originline != $obj->fk_origin_line) + { + $this->lines[$lineindex] = $line; + $lineindex++; + } + else + { + $line->total_ht += $tabprice[0]; + $line->total_localtax1 += $tabprice[9]; + $line->total_localtax2 += $tabprice[10]; + $line->total_ttc += $tabprice[2]; + $line->total_tva += $tabprice[1]; + } + + $i++; + $originline = $obj->fk_origin_line; + } + $this->db->free($resql); + return 1; + } + else + { + $this->error=$this->db->error(); + return -3; + } + } + + /** + * Return clicable link of object (with eventually picto) + * + * @param int $withpicto Add picto into link + * @param int $option Where point the link + * @param int $max Max length to show + * @param int $short Use short labels + * @param int $notooltip 1=No tooltip + * @return string String with URL + */ + function getNomUrl($withpicto=0,$option=0,$max=0,$short=0,$notooltip=0) + { + global $langs; + + $result=''; + $label = '' . $langs->trans("ShowReception") . ''; + $label .= '
' . $langs->trans('Ref') . ': '.$this->ref; + $label .= '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); + + $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id; + + if ($short) return $url; + + $linkclose=''; + if (empty($notooltip)) + { + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label=$langs->trans("ShowReception"); + $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose.=' class="classfortooltip"'; + } + + $linkstart = ''; + $linkend=''; + + $picto='reception'; + + if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend); + if ($withpicto && $withpicto != 2) $result.=' '; + $result.=$linkstart.$this->ref.$linkend; + return $result; + } + + /** + * Return status label + * + * @param int $mode 0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto + * @return string Libelle + */ + function getLibStatut($mode=0) + { + return $this->LibStatut($this->statut,$mode); + } + + /** + * Return label of a status + * + * @param int $statut Id statut + * @param int $mode 0=Long label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Long label, 5=Short label + Picto + * @return string Label of status + */ + function LibStatut($statut,$mode) + { + global $langs; + + if ($mode==0) + { + if ($statut==0) return $langs->trans($this->statuts[$statut]); + if ($statut==1) return $langs->trans($this->statuts[$statut]); + if ($statut==2) return $langs->trans($this->statuts[$statut]); + } + if ($mode==1) + { + if ($statut==0) return $langs->trans('StatusReceptionDraftShort'); + if ($statut==1) return $langs->trans('StatusReceptionValidatedShort'); + if ($statut==2) return $langs->trans('StatusReceptionProcessedShort'); + } + if ($mode == 3) + { + if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0'); + if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return img_picto($langs->trans('StatusReceptionProcessed'),'statut6'); + } + if ($mode == 4) + { + if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]); + if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]); + if ($statut==2) return img_picto($langs->trans('StatusReceptionProcessed'),'statut6').' '.$langs->trans('StatusReceptionProcessed'); + } + if ($mode == 5) + { + if ($statut==0) return $langs->trans('StatusReceptionDraftShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut0'); + if ($statut==1) return $langs->trans('StatusReceptionValidatedShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return $langs->trans('StatusReceptionProcessedShort').' '.img_picto($langs->trans('StatusReceptionProcessedShort'),'statut6'); + } + } + + /** + * Initialise an instance with random values. + * Used to build previews or test instances. + * id must be 0 if object instance is a specimen. + * + * @return void + */ + function initAsSpecimen() + { + global $langs; + + $now=dol_now(); + + dol_syslog(get_class($this)."::initAsSpecimen"); + + // Load array of products prodids + $num_prods = 0; + $prodids = array(); + $sql = "SELECT rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."product"; + $sql.= " WHERE entity IN (".getEntity('product').")"; + $resql = $this->db->query($sql); + if ($resql) + { + $num_prods = $this->db->num_rows($resql); + $i = 0; + while ($i < $num_prods) + { + $i++; + $row = $this->db->fetch_row($resql); + $prodids[$i] = $row[0]; + } + } + + $order=new Commande($this->db); + $order->initAsSpecimen(); + + // Initialise parametres + $this->id=0; + $this->ref = 'SPECIMEN'; + $this->specimen=1; + $this->statut = 1; + $this->livraison_id = 0; + $this->date = $now; + $this->date_creation = $now; + $this->date_valid = $now; + $this->date_delivery = $now; + $this->date_reception = $now + 24*3600; + + $this->entrepot_id = 0; + $this->fk_delivery_address = 0; + $this->socid = 1; + + $this->commande_id = 0; + $this->commande = $order; + + $this->origin_id = 1; + $this->origin = 'commande'; + + $this->note_private = 'Private note'; + $this->note_public = 'Public note'; + + $nbp = 5; + $xnbp = 0; + while ($xnbp < $nbp) + { + $line=new ReceptionLigne($this->db); + $line->desc=$langs->trans("Description")." ".$xnbp; + $line->libelle=$langs->trans("Description")." ".$xnbp; + $line->qty=10; + $line->qty_asked=5; + $line->qty_shipped=4; + $line->fk_product=$this->commande->lines[$xnbp]->fk_product; + + $this->lines[]=$line; + $xnbp++; + } + + } + + /** + * Set the planned delivery date + * + * @param User $user Objet utilisateur qui modifie + * @param timestamp $date_livraison Date de livraison + * @return int <0 if KO, >0 if OK + */ + function set_date_livraison($user, $date_livraison) + { + if ($user->rights->reception->creer) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null'); + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_date_livraison", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->date_delivery = $date_livraison; + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + else + { + return -2; + } + } + + /** + * Fetch deliveries method and return an array. Load array this->meths(rowid=>label). + * + * @return void + */ + function fetch_delivery_methods() + { + global $langs; + $this->meths = array(); + + $sql = "SELECT em.rowid, em.code, em.libelle"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_reception_mode as em"; + $sql.= " WHERE em.active = 1"; + $sql.= " ORDER BY em.libelle ASC"; + + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $label=$langs->trans('ReceptionMethod'.$obj->code); + $this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle); + } + } + } + + /** + * Fetch all deliveries method and return an array. Load array this->listmeths. + * + * @param id $id only this carrier, all if none + * @return void + */ + function list_delivery_methods($id='') + { + global $langs; + + $this->listmeths = array(); + $i=0; + + $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_reception_mode as em"; + if ($id!='') $sql.= " WHERE em.rowid=".$id; + + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $this->listmeths[$i]['rowid'] = $obj->rowid; + $this->listmeths[$i]['code'] = $obj->code; + $label=$langs->trans('ReceptionMethod'.$obj->code); + $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle); + $this->listmeths[$i]['description'] = $obj->description; + $this->listmeths[$i]['tracking'] = $obj->tracking; + $this->listmeths[$i]['active'] = $obj->active; + $i++; + } + } + } + + /** + * Update/create delivery method. + * + * @param string $id id method to activate + * + * @return void + */ + function update_delivery_method($id='') + { + if ($id=='') + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."c_reception_mode (code, libelle, description, tracking)"; + $sql.=" VALUES ('".$this->update['code']."','".$this->update['libelle']."','".$this->update['description']."','".$this->update['tracking']."')"; + $resql = $this->db->query($sql); + } + else + { + $sql = "UPDATE ".MAIN_DB_PREFIX."c_reception_mode SET"; + $sql.= " code='".$this->db->escape($this->update['code'])."'"; + $sql.= ",libelle='".$this->db->escape($this->update['libelle'])."'"; + $sql.= ",description='".$this->db->escape($this->update['description'])."'"; + $sql.= ",tracking='".$this->db->escape($this->update['tracking'])."'"; + $sql.= " WHERE rowid=".$id; + $resql = $this->db->query($sql); + } + if ($resql < 0) dol_print_error($this->db,''); + } + + /** + * Activate delivery method. + * + * @param id $id id method to activate + * + * @return void + */ + function activ_delivery_method($id) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_reception_mode SET active=1'; + $sql.= ' WHERE rowid='.$id; + + $resql = $this->db->query($sql); + + } + + /** + * DesActivate delivery method. + * + * @param id $id id method to desactivate + * + * @return void + */ + function disable_delivery_method($id) + { + $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_reception_mode SET active=0'; + $sql.= ' WHERE rowid='.$id; + + $resql = $this->db->query($sql); + + } + + + /** + * Forge an set tracking url + * + * @param string $value Value + * @return void + */ + function GetUrlTrackingStatus($value='') + { + if (! empty($this->reception_method_id)) + { + $sql = "SELECT em.code, em.tracking"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_reception_mode as em"; + $sql.= " WHERE em.rowid = ".$this->reception_method_id; + + $resql = $this->db->query($sql); + if ($resql) + { + if ($obj = $this->db->fetch_object($resql)) + { + $tracking = $obj->tracking; + } + } + } + + if (!empty($tracking) && !empty($value)) + { + $url = str_replace('{TRACKID}', $value, $tracking); + $this->tracking_url = sprintf(''.($value?$value:'url').'',$url,$url); + } + else + { + $this->tracking_url = $value; + } + } + + /** + * Classify the reception as closed. + * + * @return int <0 if KO, >0 if OK + */ + function setClosed() + { + global $conf,$langs,$user; + + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + // Set order billed if 100% of order is shipped (qty in reception lines match qty in order lines) + if ($this->origin == 'commande' && $this->origin_id > 0) + { + $order = new Commande($this->db); + $order->fetch($this->origin_id); + + $order->loadReceptions(self::STATUS_CLOSED); // Fill $order->receptions = array(orderlineid => qty) + + $receptions_match_order = 1; + foreach($order->lines as $line) + { + $lineid = $line->id; + $qty = $line->qty; + if (($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] != $qty) + { + $receptions_match_order = 0; + $text='Qty for order line id '.$lineid.' is '.$qty.'. However in the receptions with status Reception::STATUS_CLOSED='.self::STATUS_CLOSED.' we have qty = '.$order->receptions[$lineid].', so we can t close order'; + dol_syslog($text); + break; + } + } + if ($receptions_match_order) + { + dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for receptions with status Reception::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order'); + $order->cloture($user); + } + } + + $this->statut=self::STATUS_CLOSED; + + + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite d'expedier a partir d'une propale ou autre origine ? + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."receptiondet as ed"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."receptiondet_batch as edb on edb.fk_receptiondet = ed.rowid"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) + { + $qty = $obj->qty; + } + else + { + $qty = $obj->edbqty; + } + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->edbrowid)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr",$numref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + // Call trigger + if (! $error) + { + $result=$this->call_trigger('RECEPTION_CLOSED',$user); + if ($result < 0) { + $error++; + } + } + } + else + { + dol_print_error($this->db); + $error++; + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Classify the reception as invoiced (used when WORKFLOW_BILL_ON_RECEPTION is on) + * + * @return int <0 if ko, >0 if ok + */ + function set_billed() + { + global $user; + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=2, billed=1'; // TODO Update only billed + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + $this->statut=2; + $this->billed=1; + + // Call trigger + $result=$this->call_trigger('RECEPTION_BILLED',$user); + if ($result < 0) { + $error++; + } + + } else { + $error++; + $this->errors[]=$this->db->lasterror; + } + + if (empty($error)) { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Classify the reception as validated/opened + * + * @return int <0 if ko, >0 if ok + */ + function reOpen() + { + global $conf,$langs,$user; + + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1'; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + $this->statut=1; + $this->billed=0; + + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite d'expedier a partir d'une propale ou autre origine + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."receptiondet as ed"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."receptiondet_batch as edb on edb.fk_receptiondet = ed.rowid"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) + { + $qty = $obj->qty; + } + else + { + $qty = $obj->edbqty; + } + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->edbrowid)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr",$numref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr",$numref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + if (! $error) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_REOPEN',$user); + if ($result < 0) { + $error++; + } + } + + } else { + $error++; + $this->errors[]=$this->db->lasterror(); + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @return int <0 if KO, >0 if OK + */ + function set_draft($user) + { + global $conf,$langs; + + $error=0; + + // Protection + if ($this->statut <= self::STATUS_DRAFT) + { + return 0; + } + + if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + } + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET fk_statut = ".self::STATUS_DRAFT; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_draft", LOG_DEBUG); + if ($this->db->query($sql)) + { + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite d'expedier a partir d'une propale ou autre origine + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " edb.rowid as edbrowid, edb.eatby, edb.sellby, edb.batch, edb.qty as edbqty, edb.fk_origin_stock"; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."receptiondet as ed"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."receptiondet_batch as edb on edb.fk_receptiondet = ed.rowid"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_origin_line"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + if (empty($obj->edbrowid)) + { + $qty = $obj->qty; + } + else + { + $qty = $obj->edbqty; + } + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->edbrowid)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr",$this->ref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr",$this->ref), '', $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + if (!$error) { + // Call trigger + $result=$this->call_trigger('RECEPTION_UNVALIDATE',$user); + if ($result < 0) $error++; + } + if($this->origin == 'commande'){ + $commande = new Commande($this->db); + $commande->fetch($this->origin_id); + $commande->statut = Commande::STATUS_VALIDATED; + $commande->update(); + } + + + if (!$error) { + $this->statut=self::STATUS_DRAFT; + $this->db->commit(); + return 1; + }else { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force the model to using ('' to not force) + * @param Translate $outputlangs object lang to use for translations + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs,$hidedetails=0, $hidedesc=0, $hideref=0) + { + global $conf,$langs; + + $langs->load("receptions"); + + if (! dol_strlen($modele)) { + + $modele = 'rouget'; + + if ($this->modelpdf) { + $modele = $this->modelpdf; + } elseif (! empty($conf->global->RECEPTION_ADDON_PDF)) { + $modele = $conf->global->RECEPTION_ADDON_PDF; + } + } + + $modelpath = "core/modules/reception/doc/"; + + $this->fetch_origin(); + + return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'reception' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } +} + + +/** + * Classe de gestion des lignes de bons d'reception + */ +class ReceptionLigne extends CommonObjectLine +{ + public $element='receptiondet'; + public $table_element='receptiondet'; + + public $fk_origin_line; + + /** + * Id of reception + * @var int + */ + public $fk_reception; + + var $db; + + // From llx_receptiondet + var $qty; + var $qty_shipped; + var $fk_product; + var $detail_batch; + /** + * Id of warehouse + * @var int + */ + public $entrepot_id; + + + // From llx_commandedet or llx_propaldet + var $qty_asked; + public $product_ref; + public $product_label; + public $product_desc; + + + // Invoicing + var $remise_percent; + var $total_ht; // Total net of tax + var $total_ttc; // Total with tax + var $total_tva; // Total VAT + var $total_localtax1; // Total Local tax 1 + var $total_localtax2; // Total Local tax 2 + + + + // Deprecated + /** + * @deprecated + * @see fk_origin_line + */ + var $origin_line_id; + /** + * @deprecated + * @see product_ref + */ + var $ref; + /** + * @deprecated + * @see product_label + */ + var $libelle; + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db=$db; + } + + /** + * Load line reception + * + * @param int $rowid Id line order + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT ed.rowid, ed.fk_reception, ed.fk_entrepot, ed.fk_origin_line, ed.qty, ed.rang'; + $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as ed'; + $sql.= ' WHERE ed.rowid = '.$rowid; + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); + $this->id = $objp->rowid; + $this->fk_reception = $objp->fk_reception; + $this->entrepot_id = $objp->fk_entrepot; + $this->fk_origin_line = $objp->fk_origin_line; + $this->qty = $objp->qty; + $this->rang = $objp->rang; + + $this->db->free($result); + + return 1; + } + else + { + $this->errors[] = $this->db->lasterror(); + $this->error = $this->db->lasterror(); + return -1; + } + } + + /** + * Insert line into database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int <0 if KO, line id >0 if OK + */ + function insert($user=null, $notrigger=0) + { + global $langs, $conf; + + $error=0; + + // Check parameters + if (empty($this->fk_reception) || empty($this->fk_origin_line) || ! is_numeric($this->qty)) + { + $this->error = 'ErrorMandatoryParametersNotProvided'; + return -1; + } + // Clean parameters + if (empty($this->entrepot_id)) $this->entrepot_id='null'; + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."receptiondet ("; + $sql.= "fk_reception"; + $sql.= ", fk_entrepot"; + $sql.= ", fk_origin_line"; + $sql.= ", qty"; + $sql.= ") VALUES ("; + $sql.= $this->fk_reception; + $sql.= ", ".$this->entrepot_id; + $sql.= ", ".$this->fk_origin_line; + $sql.= ", ".$this->qty; + $sql.= ")"; + + dol_syslog(get_class($this)."::insert", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."receptiondet"); + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINERECEPTION_INSERT',$user); + if ($result < 0) + { + $error++; + } + // End call triggers + } + + if (! $error) { + $this->db->commit(); + return $this->id; + } + + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + + $this->db->rollback(); + return -1*$error; + } + else + { + $error++; + } + } + + /** + * Delete reception line. + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int >0 if OK, <0 if KO + */ + function delete($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + $this->db->begin(); + + // delete batch reception line + if ($conf->productbatch->enabled) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."receptiondet_batch"; + $sql.= " WHERE fk_receptiondet = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + } + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."receptiondet"; + $sql.= " WHERE rowid = ".$this->id; + + if (! $error && $this->db->query($sql)) + { + // Remove extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINERECEPTION_DELETE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + } + else + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + + if (! $error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + /** + * Update a line in database + * + * @param User $user User that modify + * @param int $notrigger 1 = disable triggers + * @return int < 0 if KO, > 0 if OK + */ + function update($user = null, $notrigger = 0) + { + global $conf; + + $error=0; + + dol_syslog(get_class($this)."::update id=$this->id, entrepot_id=$this->entrepot_id, product_id=$this->fk_product, qty=$this->qty"); + + $this->db->begin(); + + // Clean parameters + if (empty($this->qty)) $this->qty=0; + $qty=price2num($this->qty); + $remainingQty = 0; + $batch = null; + $batch_id = null; + $reception_batch_id = null; + if (is_array($this->detail_batch)) // array of ReceptionLineBatch + { + if (count($this->detail_batch) > 1) + { + dol_syslog(get_class($this).'::update only possible for one batch', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + else + { + $batch = $this->detail_batch[0]->batch; + $batch_id = $this->detail_batch[0]->fk_origin_stock; + $reception_batch_id = $this->detail_batch[0]->id; + if ($this->entrepot_id != $this->detail_batch[0]->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch[0]->dluo_qty); + } + } + else if (! empty($this->detail_batch)) + { + $batch = $this->detail_batch->batch; + $batch_id = $this->detail_batch->fk_origin_stock; + $reception_batch_id = $this->detail_batch->id; + if ($this->entrepot_id != $this->detail_batch->entrepot_id) + { + dol_syslog(get_class($this).'::update only possible for batch of same warehouse', LOG_ERR); + $this->errors[]='ErrorBadParameters'; + $error++; + } + $qty = price2num($this->detail_batch->dluo_qty); + } + + // check parameters + if (! isset($this->id) || ! isset($this->entrepot_id)) + { + dol_syslog(get_class($this).'::update missing line id and/or warehouse id', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + return -1; + } + + // update lot + + if (! empty($batch) && $conf->productbatch->enabled) + { + dol_syslog(get_class($this)."::update reception batch id=$reception_batch_id, batch_id=$batch_id, batch=$batch"); + + if (empty($batch_id) || empty($this->fk_product)) { + dol_syslog(get_class($this).'::update missing fk_origin_stock (batch_id) and/or fk_product', LOG_ERR); + $this->errors[]='ErrorMandatoryParametersNotProvided'; + $error++; + } + + // fetch remaining lot qty + require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionbatch.class.php'; + if (! $error && ($lotArray = ReceptionLineBatch::fetchAll($this->db, $this->id)) < 0) + { + $this->errors[]=$this->db->lasterror()." - ReceptionLineBatch::fetchAll"; + $error++; + } + else + { + // caculate new total line qty + foreach ($lotArray as $lot) + { + if ($reception_batch_id != $lot->id) + { + $remainingQty += $lot->dluo_qty; + } + } + $qty += $remainingQty; + + //fetch lot details + + // fetch from product_lot + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; + $lot = new Productlot($this->db); + if ($lot->fetch(0,$this->fk_product,$batch) < 0) + { + $this->errors[] = $lot->errors; + $error++; + } + if (! $error && ! empty($reception_batch_id)) + { + // delete lot reception line + $sql = "DELETE FROM ".MAIN_DB_PREFIX."receptiondet_batch"; + $sql.= " WHERE fk_receptiondet = ".$this->id; + $sql.= " AND rowid = ".$reception_batch_id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + } + if (! $error && $this->detail_batch->dluo_qty > 0) + { + // create lot reception line + if (isset($lot->id)) + { + $receptionLot = new ReceptionLineBatch($this->db); + $receptionLot->batch = $lot->batch; + $receptionLot->eatby = $lot->eatby; + $receptionLot->sellby = $lot->sellby; + $receptionLot->entrepot_id = $this->detail_batch->entrepot_id; + $receptionLot->dluo_qty = $this->detail_batch->dluo_qty; + $receptionLot->fk_origin_stock = $batch_id; + if ($receptionLot->create($this->id) < 0) + { + $this->errors[]=$receptionLot->errors; + $error++; + } + } + } + } + } + if (! $error) + { + // update line + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element." SET"; + $sql.= " fk_entrepot = ".($this->entrepot_id > 0 ? $this->entrepot_id : 'null'); + $sql.= " , qty = ".$qty; + $sql.= " WHERE rowid = ".$this->id; + + if (!$this->db->query($sql)) + { + $this->errors[]=$this->db->lasterror()." - sql=$sql"; + $error++; + } + else + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + } + } + } + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINERECEPTION_UPDATE',$user); + if ($result < 0) + { + $this->errors[]=$this->error; + $error++; + } + // End call triggers + } + if (!$error) { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } +} + diff --git a/htdocs/reception/contact.php b/htdocs/reception/contact.php new file mode 100644 index 00000000000..7c721d7cf47 --- /dev/null +++ b/htdocs/reception/contact.php @@ -0,0 +1,274 @@ + + * Copyright (C) 2005-2011 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/contact.php + * \ingroup expedition + * \brief Onglet de gestion des contacts de expedition + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +if (! empty($conf->projet->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; +} + +$langs->load("orders"); +$langs->load("sendings"); +$langs->load("companies"); + +$id=GETPOST('id','int'); +$ref=GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'expedition', $id,''); + +$object = new Expedition($db); +if ($id > 0 || ! empty($ref)) +{ + $object->fetch($id, $ref); + $object->fetch_thirdparty(); + + if (!empty($object->origin)) + { + $typeobject = $object->origin; + $origin = $object->origin; + $object->fetch_origin(); + } + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } +} + + +/* + * Actions + */ + +if ($action == 'addcontact' && $user->rights->expedition->creer) +{ + if ($result > 0 && $id > 0) + { + $result = $objectsrc->add_contact(GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'), $_POST["type"], $_POST["source"]); + } + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + if ($objectsrc->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $langs->load("errors"); + $mesg = $langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"); + } else { + $mesg = $objectsrc->error; + $mesgs = $objectsrc->errors; + } + setEventMessages($mesg, $mesgs, 'errors'); + } +} + +// bascule du statut d'un contact +else if ($action == 'swapstatut' && $user->rights->expedition->creer) +{ + $result=$objectsrc->swapContactStatus(GETPOST('ligne')); +} + +// Efface un contact +else if ($action == 'deletecontact' && $user->rights->expedition->creer) +{ + $result = $objectsrc->delete_contact(GETPOST("lineid")); + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else { + dol_print_error($db); + } +} +/* +else if ($action == 'setaddress' && $user->rights->expedition->creer) +{ + $object->fetch($id); + $result=$object->setDeliveryAddress($_POST['fk_address']); + if ($result < 0) dol_print_error($db,$object->error); +}*/ + + +/* + * View + */ + +llxHeader('',$langs->trans('Order'),'EN:Customers_Orders|FR:expeditions_Clients|ES:Pedidos de clientes'); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$formother = new FormOther($db); +$contactstatic=new Contact($db); +$userstatic=new User($db); + + +/* *************************************************************************** */ +/* */ +/* Mode vue et edition */ +/* */ +/* *************************************************************************** */ + +if ($id > 0 || ! empty($ref)) +{ + $langs->trans("OrderCard"); + + $head = shipping_prepare_head($object); + dol_fiche_head($head, 'contact', $langs->trans("Shipment"), -1, 'sending'); + + + // Shipment card + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref='
'; + // Ref customer shipment + $morehtmlref.=$form->editfieldkey("RefCustomer", '', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", '', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on shipment + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= ''; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on shipment, so we will use the project or source object instead + // TODO Add project on shipment + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + //print '
'; + print '
'; + + print ''; + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + print ''; + print '\n"; + print ''; + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + print ''; + print '\n"; + print ''; + } + + print "
'; + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + print $langs->trans("RefOrder").''; + print $objectsrc->getNomUrl(1,'commande'); + print "
'; + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + print $langs->trans("RefProposal").''; + print $objectsrc->getNomUrl(1,'expedition'); + print "
"; + + + //print '
'; + //print '
'; + //print '
'; + //print '
'; + + + //print '
'; + //print '
'; + print '
'; + + print '
'; + + + dol_fiche_end(); + + // Lignes de contacts + echo '
'; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $res=@include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) break; + } + +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/index.php b/htdocs/reception/index.php new file mode 100644 index 00000000000..7eaba0b29ad --- /dev/null +++ b/htdocs/reception/index.php @@ -0,0 +1,296 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/index.php + * \ingroup expedition + * \brief Home page of shipping area. + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; + +$langs->load("orders"); +$langs->load("sendings"); + +/* + * View + */ + +$orderstatic=new Commande($db); +$companystatic=new Societe($db); +$shipment=new Expedition($db); + +$helpurl='EN:Module_Shipments|FR:Module_Expéditions|ES:Módulo_Expediciones'; +llxHeader('',$langs->trans("Shipment"),$helpurl); + +print load_fiche_titre($langs->trans("SendingsArea")); + + +print '
'; + + +if (! empty($conf->global->MAIN_SEARCH_FORM_ON_HOME_AREAS)) // This is useless due to the global search combo +{ + print '
'; + print ''; + print ''; + print ''; + print ''; + print "
'.$langs->trans("Search").'
'; + print $langs->trans("Shipment").':

\n"; +} + +/* + * Shipments to validate + */ +$clause = " WHERE "; + +$sql = "SELECT e.rowid, e.ref, e.ref_customer,"; +$sql.= " s.nom as name, s.rowid as socid,"; +$sql.= " c.ref as commande_ref, c.rowid as commande_id"; +$sql.= " FROM ".MAIN_DB_PREFIX."expedition as e"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON e.rowid = el.fk_target AND el.targettype = 'shipping'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."commande as c ON el.fk_source = c.rowid"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +if (!$user->rights->societe->client->voir && !$socid) +{ + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON e.fk_soc = sc.fk_soc"; + $sql.= $clause." sc.fk_user = " .$user->id; + $clause = " AND "; +} +$sql.= $clause." e.fk_statut = 0"; +$sql.= " AND e.entity IN (".getEntity('expedition').")"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; + +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + print ''; + print ''; + print ''; + $i = 0; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $shipment->id=$obj->rowid; + $shipment->ref=$obj->ref; + $shipment->ref_customer=$obj->ref_customer; + + print '"; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("SendingsToValidate").'
'; + print $shipment->getNomUrl(1); + print "'; + print ''.$obj->name.''; + print ''; + if ($obj->commande_id) print ''.$obj->commande_ref.''; + print '

"; + } +} + + +/* + * Commandes a traiter + */ +$sql = "SELECT c.rowid, c.ref, c.ref_client as ref_customer, c.fk_statut, s.nom as name, s.rowid as socid"; +$sql.= " FROM ".MAIN_DB_PREFIX."commande as c,"; +$sql.= " ".MAIN_DB_PREFIX."societe as s"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE c.fk_soc = s.rowid"; +$sql.= " AND c.entity = ".$conf->entity; +$sql.= " AND c.fk_statut = 1"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +$sql.= " ORDER BY c.rowid ASC"; + +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + $langs->load("orders"); + + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $orderstatic->id=$obj->rowid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_customer=$obj->ref_customer; + $orderstatic->statut=$obj->fk_statut; + $orderstatic->facturee=0; + + $companystatic->name=$obj->name; + $companystatic->id=$obj->socid; + + print ''; + print ''; + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("OrdersToProcess").'
'; + print $orderstatic->getNomUrl(1); + print ''; + print $companystatic->getNomUrl(1,'customer',32); + print ''; + print $orderstatic->getLibStatut(3); + print '

"; + } +} + + +//print ''; +print '
'; + + +/* + * Commandes en traitement + */ +$sql = "SELECT c.rowid, c.ref, c.ref_client as ref_customer, c.fk_statut as status, c.facture as billed, s.nom as name, s.rowid as socid"; +$sql.= " FROM ".MAIN_DB_PREFIX."commande as c,"; +$sql.= " ".MAIN_DB_PREFIX."societe as s"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE c.fk_soc = s.rowid"; +$sql.= " AND c.entity = ".$conf->entity; +$sql.= " AND c.fk_statut = 2"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + +$resql = $db->query($sql); +if ( $resql ) +{ + $langs->load("orders"); + + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $orderstatic->id=$obj->rowid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_customer=$obj->ref_customer; + $orderstatic->statut=$obj->status; + $orderstatic->facturee=$obj->billed; + + $companystatic->name=$obj->name; + $companystatic->id=$obj->socid; + + print ''; + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("OrdersInProcess").'
'; + print $orderstatic->getNomUrl(1); + print ''; + print $companystatic->getNomUrl(1,'customer'); + print ''; + print $orderstatic->getLibStatut(3); + print '

"; + } +} +else dol_print_error($db); + + +/* + * Last shipments + */ +$sql = "SELECT e.rowid, e.ref, e.ref_customer,"; +$sql.= " s.nom as name, s.rowid as socid,"; +$sql.= " c.ref as commande_ref, c.rowid as commande_id"; +$sql.= " FROM ".MAIN_DB_PREFIX."expedition as e"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON e.rowid = el.fk_target AND el.targettype = 'shipping' AND el.sourcetype IN ('commande')"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."commande as c ON el.fk_source = c.rowid AND el.sourcetype IN ('commande') AND el.targettype = 'shipping'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +if (! $user->rights->societe->client->voir && ! $socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON e.fk_soc = sc.fk_soc"; +$sql.= " WHERE e.entity IN (".getEntity('expedition').")"; +if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND sc.fk_user = " .$user->id; +$sql.= " AND e.fk_statut = 1"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; +$sql.= " ORDER BY e.date_delivery DESC"; +$sql.= $db->plimit(5, 0); + +$resql = $db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $shipment->id=$obj->rowid; + $shipment->ref=$obj->ref; + $shipment->ref_customer=$obj->ref_customer; + + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("LastSendings", $num).'
'; + print $shipment->getNomUrl(1); + print ''.img_object($langs->trans("ShowCompany"),"company").' '.$obj->name.''; + if ($obj->commande_id > 0) + { + $orderstatic->id=$obj->commande_id; + $orderstatic->ref=$obj->commande_ref; + print $orderstatic->getNomUrl(1); + } + else print ' '; + print '

"; + } + $db->free($resql); +} +else dol_print_error($db); + + +print '
'; + + +llxFooter(); +$db->close(); diff --git a/htdocs/reception/list.php b/htdocs/reception/list.php new file mode 100644 index 00000000000..ab5fa27b13f --- /dev/null +++ b/htdocs/reception/list.php @@ -0,0 +1,669 @@ + + * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2005-2010 Regis Houssin + * Copyright (C) 2016 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/list.php + * \ingroup expedition + * \brief Page to list all shipments + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +$langs->load("sendings"); +$langs->load("deliveries"); +$langs->load('companies'); + +$socid=GETPOST('socid','int'); +// Security check +$expeditionid = GETPOST('id','int'); +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'expedition',$expeditionid,''); + +$diroutputmassaction=$conf->expedition->dir_output . '/temp/massgeneration/'.$user->id; + +$search_ref_exp = GETPOST("search_ref_exp"); +$search_ref_liv = GETPOST('search_ref_liv'); +$search_company = GETPOST("search_company"); +$search_town=GETPOST('search_town','alpha'); +$search_zip=GETPOST('search_zip','alpha'); +$search_state=trim(GETPOST("search_state")); +$search_country=GETPOST("search_country",'int'); +$search_type_thirdparty=GETPOST("search_type_thirdparty",'int'); +$search_billed=GETPOST("search_billed",'int'); +$sall = GETPOST('sall', 'alphanohtml'); +$optioncss = GETPOST('optioncss','alpha'); + +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$sortfield = GETPOST('sortfield','alpha'); +$sortorder = GETPOST('sortorder','alpha'); +$page = GETPOST('page','int'); +if (! $sortfield) $sortfield="e.ref"; +if (! $sortorder) $sortorder="DESC"; +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$contextpage='shipmentlist'; + +$viewstatut=GETPOST('viewstatut'); + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('shipmentlist')); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('expedition'); +$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_'); + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array( + 'e.ref'=>"Ref", + 's.nom'=>"ThirdParty", + 'e.note_public'=>'NotePublic', +); +if (empty($user->socid)) $fieldstosearchall["e.note_private"]="NotePrivate"; + +$checkedtypetiers=0; +$arrayfields=array( + 'e.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1), + 'e.ref_customer'=>array('label'=>$langs->trans("RefCustomer"), 'checked'=>1), + 's.nom'=>array('label'=>$langs->trans("ThirdParty"), 'checked'=>1), + 's.town'=>array('label'=>$langs->trans("Town"), 'checked'=>1), + 's.zip'=>array('label'=>$langs->trans("Zip"), 'checked'=>1), + 'state.nom'=>array('label'=>$langs->trans("StateShort"), 'checked'=>0), + 'country.code_iso'=>array('label'=>$langs->trans("Country"), 'checked'=>0), + 'typent.code'=>array('label'=>$langs->trans("ThirdPartyType"), 'checked'=>$checkedtypetiers), + 'e.date_delivery'=>array('label'=>$langs->trans("DateDeliveryPlanned"), 'checked'=>1), + 'e.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500), + 'e.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500), + 'e.fk_statut'=>array('label'=>$langs->trans("Status"), 'checked'=>1, 'position'=>1000), + 'l.ref'=>array('label'=>$langs->trans("DeliveryRef"), 'checked'=>1, 'enabled'=>$conf->livraison_bon->enabled), + 'l.date_delivery'=>array('label'=>$langs->trans("DateReceived"), 'checked'=>1, 'enabled'=>$conf->livraison_bon->enabled), + 'e.billed'=>array('label'=>$langs->trans("Billed"), 'checked'=>1, 'position'=>1000, 'enabled'=>(!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) +); + +// Extra fields +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) +{ + foreach($extrafields->attribute_label as $key => $val) + { + $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>$extrafields->attribute_perms[$key]); + } +} + + +/* + * Actions + */ + +if (GETPOST('cancel')) { $action='list'; $massaction=''; } +if (! GETPOST('confirmmassaction')) { $massaction=''; } + +$parameters=array('socid'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + +// Purge search criteria +if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers +{ + $search_ref_exp=''; + $search_ref_liv=''; + $search_company=''; + $search_town=''; + $search_zip=""; + $search_state=""; + $search_type=''; + $search_country=''; + $search_type_thirdparty=''; + $search_billed=''; + $viewstatut=''; + $search_array_options=array(); +} + +if (empty($reshook)) +{ + // Mass actions. Controls on number of lines checked + $maxformassaction=1000; + if (! empty($massaction) && count($toselect) < 1) + { + $error++; + setEventMessages($langs->trans("NoLineChecked"), null, "warnings"); + } + if (! $error && count($toselect) > $maxformassaction) + { + setEventMessages($langs->trans('TooManyRecordForMassAction',$maxformassaction), null, 'errors'); + $error++; + } + +} + + + + +/* + * View + */ + +$form=new Form($db); +$companystatic=new Societe($db); +$shipment=new Expedition($db); +$formcompany=new FormCompany($db); + +$helpurl='EN:Module_Shipments|FR:Module_Expéditions|ES:Módulo_Expediciones'; +llxHeader('',$langs->trans('ListOfSendings'),$helpurl); + +$sql = "SELECT e.rowid, e.ref, e.ref_customer, e.date_expedition as date_expedition, e.date_delivery as date_livraison, l.date_delivery as date_reception, e.fk_statut, e.billed,"; +$sql.= ' s.rowid as socid, s.nom as name, s.town, s.zip, s.fk_pays, s.client, s.code_client, '; +$sql.= " typent.code as typent_code,"; +$sql.= " state.code_departement as state_code, state.nom as state_name,"; +$sql.= ' e.date_creation as date_creation, e.tms as date_update'; +// Add fields from extrafields +foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : ''); +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql.= " FROM ".MAIN_DB_PREFIX."expedition as e"; +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."expedition_extrafields as ef on (e.rowid = ef.fk_object)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as country on (country.rowid = s.fk_pays)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_typent as typent on (typent.id = s.fk_typent)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as state on (state.rowid = s.fk_departement)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as ee ON e.rowid = ee.fk_source AND ee.sourcetype = 'shipping' AND ee.targettype = 'delivery'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.rowid = ee.fk_target"; +if (!$user->rights->societe->client->voir && !$socid) // Internal user with no permission to see all +{ + $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +} +$sql.= " WHERE e.entity IN (".getEntity('expedition').")"; +if (!$user->rights->societe->client->voir && !$socid) // Internal user with no permission to see all +{ + $sql.= " AND e.fk_soc = sc.fk_soc"; + $sql.= " AND sc.fk_user = " .$user->id; +} +if ($socid) +{ + $sql.= " AND e.fk_soc = ".$socid; +} +if ($viewstatut <> '' && $viewstatut >= 0) { + $sql.= " AND e.fk_statut = ".$viewstatut; +} +if ($search_billed != '' && $search_billed >= 0) $sql.=' AND e.billed = '.$search_billed; +if ($search_town) $sql.= natural_search('s.town', $search_town); +if ($search_zip) $sql.= natural_search("s.zip",$search_zip); +if ($search_state) $sql.= natural_search("state.nom",$search_state); +if ($search_country) $sql .= " AND s.fk_pays IN (".$search_country.')'; +if ($search_type_thirdparty) $sql .= " AND s.fk_typent IN (".$search_type_thirdparty.')'; +if ($search_ref_exp) $sql .= natural_search('e.ref', $search_ref_exp); +if ($search_ref_liv) $sql .= natural_search('l.ref', $search_ref_liv); +if ($search_company) $sql .= natural_search('s.nom', $search_company); +if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall); + +// Add where from extra fields +foreach ($search_array_options as $key => $val) +{ + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + $typ=$extrafields->attribute_type[$tmpkey]; + $mode=0; + if (in_array($typ, array('int','double','real'))) $mode=1; // Search on a numeric + if (in_array($typ, array('sellist')) && $crit != '0' && $crit != '-1') $mode=2; // Search on a foreign key int + if ($crit != '' && (! in_array($typ, array('select','sellist')) || $crit != '0')) + { + $sql .= natural_search('ef.'.$tmpkey, $crit, $mode); + } +} +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); +} + +$sql.= $db->order($sortfield,$sortorder); +$sql.= $db->plimit($limit + 1,$offset); + +//print $sql; +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + + $expedition = new Expedition($db); + + $param=''; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + if ($sall) $param.= "&sall=".$sall; + if ($search_ref_exp) $param.= "&search_ref_exp=".$search_ref_exp; + if ($search_ref_liv) $param.= "&search_ref_liv=".$search_ref_liv; + if ($search_company) $param.= "&search_company=".$search_company; + if ($optioncss != '') $param.='&optioncss='.$optioncss; + // Add $param from extra fields + foreach ($search_array_options as $key => $val) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val); + } + + //$massactionbutton=$form->selectMassAction('', $massaction == 'presend' ? array() : array('presend'=>$langs->trans("SendByMail"), 'builddoc'=>$langs->trans("PDFMerge"))); + + $i = 0; + print '
'."\n"; + if ($optioncss != '') print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + print_barre_liste($langs->trans('ListOfSendings'), $page, $_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,'',$num, $nbtotalofrecords, '', 0, '', '', $limit); + + if ($sall) + { + foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall); + } + + $moreforfilter=''; + if (! empty($moreforfilter)) + { + print '
'; + print $moreforfilter; + $parameters=array('type'=>$type); + $reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print '
'; + } + + $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; + $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + + print '
'; + print ''."\n"; + + // Lignes des champs de filtre + print ''; + // Ref + if (! empty($arrayfields['e.ref']['checked'])) + { + print ''; + } + // Ref customer + if (! empty($arrayfields['e.ref_customer']['checked'])) + { + print ''; + } + // Thirdparty + if (! empty($arrayfields['s.nom']['checked'])) + { + print ''; + } + // Town + if (! empty($arrayfields['s.town']['checked'])) print ''; + // Zip + if (! empty($arrayfields['s.zip']['checked'])) print ''; + // State + if (! empty($arrayfields['state.nom']['checked'])) + { + print ''; + } + // Country + if (! empty($arrayfields['country.code_iso']['checked'])) + { + print ''; + } + // Company type + if (! empty($arrayfields['typent.code']['checked'])) + { + print ''; + } + // Date delivery planned + if (! empty($arrayfields['e.date_delivery']['checked'])) + { + print ''; + } + if (! empty($arrayfields['l.ref']['checked'])) + { + // Delivery ref + print ''; + } + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + $align=$extrafields->getAlignFlag($key); + $typeofextrafield=$extrafields->attribute_type[$key]; + print ''; + } + } + } + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListOption',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Date creation + if (! empty($arrayfields['e.datec']['checked'])) + { + print ''; + } + // Date modification + if (! empty($arrayfields['e.tms']['checked'])) + { + print ''; + } + // Status + if (! empty($arrayfields['e.fk_statut']['checked'])) + { + print ''; + } + // Status billed + if (! empty($arrayfields['e.billed']['checked'])) + { + print ''; + } + // Action column + print ''; + print "\n"; + + print ''; + if (! empty($arrayfields['e.ref']['checked'])) print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"],"e.ref","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['e.ref_customer']['checked'])) print_liste_field_titre($arrayfields['e.ref_customer']['label'], $_SERVER["PHP_SELF"],"e.ref_customer","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['s.nom']['checked'])) print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"],"s.nom", "", $param,'align="left"',$sortfield,$sortorder); + if (! empty($arrayfields['s.town']['checked'])) print_liste_field_titre($arrayfields['s.town']['label'],$_SERVER["PHP_SELF"],'s.town','',$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['s.zip']['checked'])) print_liste_field_titre($arrayfields['s.zip']['label'],$_SERVER["PHP_SELF"],'s.zip','',$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['state.nom']['checked'])) print_liste_field_titre($arrayfields['state.nom']['label'],$_SERVER["PHP_SELF"],"state.nom","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['country.code_iso']['checked'])) print_liste_field_titre($arrayfields['country.code_iso']['label'],$_SERVER["PHP_SELF"],"country.code_iso","",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['typent.code']['checked'])) print_liste_field_titre($arrayfields['typent.code']['label'],$_SERVER["PHP_SELF"],"typent.code","",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['e.date_delivery']['checked'])) print_liste_field_titre($arrayfields['e.date_delivery']['label'], $_SERVER["PHP_SELF"],"e.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['l.ref']['checked'])) print_liste_field_titre($arrayfields['l.ref']['label'], $_SERVER["PHP_SELF"],"l.ref","",$param, '',$sortfield,$sortorder); + if (! empty($arrayfields['l.date_delivery']['checked'])) print_liste_field_titre($arrayfields['l.date_delivery']['label'], $_SERVER["PHP_SELF"],"l.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + $align=$extrafields->getAlignFlag($key); + $sortonfield = "ef.".$key; + if (! empty($extrafields->attribute_computed[$key])) $sortonfield=''; + print_liste_field_titre($extralabels[$key],$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder); + } + } + } + // Hook fields + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + if (! empty($arrayfields['e.datec']['checked'])) print_liste_field_titre($arrayfields['e.datec']['label'],$_SERVER["PHP_SELF"],"e.date_creation","",$param,'align="center" class="nowrap"',$sortfield,$sortorder); + if (! empty($arrayfields['e.tms']['checked'])) print_liste_field_titre($arrayfields['e.tms']['label'],$_SERVER["PHP_SELF"],"e.tms","",$param,'align="center" class="nowrap"',$sortfield,$sortorder); + if (! empty($arrayfields['e.fk_statut']['checked'])) print_liste_field_titre($arrayfields['e.fk_statut']['label'],$_SERVER["PHP_SELF"],"e.fk_statut","",$param,'align="right"',$sortfield,$sortorder); + if (! empty($arrayfields['e.billed']['checked'])) print_liste_field_titre($arrayfields['e.billed']['label'],$_SERVER["PHP_SELF"],"e.billed","",$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch '); + print "\n"; + + $i=0; + $var=true; + $totalarray=array(); + while ($i < min($num,$limit)) + { + $obj = $db->fetch_object($resql); + + $shipment->id=$obj->rowid; + $shipment->ref=$obj->ref; + + $companystatic->id=$obj->socid; + $companystatic->ref=$obj->name; + $companystatic->name=$obj->name; + + + print ''; + + // Ref + if (! empty($arrayfields['e.ref']['checked'])) + { + print "\n"; + if (! $i) $totalarray['nbfield']++; + } + + // Ref customer + if (! empty($arrayfields['e.ref_customer']['checked'])) + { + print "\n"; + if (! $i) $totalarray['nbfield']++; + } + + // Third party + if (! empty($arrayfields['s.nom']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Town + if (! empty($arrayfields['s.town']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Zip + if (! empty($arrayfields['s.zip']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // State + if (! empty($arrayfields['state.nom']['checked'])) + { + print "\n"; + if (! $i) $totalarray['nbfield']++; + } + // Country + if (! empty($arrayfields['country.code_iso']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Type ent + if (! empty($arrayfields['typent.code']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Date delivery planed + if (! empty($arrayfields['e.date_delivery']['checked'])) + { + print '\n"; + } + + if (! empty($arrayfields['l.ref']['checked']) || ! empty($arrayfields['l.date_delivery']['checked'])) + { + $shipment->fetchObjectLinked($shipment->id,$shipment->element); + $receiving=''; + if (count($shipment->linkedObjects['delivery']) > 0) $receiving=reset($shipment->linkedObjects['delivery']); + + if (! empty($arrayfields['l.ref']['checked'])) + { + // Ref + print ''; + } + + if (! empty($arrayfields['l.date_delivery']['checked'])) + { + // Date received + print ''."\n"; + } + } + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + } + } + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj); + $reshook=$hookmanager->executeHooks('printFieldListValue',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Date creation + if (! empty($arrayfields['e.datec']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Date modification + if (! empty($arrayfields['e.tms']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Status + if (! empty($arrayfields['e.fk_statut']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Billed + if (! empty($arrayfields['e.billed']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Action column + print ''; + if (! $i) $totalarray['nbfield']++; + + print "\n"; + + $i++; + } + + print "
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print $form->select_country($search_country,'search_country','',0,'maxwidth100'); + print ''; + print $form->selectarray("search_type_thirdparty", $formcompany->typent_array(0), $search_type_thirdparty, 0, 0, 0, '', 0, 0, 0, (empty($conf->global->SOCIETE_SORT_ON_TYPEENT)?'ASC':$conf->global->SOCIETE_SORT_ON_TYPEENT)); + print ' '; + print ''; + } + if (! empty($arrayfields['l.date_delivery']['checked'])) + { + // Date received + print ' '; + if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select'))) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + $searchclass=''; + if (in_array($typeofextrafield, array('varchar', 'select'))) $searchclass='searchstring'; + if (in_array($typeofextrafield, array('int', 'double'))) $searchclass='searchnum'; + print ''; + } + print ''; + print ''; + print ''; + print $form->selectarray('viewstatut', array('0'=>$langs->trans('StatusSendingDraftShort'),'1'=>$langs->trans('StatusSendingValidatedShort'),'2'=>$langs->trans('StatusSendingProcessedShort')),$viewstatut,1); + print ''; + print $form->selectyesno('search_billed', $search_billed, 1, 0, 1); + print ''; + $searchpicto=$form->showFilterAndCheckAddButtons(0); + print $searchpicto; + print '
"; + print $shipment->getNomUrl(1); + print ""; + print $obj->ref_customer; + print "'; + print $companystatic->getNomUrl(1); + print ''; + print $obj->town; + print ''; + print $obj->zip; + print '".$obj->state_name."'; + $tmparray=getCountry($obj->fk_pays,'all'); + print $tmparray['label']; + print ''; + if (count($typenArray)==0) $typenArray = $formcompany->typent_array(1); + print $typenArray[$obj->typent_code]; + print ''; + print dol_print_date($db->jdate($obj->date_livraison),"day"); + /*$now = time(); + if ( ($now - $db->jdate($obj->date_expedition)) > $conf->warnings->lim && $obj->statutid == 1 ) + { + }*/ + print "'; + print !empty($receiving) ? $receiving->getNomUrl($db) : ''; + print ''; + print dol_print_date($db->jdate($obj->date_reception),"day"); + print 'getAlignFlag($key); + if ($align) print ' align="'.$align.'"'; + print '>'; + $tmpkey='options_'.$key; + print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1); + print ''; + print dol_print_date($db->jdate($obj->date_creation), 'dayhour'); + print ''; + print dol_print_date($db->jdate($obj->date_update), 'dayhour'); + print ''.$shipment->LibStatut($obj->fk_statut,5).''.yn($obj->billed).'
"; + print "
"; + print '
'; + $db->free($resql); +} +else +{ + dol_print_error($db); +} + +llxFooter(); +$db->close(); diff --git a/htdocs/reception/note.php b/htdocs/reception/note.php new file mode 100644 index 00000000000..c32ec5c5124 --- /dev/null +++ b/htdocs/reception/note.php @@ -0,0 +1,164 @@ + + * Copyright (C) 2004-2008 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Florian Henry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/note.php + * \ingroup expedition + * \brief Note card expedition + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php'; +if (! empty($conf->projet->enabled)) { + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; +} + +$langs->load("sendings"); +$langs->load("companies"); +$langs->load("bills"); +$langs->load('deliveries'); +$langs->load('orders'); +$langs->load('stocks'); +$langs->load('other'); +$langs->load('propal'); + +$id=(GETPOST('id','int')?GETPOST('id','int'):GETPOST('facid','int')); // For backward compatibility +$ref=GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +$socid=''; +if ($user->societe_id) $socid=$user->societe_id; +$result=restrictedArea($user, $origin, $origin_id); + +$object = new Expedition($db); +if ($id > 0 || ! empty($ref)) +{ + $object->fetch($id, $ref); + $object->fetch_thirdparty(); + + if (!empty($object->origin)) + { + $typeobject = $object->origin; + $origin = $object->origin; + $object->fetch_origin(); + } + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } +} + +$permissionnote=$user->rights->expedition->creer; // Used by the include of actions_setnotes.inc.php + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + +/* + * View + */ + +llxHeader(); + +$form = new Form($db); + +if ($id > 0 || ! empty($ref)) +{ + + $head=shipping_prepare_head($object); + dol_fiche_head($head, 'note', $langs->trans("Shipment"), -1, 'sending'); + + + // Shipment card + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref='
'; + // Ref customer shipment + $morehtmlref.=$form->editfieldkey("RefCustomer", '', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", '', $object->ref_customer, $object, $user->rights->expedition->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on shipment + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on shipment, so we will use the project or source object instead + // TODO Add project on shipment + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + + $cssclass='titlefield'; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + dol_fiche_end(); +} + + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/shipment.php b/htdocs/reception/shipment.php new file mode 100644 index 00000000000..849053c610c --- /dev/null +++ b/htdocs/reception/shipment.php @@ -0,0 +1,939 @@ + + * Copyright (C) 2005-2012 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2012-2015 Juanjo Menent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/shipment.php + * \ingroup expedition + * \brief Tab shipments/delivery receipts on the order + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/order.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +if (! empty($conf->projet->enabled)) { + require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php'; +} +if (! empty($conf->stock->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; +if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; + +$langs->load('orders'); +$langs->load("companies"); +$langs->load("bills"); +$langs->load('propal'); +$langs->load('deliveries'); +$langs->load('stocks'); +$langs->load("productbatch"); + +$id=GETPOST('id','int'); // id of order +$ref= GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +$socid=0; +if (! empty($user->societe_id)) $socid=$user->societe_id; +$result=restrictedArea($user,'commande',$id); + +$object = new Commande($db); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + +// Load object +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once + + + + +/* + * Actions + */ + +$parameters = array('socid' => $socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + // Categorisation dans projet + if ($action == 'classin') + { + $object = new Commande($db); + $object->fetch($id); + $object->setProject(GETPOST('projectid','int')); + } + + if ($action == 'confirm_cloture' && GETPOST('confirm','alpha') == 'yes') + { + $object = new Commande($db); + $object->fetch($id); + $result = $object->cloture($user); + } + + // Positionne ref commande client + else if ($action == 'setref_client' && $user->rights->commande->creer) { + $result = $object->set_ref_client($user, GETPOST('ref_client')); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + if ($action == 'setdatedelivery' && $user->rights->commande->creer) + { + //print "x ".$_POST['liv_month'].", ".$_POST['liv_day'].", ".$_POST['liv_year']; + $datelivraison=dol_mktime(0, 0, 0, GETPOST('liv_month','int'), GETPOST('liv_day','int'),GETPOST('liv_year','int')); + + $object = new Commande($db); + $object->fetch($id); + $result=$object->set_date_livraison($user,$datelivraison); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + /* + if ($action == 'setdeliveryaddress' && $user->rights->commande->creer) + { + $object = new Commande($db); + $object->fetch($id); + $object->setDeliveryAddress(GETPOST('delivery_address_id','int')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + */ + if ($action == 'setmode' && $user->rights->commande->creer) + { + $object = new Commande($db); + $object->fetch($id); + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id','int')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + if ($action == 'setavailability' && $user->rights->commande->creer) { + $object = new Commande($db); + $object->fetch($id); + $result=$object->availability(GETPOST('availability_id')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + if ($action == 'setdemandreason' && $user->rights->commande->creer) { + $object = new Commande($db); + $object->fetch($id); + $result=$object->demand_reason(GETPOST('demand_reason_id')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + if ($action == 'setconditions' && $user->rights->commande->creer) + { + $object = new Commande($db); + $object->fetch($id); + $result=$object->setPaymentTerms(GETPOST('cond_reglement_id','int')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + // shipping method + if ($action == 'setshippingmethod' && $user->rights->commande->creer) { + $object = new Commande($db); + $object->fetch($id); + $result=$object->setShippingMethod(GETPOST('shipping_method_id', 'int')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + // warehouse + if ($action == 'setwarehouse' && $user->rights->commande->creer) { + $object = new Commande($db); + $object->fetch($id); + $result = $object->setWarehouse(GETPOST('warehouse_id', 'int')); + if ($result < 0) + setEventMessages($object->error, $object->errors, 'errors'); + } + + if ($action == 'update_extras') + { + // Fill array 'array_options' with data from update form + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute')); + if ($ret < 0) $error++; + + if (! $error) + { + // Actions on extra fields (by external module or standard code) + $hookmanager->initHooks(array('orderdao')); + $parameters = array('id' => $object->id); + $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by + // some hooks + if (empty($reshook)) { + $result = $object->insertExtraFields(); + if ($result < 0) { + $error++; + } + } else if ($reshook < 0) + $error++; + } + + if ($error) + $action = 'edit_extras'; + } + + if ($action == 'set_thirdparty' && $user->rights->commande->creer) + { + $object->fetch($id); + $object->setValueFrom('fk_soc', $socid, '', '', 'date', '', $user, 'ORDER_MODIFY'); + + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id); + exit(); + } + + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + +} + +/* + * View + */ + +$form = new Form($db); +$formfile = new FormFile($db); +$formproduct = new FormProduct($db); +if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } + +llxHeader('',$langs->trans('OrderCard'),''); + + +if ($id > 0 || ! empty($ref)) +{ + $object = new Commande($db); + if ( $object->fetch($id,$ref) > 0) + { + $object->loadExpeditions(1); + + $product_static=new Product($db); + + $soc = new Societe($db); + $soc->fetch($object->socid); + + $author = new User($db); + $author->fetch($object->user_author_id); + + $res = $object->fetch_optionals($object->id, $extralabels); + + $head = commande_prepare_head($object); + dol_fiche_head($head, 'shipping', $langs->trans("CustomerOrder"), -1, 'order'); + + + $formconfirm = ''; + + // Confirm validation + if ($action == 'cloture') + { + $formconfirm = $form->formconfirm($_SERVER['PHP_SELF']."?id=".$id,$langs->trans("CloseShipment"),$langs->trans("ConfirmCloseShipment"),"confirm_cloture"); + + } + + if (! $formconfirm) { + $parameters = array(); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Order card + + $linkback = '' . $langs->trans("BackToList") . ''; + + + $morehtmlref='
'; + // Ref customer + $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $user->rights->commande->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $user->rights->commande->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + $morehtmlref.='
'.$langs->trans('Project') . ' '; + if ($user->rights->commande->creer) + { + if ($action != 'classify') + $morehtmlref.='' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + if ($action == 'classify') { + //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref.='
'; + $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref.=''; + $morehtmlref.='
'; + } else { + $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + if (! empty($object->fk_project)) { + $proj = new Project($db); + $proj->fetch($object->fk_project); + $morehtmlref.=''; + $morehtmlref.=$proj->ref; + $morehtmlref.=''; + } else { + $morehtmlref.=''; + } + } + } + $morehtmlref.='
'; + + + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + print '
'; + print '
'; + + print ''; + + // Discounts for third party + print ''; + + // Date + print ''; + print ''; + print ''; + + // Delivery date planned + print ''; + // Note on several rows + //print ''; + print ''; + + // Shipping Method + print ''; + print ''; + + // Warehouse + if (! empty($conf->stock->enabled) && ! empty($conf->global->WAREHOUSE_ASK_WAREHOUSE_DURING_ORDER)) { + require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; + $formproduct=new FormProduct($db); + print ''; + print ''; + } + + // Terms of payment + /* + print ''; + + // Mode of payment + print '';*/ + + // Availability + print ''; + + // Source + print ''; + print ''; + print ''; + print ''; + } + + // TODO How record was recorded OrderMode (llx_c_input_method) + + // Incoterms + if (!empty($conf->incoterm->enabled)) + { + print ''; + print ''; + } + + // Other attributes + $cols = 2; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
'.$langs->trans('Discounts').''; + if ($soc->remise_percent) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_percent); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + print '. '; + $absolute_discount=$soc->getAvailableDiscounts('','fk_facture_source IS NULL'); + $absolute_creditnote=$soc->getAvailableDiscounts('','fk_facture_source IS NOT NULL'); + $absolute_discount=price2num($absolute_discount,'MT'); + $absolute_creditnote=price2num($absolute_creditnote,'MT'); + if ($absolute_discount) + { + if ($object->statut > Commande::STATUS_DRAFT) + { + print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); + } + else + { + // Remise dispo de type non avoir + $filter='fk_facture_source IS NULL'; + print '
'; + $form->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$object->id,0,'remise_id',$soc->id,$absolute_discount,$filter, 0, '', 1); + } + } + if ($absolute_creditnote) + { + print $langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)).'. '; + } + if (! $absolute_discount && ! $absolute_creditnote) print $langs->trans("CompanyHasNoAbsoluteDiscount").'.'; + print '
'.$langs->trans('Date').''; + print dol_print_date($object->date,'daytext'); + if ($object->hasDelay() && empty($object->date_livraison)) { + print ' '.img_picto($langs->trans("Late").' : '.$object->showDelay(), "warning"); + } + print '
'; + print ''; + + if ($action != 'editdate_livraison') print ''; + print '
'; + print $langs->trans('DateDeliveryPlanned'); + print 'id.'">'.img_edit($langs->trans('SetDeliveryDate'),1).'
'; + print '
'; + if ($action == 'editdate_livraison') + { + print '
'; + print ''; + print ''; + $form->select_date($object->date_livraison>0?$object->date_livraison:-1,'liv_','','','',"setdatedelivery"); + print ''; + print '
'; + } + else + { + print dol_print_date($object->date_livraison,'daytext'); + if ($object->hasDelay() && ! empty($object->date_livraison)) { + print ' '.img_picto($langs->trans("Late").' : '.$object->showDelay(), "warning"); + } + } + print '
'.$langs->trans('NotePublic').' :
'; + //print nl2br($object->note_public); + //print '
'; + print ''; + if ($action != 'editshippingmethod' && $user->rights->expedition->creer) + print ''; + print '
'; + print $langs->trans('SendingMethod'); + print 'id.'">'.img_edit($langs->trans('SetShippingMode'),1).'
'; + print '
'; + if ($action == 'editshippingmethod') { + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'shipping_method_id', 1); + } else { + $form->formSelectShippingMethod($_SERVER['PHP_SELF'].'?id='.$object->id, $object->shipping_method_id, 'none'); + } + print '
'; + print ''; + if ($action != 'editwarehouse' && $user->rights->commande->creer) + print ''; + print '
'; + print $langs->trans('Warehouse'); + print 'id.'">'.img_edit($langs->trans('SetWarehouse'),1).'
'; + print '
'; + if ($action == 'editwarehouse') { + $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'warehouse_id', 1); + } else { + $formproduct->formSelectWarehouses($_SERVER['PHP_SELF'].'?id='.$object->id, $object->warehouse_id, 'none'); + } + print '
'; + print ''; + + if ($action != 'editconditions' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('PaymentConditionsShort'); + print 'id.'">'.img_edit($langs->trans('SetConditions'),1).'
'; + print '
'; + if ($action == 'editconditions') + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'cond_reglement_id'); + } + else + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'none'); + } + print '
'; + print ''; + if ($action != 'editmode' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('PaymentMode'); + print 'id.'">'.img_edit($langs->trans('SetMode'),1).'
'; + print '
'; + if ($action == 'editmode') + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'mode_reglement_id'); + } + else + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'none'); + } + print '
'; + print ''; + if ($action != 'editavailability') + print ''; + print '
'; + print $langs->trans('AvailabilityPeriod'); + print 'id . '">' . img_edit($langs->trans('SetAvailability'), 1) . '
'; + print '
'; + if ($action == 'editavailability') { + $form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->availability_id, 'availability_id', 1); + } else { + $form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->availability_id, 'none', 1); + } + print '
'; + print ''; + if ($action != 'editdemandreason') + print ''; + print '
'; + print $langs->trans('Source'); + print 'id . '">' . img_edit($langs->trans('SetDemandReason'), 1) . '
'; + print '
'; + if ($action == 'editdemandreason') { + $form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->demand_reason_id, 'demand_reason_id', 1); + } else { + $form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->demand_reason_id, 'none'); + } + + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + if ($totalWeight || $totalVolume) + { + print '
'.$langs->trans("CalculatedWeight").''; + print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND)?$conf->global->MAIN_WEIGHT_DEFAULT_ROUND:-1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT)?$conf->global->MAIN_WEIGHT_DEFAULT_UNIT:'no'); + print '
'.$langs->trans("CalculatedVolume").''; + print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + print '
'; + print '
'; + print $langs->trans('IncotermLabel'); + print ''; + if ($user->rights->commande->creer) print ''.img_edit().''; + else print ' '; + print '
'; + print '
'; + if ($action != 'editincoterm') + { + print $form->textwithpicto($object->display_incoterms(), $object->libelle_incoterms, 1); + } + else + { + print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms)?$object->location_incoterms:''), $_SERVER['PHP_SELF'].'?id='.$object->id); + } + print '
'; + + print '
'; + print '
'; + print '
'; + print '
'; + + print ''; + + if (!empty($conf->multicurrency->enabled) && ($object->multicurrency_code != $conf->currency)) + { + // Multicurrency Amount HT + print ''; + print ''; + print ''; + + // Multicurrency Amount VAT + print ''; + print ''; + print ''; + + // Multicurrency Amount TTC + print ''; + print ''; + print ''; + } + + // Total HT + print ''; + print ''; + print ''; + + // Total VAT + print ''; + print ''; + + // Amount Local Taxes + if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) // Localtax1 + { + print ''; + print ''; + } + if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) // Localtax2 IRPF + { + print ''; + print ''; + } + + // Total TTC + print ''; + print ''; + + print '
' . fieldLabel('MulticurrencyAmountHT','multicurrency_total_ht') . '' . price($object->multicurrency_total_ht, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . '
' . fieldLabel('MulticurrencyAmountVAT','multicurrency_total_tva') . '' . price($object->multicurrency_total_tva, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . '
' . fieldLabel('MulticurrencyAmountTTC','multicurrency_total_ttc') . '' . price($object->multicurrency_total_ttc, '', $langs, 0, - 1, - 1, (!empty($object->multicurrency_code) ? $object->multicurrency_code : $conf->currency)) . '
'.$langs->trans('AmountHT').''.price($object->total_ht, 0, '', 1, -1, -1, $conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva, 0, '', 1, -1, -1, $conf->currency).'
' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '' . price($object->total_localtax1, 1, '', 1, - 1, - 1, $conf->currency) . '
' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '' . price($object->total_localtax2, 1, '', 1, - 1, - 1, $conf->currency) . '
'.$langs->trans('AmountTTC').''.price($object->total_ttc, 0, '', 1, -1, -1, $conf->currency).'
'; + + print '
'; + print '
'; + print '
'; + + print '

'; + + + + /** + * Lines or orders with quantity shipped and remain to ship + * Note: Qty shipped are already available into $object->expeditions[fk_product] + */ + print ''; + + $sql = "SELECT cd.rowid, cd.fk_product, cd.product_type as type, cd.label, cd.description,"; + $sql.= " cd.price, cd.tva_tx, cd.subprice,"; + $sql.= " cd.qty,"; + $sql.= ' cd.date_start,'; + $sql.= ' cd.date_end,'; + $sql.= ' p.rowid as prodid, p.label as product_label, p.entity, p.ref, p.fk_product_type as product_type, p.description as product_desc'; + $sql.= " FROM ".MAIN_DB_PREFIX."commandedet as cd"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON cd.fk_product = p.rowid"; + $sql.= " WHERE cd.fk_commande = ".$object->id; + $sql.= " ORDER BY cd.rang, cd.rowid"; + + //print $sql; + dol_syslog("shipment.php", LOG_DEBUG); + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + + print ''; + print ''; + print ''; + print ''; + print ''; + if (! empty($conf->stock->enabled)) + { + print ''; + } + else + { + print ''; + } + print "\n"; + + $var=true; + $toBeShipped=array(); + $toBeShippedTotal=0; + while ($i < $num) + { + $objp = $db->fetch_object($resql); + + + // Show product and description + $type=isset($objp->type)?$objp->type:$objp->product_type; + + // Try to enhance type detection using date_start and date_end for free lines where type + // was not saved. + if (! empty($objp->date_start)) $type=1; + if (! empty($objp->date_end)) $type=1; + + print ''; + + // Product label + if ($objp->fk_product > 0) + { + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $object->fetch_thirdparty(); + + $prod = new Product($db); + $prod->id = $objp->fk_product; + $prod->entity = $objp->entity; + $prod->getMultiLangs(); + + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if (empty($newlang)) $newlang=$object->thirdparty->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $label = (! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $objp->product_label; + } + else + $label = (! empty($objp->label)?$objp->label:$objp->product_label); + + print ''; + } + else + { + print "\n"; + } + + // Qty ordered + print ''; + + // Qty already shipped + $qtyProdCom=$objp->qty; + print ''; + + // Qty remains to ship + print ''; + + if ($objp->fk_product > 0) + { + $product = new Product($db); + $product->fetch($objp->fk_product); + $product->load_stock('warehouseopen'); + } + + if ($objp->fk_product > 0 && $type == 0 && ! empty($conf->stock->enabled)) + { + print ''; + } + else + { + print ''; + } + print "\n"; + + // Show subproducts lines + if ($objp->fk_product > 0 && ! empty($conf->global->PRODUIT_SOUSPRODUITS)) + { + // Set tree of subproducts in product->sousprods + $product->get_sousproduits_arbo(); + //var_dump($product->sousprods);exit; + + // Define a new tree with quantiies recalculated + $prods_arbo = $product->get_arbo_each_prod($qtyProdCom); + //var_dump($prods_arbo); + if (count($prods_arbo) > 0) + { + foreach($prods_arbo as $key => $value) + { + $img=''; + if ($value['stock'] < $value['stock_alert']) + { + $img=img_warning($langs->trans("StockTooLow")); + } + print ''; + print ''; + print ''; + print ''; + print ''."\n"; + } + } + } + + $i++; + } + $db->free($resql); + + if (! $num) + { + print '
'.$langs->trans("Description").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyShipped").''.$langs->trans("KeepToShip").''.$langs->trans("RealStock").' 
'; + print ''; // ancre pour retourner sur la ligne + + // Show product and description + $product_static->type=$type; + $product_static->id=$objp->fk_product; + $product_static->ref=$objp->ref; + $product_static->entity = $objp->entity; + $text=$product_static->getNomUrl(1); + $text.= ' - '.$label; + $description=($conf->global->PRODUIT_DESC_IN_FORM?'':dol_htmlentitiesbr($objp->description)).'
'; + $description.= $product_static->show_photos($conf->product->multidir_output[$product_static->entity],1,1,0,0,0,80); + print $form->textwithtooltip($text,$description,3,'','',$i); + + // Show range + print_date_range($db->jdate($objp->date_start),$db->jdate($objp->date_end)); + + // Add description in form + if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) + { + print ($objp->description && $objp->description!=$objp->product_label)?'
'.dol_htmlentitiesbr($objp->description):''; + } + + print '
"; + if ($type==1) $text = img_object($langs->trans('Service'),'service'); + else $text = img_object($langs->trans('Product'),'product'); + + if (! empty($objp->label)) { + $text.= ' '.$objp->label.''; + print $form->textwithtooltip($text,$objp->description,3,'','',$i); + } else { + print $text.' '.nl2br($objp->description); + } + + // Show range + print_date_range($db->jdate($objp->date_start),$db->jdate($objp->date_end)); + print "' . $objp->qty . ''; + // Nb of sending products for this line of order + $qtyAlreadyShipped = (! empty($object->expeditions[$objp->rowid])?$object->expeditions[$objp->rowid]:0); + print $qtyAlreadyShipped; + print ''; + if ($type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $toBeShipped[$objp->fk_product] = $objp->qty - $qtyAlreadyShipped; + $toBeShippedTotal += $toBeShipped[$objp->fk_product]; + print $toBeShipped[$objp->fk_product]; + } + else + { + print '0 ('.$langs->trans("Service").')'; + } + print ''; + print $product->stock_reel; + if ($product->stock_reel < $toBeShipped[$objp->fk_product]) + { + print ' '.img_warning($langs->trans("StockTooLow")); + } + print ' 
      -> '.$value['fullpath'].' ('.$value['nb'].') '.$value['nb_total'].'  '.$value['stock'].' '.$img.'
'.$langs->trans("NoArticleOfTypeProduct").'
'; + } + + print "
"; + } + else + { + dol_print_error($db); + } + + print '
'; + + + /* + * Boutons Actions + */ + + if (empty($user->societe_id)) + { + print '
'; + + // Bouton expedier sans gestion des stocks + if (empty($conf->stock->enabled) && ($object->statut > Commande::STATUS_DRAFT && $object->statut < Commande::STATUS_CLOSED)) + { + if ($user->rights->expedition->creer) + { + print ''.$langs->trans("CreateShipment").''; + if ($toBeShippedTotal <= 0) + { + print ' '.img_warning($langs->trans("WarningNoQtyLeftToSend")); + } + } + else + { + print ''.$langs->trans("CreateShipment").''; + } + } + print "
"; + } + + + // Bouton expedier avec gestion des stocks + + if (! empty($conf->stock->enabled) && $object->statut == Commande::STATUS_DRAFT) + { + print $langs->trans("ValidateOrderFirstBeforeShipment"); + } + + if (! empty($conf->stock->enabled) && ($object->statut > Commande::STATUS_DRAFT && $object->statut < Commande::STATUS_CLOSED)) + { + if ($user->rights->expedition->creer) + { + //print load_fiche_titre($langs->trans("CreateShipment")); + print '
'; + + print '
'; + print ''; + //print ''; + print ''; + print ''; + print ''; + print ''; + //print ''; + + $langs->load("stocks"); + + //print ''; + + if (! empty($conf->stock->enabled)) + { + //print ''; + //print ''; + } + //print ''; + + //print "
'; + print $langs->trans("WarehouseSource"); + //print ''; + print $formproduct->selectWarehouses(! empty($object->warehouse_id)?$object->warehouse_id:-1, 'entrepot_id', '', 1, 0, 0, '', 0, 0, array(), 'minwidth200'); + if (count($formproduct->cache_warehouses) <= 0) + { + print '   '.$langs->trans("WarehouseSourceNotDefined").' '.$langs->trans("AddOne").''; + } + //print ''; + print ''; + if ($toBeShippedTotal <= 0) + { + print ' '.img_warning($langs->trans("WarningNoQtyLeftToSend")); + } + //print '
"; + print "
\n"; + + print '
'; + + $somethingshown=1; + + } + else + { + print '
'; + print ''.$langs->trans("CreateShipment").''; + print '
'; + } + } + + show_list_sending_receive('commande',$object->id); + } + else + { + /* Commande non trouvee */ + print "Commande inexistante"; + } +} + + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/stats/index.php b/htdocs/reception/stats/index.php new file mode 100644 index 00000000000..53837c76fd1 --- /dev/null +++ b/htdocs/reception/stats/index.php @@ -0,0 +1,364 @@ + + * Copyright (C) 2004-2016 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/stats/index.php + * \ingroup expedition + * \brief Page with shipment statistics + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionstats.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; + +$WIDTH=DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT=DolGraph::getDefaultGraphSizeForStats('height'); + +$userid=GETPOST('userid','int'); +$socid=GETPOST('socid','int'); +// Security check +if ($user->societe_id > 0) +{ + $action = ''; + $socid = $user->societe_id; +} + +$nowyear=strftime("%Y", dol_now()); +$year = GETPOST('year')>0?GETPOST('year'):$nowyear; +//$startyear=$year-2; +$startyear=$year-1; +$endyear=$year; + +$langs->load("sendings"); +$langs->load("other"); +$langs->load("companies"); + + +/* + * View + */ + +$form=new Form($db); + +llxHeader(); + +print load_fiche_titre($langs->trans("StatisticsOfSendings"), $mesg); + + +dol_mkdir($dir); + +$stats = new ExpeditionStats($db, $socid, $mode, ($userid>0?$userid:0)); + +// Build graphic number of object +$data = $stats->getNbByMonthWithPrevYear($endyear,$startyear); +//var_dump($data);exit; +// $data = array(array('Lib',val1,val2,val3),...) + + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filenamenb = $dir.'/shipmentsnbinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsnbinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsnbinyear-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filenamenb = $dir.'/shipmentsnbinyear-'.$year.'.png'; + if ($mode == 'customer') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsnbinyear-'.$year.'.png'; + if ($mode == 'supplier') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsnbinyear-'.$year.'.png'; +} + +$px1 = new DolGraph(); +$mesg = $px1->isGraphKo(); +if (! $mesg) +{ + $px1->SetData($data); + $px1->SetPrecisionY(0); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px1->SetLegend($legend); + $px1->SetMaxValue($px1->GetCeilMaxValue()); + $px1->SetMinValue(min(0,$px1->GetFloorMinValue())); + $px1->SetWidth($WIDTH); + $px1->SetHeight($HEIGHT); + $px1->SetYLabel($langs->trans("NbOfSendings")); + $px1->SetShading(3); + $px1->SetHorizTickIncrement(1); + $px1->SetPrecisionY(0); + $px1->mode='depth'; + $px1->SetTitle($langs->trans("NumberOfShipmentsByMonth")); + + $px1->draw($filenamenb,$fileurlnb); +} + +// Build graphic amount of object +/* +$data = $stats->getAmountByMonthWithPrevYear($endyear,$startyear); +//var_dump($data); +// $data = array(array('Lib',val1,val2,val3),...) + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filenameamount = $dir.'/shipmentsamountinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsamountinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsamountinyear-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filenameamount = $dir.'/shipmentsamountinyear-'.$year.'.png'; + if ($mode == 'customer') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsamountinyear-'.$year.'.png'; + if ($mode == 'supplier') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsamountinyear-'.$year.'.png'; +} + +$px2 = new DolGraph(); +$mesg = $px2->isGraphKo(); +if (! $mesg) +{ + $px2->SetData($data); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px2->SetLegend($legend); + $px2->SetMaxValue($px2->GetCeilMaxValue()); + $px2->SetMinValue(min(0,$px2->GetFloorMinValue())); + $px2->SetWidth($WIDTH); + $px2->SetHeight($HEIGHT); + $px2->SetYLabel($langs->trans("AmountOfShipments")); + $px2->SetShading(3); + $px2->SetHorizTickIncrement(1); + $px2->SetPrecisionY(0); + $px2->mode='depth'; + $px2->SetTitle($langs->trans("AmountOfShipmentsByMonthHT")); + + $px2->draw($filenameamount,$fileurlamount); +} +*/ + +/* +$data = $stats->getAverageByMonthWithPrevYear($endyear, $startyear); + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filename_avg = $dir.'/shipmentsaverage-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsaverage-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsaverage-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filename_avg = $dir.'/shipmentsaverage-'.$year.'.png'; + if ($mode == 'customer') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstats&file=shipmentsaverage-'.$year.'.png'; + if ($mode == 'supplier') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=shipmentstatssupplier&file=shipmentsaverage-'.$year.'.png'; +} + +$px3 = new DolGraph(); +$mesg = $px3->isGraphKo(); +if (! $mesg) +{ + $px3->SetData($data); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px3->SetLegend($legend); + $px3->SetYLabel($langs->trans("AmountAverage")); + $px3->SetMaxValue($px3->GetCeilMaxValue()); + $px3->SetMinValue($px3->GetFloorMinValue()); + $px3->SetWidth($WIDTH); + $px3->SetHeight($HEIGHT); + $px3->SetShading(3); + $px3->SetHorizTickIncrement(1); + $px3->SetPrecisionY(0); + $px3->mode='depth'; + $px3->SetTitle($langs->trans("AmountAverage")); + + $px3->draw($filename_avg,$fileurl_avg); +} +*/ + + +// Show array +$data = $stats->getAllByYear(); +$arrayyears=array(); +foreach($data as $val) { + if (! empty($val['year'])) { + $arrayyears[$val['year']]=$val['year']; + } +} +if (! count($arrayyears)) $arrayyears[$nowyear]=$nowyear; + +$h=0; +$head = array(); +$head[$h][0] = DOL_URL_ROOT . '/commande/stats/index.php?mode='.$mode; +$head[$h][1] = $langs->trans("ByMonthYear"); +$head[$h][2] = 'byyear'; +$h++; + +$type='shipment_stats'; + +complete_head_from_modules($conf,$langs,null,$head,$h,$type); + +dol_fiche_head($head, 'byyear', $langs->trans("Statistics"), -1); + + +print '
'; + + +//if (empty($socid)) +//{ + // Show filter box + print '
'; + print ''; + + print ''; + print ''; + // Company + print ''; + // User + print ''; + // Year + print ''; + print ''; + print '
'.$langs->trans("Filter").'
'.$langs->trans("ThirdParty").''; + if ($mode == 'customer') $filter='s.client in (1,2,3)'; + if ($mode == 'supplier') $filter='s.fournisseur = 1'; + print $form->select_company($socid,'socid',$filter,1,0,0,array(),0,'','style="width: 95%"'); + print '
'.$langs->trans("CreatedBy").''; + print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth300'); + print '
'.$langs->trans("Year").''; + if (! in_array($year,$arrayyears)) $arrayyears[$year]=$year; + if (! in_array($nowyear,$arrayyears)) $arrayyears[$nowyear]=$nowyear; + arsort($arrayyears); + print $form->selectarray('year',$arrayyears,$year,0); + print '
'; + print '
'; + print '

'; +//} + +print ''; +print ''; +print ''; +print ''; +/*print ''; +print '';*/ +print ''; + +$oldyear=0; +foreach ($data as $val) +{ + $year = $val['year']; + while (! empty($year) && $oldyear > $year+1) + { // If we have empty year + $oldyear--; + + + print ''; + print ''; + + print ''; + /*print ''; + print '';*/ + print ''; + } + + print ''; + print ''; + print ''; + /*print ''; + print '';*/ + print ''; + $oldyear=$year; +} + +print '
'.$langs->trans("Year").''.$langs->trans("NbOfSendings").''.$langs->trans("AmountTotal").''.$langs->trans("AmountAverage").'
'.$oldyear.'000
'; + if ($year) print ''.$year.''; + else print $langs->trans("ValidationDateNotDefinedEvenIfShipmentValidated"); + print ''.$val['nb'].''.price(price2num($val['total'],'MT'),1).''.price(price2num($val['avg'],'MT'),1).'
'; + + +print '
'; + + +// Show graphs +print '
'; +if ($mesg) { print $mesg; } +else { + print $px1->show(); + print "
\n"; + /*print $px2->show(); + print "
\n"; + print $px3->show();*/ +} +print '
'; + + +print '
'; +print '
'; + +dol_fiche_end(); + + + +// TODO USe code similar to commande/stats/index.php instead of this one. +/* +print ''; +print ''; +print ''; + +$sql = "SELECT count(*) as nb, date_format(date_expedition,'%Y') as dm"; +$sql.= " FROM ".MAIN_DB_PREFIX."expedition"; +$sql.= " WHERE fk_statut > 0"; +$sql.= " AND entity = ".$conf->entity; +$sql.= " GROUP BY dm DESC"; + +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $row = $db->fetch_row($resql); + $nbproduct = $row[0]; + $year = $row[1]; + print ""; + print ''; + $i++; + } +} +$db->free($resql); + +print '
'.$langs->trans("Year").''.$langs->trans("NbOfSendings").'
'.$year.''.$nbproduct.'
'; +*/ + +print '
'; +print ''.$langs->trans("StatsOnShipmentsOnlyValidated").''; + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/stats/month.php b/htdocs/reception/stats/month.php new file mode 100644 index 00000000000..b7d217217c2 --- /dev/null +++ b/htdocs/reception/stats/month.php @@ -0,0 +1,76 @@ + + * Copyright (C) 2004-2009 Laurent Destailleur + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/expedition/stats/month.php + * \ingroup commande + * \brief Page des stats expeditions par mois + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/expedition/class/expeditionstats.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; + + +/* + * View + */ + +llxHeader(); + +$WIDTH=DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT=DolGraph::getDefaultGraphSizeForStats('height'); + +$mesg = ''; + +print load_fiche_titre($langs->trans("StatisticsOfSendings").' '.$_GET["year"], $mesg); + +$stats = new ExpeditionStats($db); +$data = $stats->getNbExpeditionByMonth($_GET["year"]); + +dol_mkdir($conf->expedition->dir_temp); + +$filename = $conf->expedition->dir_temp."/expedition".$year.".png"; +$fileurl = DOL_URL_ROOT.'/viewimage.php?modulepart=expeditionstats&file=expedition'.$year.'.png'; + +$px = new DolGraph(); +$mesg = $px->isGraphKo(); +if (! $mesg) +{ + $px->SetData($data); + $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetWidth($WIDTH); + $px->SetHeight($HEIGHT); + $px->SetYLabel($langs->trans("NbOfOrders")); + $px->SetShading(3); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); + $px->draw($filename,$fileurl); +} + +print ''; +print ''; +print ''; +print '
Nombre d expedition par mois'; +print $px->show(); +print '
'; + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/tpl/index.html b/htdocs/reception/tpl/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/reception/tpl/linkedobjectblock.tpl.php b/htdocs/reception/tpl/linkedobjectblock.tpl.php new file mode 100644 index 00000000000..b55654f4786 --- /dev/null +++ b/htdocs/reception/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,80 @@ + + * Copyright (C) 2014 Marcos García + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + * + */ +?> + + + +load("sendings"); + +$total=0; $ilink=0; +$var=true; +foreach($linkedObjectBlock as $key => $objectlink) +{ + $ilink++; + + $trclass=($var?'pair':'impair'); + if ($ilink == count($linkedObjectBlock) && empty($noMoreLinkedObjectBlockAfter) && count($linkedObjectBlock) <= 1) $trclass.=' liste_sub_total'; +?> + + trans("Shipment"); ?> + getNomUrl(1); ?> + + date_delivery,'day'); ?> + rights->expedition->lire) { + $total = $total + $objectlink->total_ht; + echo price($objectlink->total_ht); + } ?> + getLibStatut(3); ?> + + element != 'commande') { + ?> + ">transnoentitiesnoconv("RemoveLink")); ?> + + + 1) +{ + ?> + + trans("Total"); ?> + + + + + + + + + + From 52717dbb651324d2ea82359c4f68a08b3f5eb45f Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Wed, 3 Oct 2018 18:05:22 +0200 Subject: [PATCH 04/50] NEW debut rename stock conf --- htdocs/admin/dict.php | 2 +- htdocs/admin/mails_templates.php | 1 + htdocs/admin/reception_extrafields.php | 127 ++++++++ htdocs/admin/reception_setup.php | 2 +- htdocs/admin/receptiondet_extrafields.php | 127 ++++++++ htdocs/admin/stock.php | 80 ++++- htdocs/core/class/conf.class.php | 6 +- htdocs/core/lib/fourn.lib.php | 2 +- htdocs/fourn/commande/card.php | 4 +- .../llx_commande_fournisseur_dispatch.sql | 1 + .../mysql/tables/llx_reception.key.sql | 18 +- htdocs/install/mysql/tables/llx_reception.sql | 7 +- .../tables/llx_reception_extrafields.key.sql | 2 +- .../tables/llx_reception_extrafields.sql | 2 +- .../mysql/tables/llx_receptiondet.key.sql | 4 +- .../install/mysql/tables/llx_receptiondet.sql | 4 +- .../tables/llx_receptiondet_batch.key.sql | 4 +- .../mysql/tables/llx_receptiondet_batch.sql | 4 +- .../llx_receptiondet_extrafields.key.sql | 2 +- .../tables/llx_receptiondet_extrafields.sql | 2 +- htdocs/langs/fr_FR/admin.lang | 4 +- htdocs/langs/fr_FR/stocks.lang | 9 +- htdocs/product/class/product.class.php | 3 + htdocs/product/list.php | 2 +- htdocs/product/reassort.php | 2 +- htdocs/product/stock/product.php | 2 + htdocs/product/stock/replenish.php | 4 +- htdocs/product/stock/replenishorders.php | 2 +- htdocs/reception/class/reception.class.php | 24 +- scripts/reception/create-table.php | 278 ++++++++++++++++++ 30 files changed, 667 insertions(+), 64 deletions(-) create mode 100644 htdocs/admin/reception_extrafields.php create mode 100644 htdocs/admin/receptiondet_extrafields.php create mode 100644 scripts/reception/create-table.php diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index ce87f507cc6..3bdeb742650 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -407,7 +407,7 @@ $tabcond[14]= (! empty($conf->product->enabled) && ! empty($conf->ecotax->enable $tabcond[15]= true; $tabcond[16]= (! empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS)); $tabcond[17]= (! empty($conf->deplacement->enabled) || ! empty($conf->expensereport->enabled)); -$tabcond[18]= ! empty($conf->expedition->enabled); +$tabcond[18]= ! empty($conf->expedition->enabled) || ! empty($conf->reception->enabled); $tabcond[19]= ! empty($conf->societe->enabled); $tabcond[20]= ! empty($conf->fournisseur->enabled); $tabcond[21]= ! empty($conf->propal->enabled); diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index aae1b5db470..70e0ae268ba 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -148,6 +148,7 @@ if ($conf->propal->enabled) $elementList['propal_send']=$langs->trans('MailToSen if ($conf->commande->enabled) $elementList['order_send']=$langs->trans('MailToSendOrder'); if ($conf->facture->enabled) $elementList['facture_send']=$langs->trans('MailToSendInvoice'); if ($conf->expedition->enabled) $elementList['shipping_send']=$langs->trans('MailToSendShipment'); +if ($conf->reception->enabled) $elementList['reception_send']=$langs->trans('MailToSendReception'); if ($conf->ficheinter->enabled) $elementList['fichinter_send']=$langs->trans('MailToSendIntervention'); if ($conf->supplier_proposal->enabled) $elementList['supplier_proposal_send']=$langs->trans('MailToSendSupplierRequestForQuotation'); if ($conf->fournisseur->enabled) $elementList['order_supplier_send']=$langs->trans('MailToSendSupplierOrder'); diff --git a/htdocs/admin/reception_extrafields.php b/htdocs/admin/reception_extrafields.php new file mode 100644 index 00000000000..dbfccb60773 --- /dev/null +++ b/htdocs/admin/reception_extrafields.php @@ -0,0 +1,127 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2012 Florian Henry + * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/admin/reception_extrafields.php + * \ingroup reception + * \brief Page to setup extra fields of reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + + +if (!$user->admin) + accessforbidden(); + +$langs->load("admin"); +$langs->load("other"); +$langs->load("receptions"); +$langs->load("deliveries"); + + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=ExtraFields::$type2label; +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='reception'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("Receptions"); + +llxHeader('',$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print "
\n"; + +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'attributes_reception', $langs->trans("Receptions"), -1, 'sending'); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation of an optional field */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print load_fiche_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition of an optional field */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print load_fiche_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/admin/reception_setup.php b/htdocs/admin/reception_setup.php index 710c1fb6ba1..4aa362932af 100644 --- a/htdocs/admin/reception_setup.php +++ b/htdocs/admin/reception_setup.php @@ -205,7 +205,7 @@ print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup') print '
'; $head = reception_admin_prepare_head(); -dol_fiche_head($head, 'reception', $langs->trans("Receptions"), -1, 'reception'); +dol_fiche_head($head, 'reception', $langs->trans("Receptions"), -1, 'sending'); // Reception numbering model diff --git a/htdocs/admin/receptiondet_extrafields.php b/htdocs/admin/receptiondet_extrafields.php new file mode 100644 index 00000000000..80bc3806b52 --- /dev/null +++ b/htdocs/admin/receptiondet_extrafields.php @@ -0,0 +1,127 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2012 Florian Henry + * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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 . + */ + +/** + * \file htdocs/admin/receptiondet_extrafields.php + * \ingroup reception + * \brief Page to setup extra fields of reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + + +if (!$user->admin) + accessforbidden(); + +$langs->load("admin"); +$langs->load("other"); +$langs->load("receptions"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=ExtraFields::$type2label; +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='receptiondet'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("Receptions"); + +llxHeader('',$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print "
\n"; + +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'attributeslines_reception', $langs->trans("Receptions"), -1, 'sending'); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation of an optional field */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print load_fiche_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition of an optional field */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print load_fiche_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php index 36a4ec697e6..cc77ea99e1a 100644 --- a/htdocs/admin/stock.php +++ b/htdocs/admin/stock.php @@ -74,16 +74,22 @@ if($action) // Mode of stock increase if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL' || $action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER' - || $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') + || $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER' + || $action == 'STOCK_CALCULATE_ON_RECEPTION' + || $action == 'STOCK_CALCULATE_ON_RECEPTION_CLOSE') { //Use variable cause empty(GETPOST()) do not work with php version < 5.4 $valdispatch=GETPOST('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER','alpha'); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", '','chaine',0,'',$conf->entity); + $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION", '','chaine',0,'',$conf->entity); + $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION_CLOSE", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", '','chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_BILL','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER','alpha'),'chaine',0,'',$conf->entity); + if ($action == 'STOCK_CALCULATE_ON_RECEPTION') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION", GETPOST('STOCK_CALCULATE_ON_RECEPTION','alpha'),'chaine',0,'',$conf->entity); + if ($action == 'STOCK_CALCULATE_ON_RECEPTION_CLOSE') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION_CLOSE", GETPOST('STOCK_CALCULATE_ON_RECEPTION_CLOSE','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", $valdispatch,'chaine',0,'',$conf->entity); if (empty($valdispatch)) { $res=dolibarr_set_const($db, "SUPPLIER_ORDER_USE_DISPATCH_STATUS", '','chaine',0,'',$conf->entity); @@ -107,6 +113,9 @@ if($action) if($action == 'STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT') { $res = dolibarr_set_const($db, "STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT", GETPOST('STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT','alpha'),'chaine',0,'',$conf->entity); } + if($action == 'STOCK_MUST_BE_ENOUGH_FOR_RECEPTION') { + $res = dolibarr_set_const($db, "STOCK_MUST_BE_ENOUGH_FOR_RECEPTION", GETPOST('STOCK_MUST_BE_ENOUGH_FOR_RECEPTION','alpha'),'chaine',0,'',$conf->entity); + } if($action == 'INDEPENDANT_SUBPRODUCT_STOCK') { $res = dolibarr_set_const($db, "INDEPENDANT_SUBPRODUCT_STOCK", GETPOST('INDEPENDANT_SUBPRODUCT_STOCK','alpha'),'chaine',0,'',$conf->entity); } @@ -307,25 +316,58 @@ else print "\n\n"; $found++; - -print ''; -print ''.$langs->trans("ReStockOnDispatchOrder").''; -print ''; -if (! empty($conf->fournisseur->enabled)) +if (!empty($conf->reception->enabled)) { - print "
"; + print ''; + print ''.$langs->trans("StockOnReception").''; + print ''; + + print ""; print ''; - print ""; - print $form->selectyesno("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER",$conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER,1,$disabled); + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_RECEPTION", $conf->global->STOCK_CALCULATE_ON_RECEPTION, 1, $disabled); print ''; print "
\n"; + + print "\n\n"; + $found++; + + + print ''; + print ''.$langs->trans("StockOnReceptionOnClosing").''; + print ''; + + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_RECEPTION_CLOSE", $conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE, 1, $disabled); + print ''; + print "
\n"; + + print "\n\n"; + $found++; } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + print ''; + print ''.$langs->trans("ReStockOnDispatchOrder").''; + print ''; + if (!empty($conf->fournisseur->enabled)) + { + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", $conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER, 1, $disabled); + print ''; + print "
\n"; + } + else + { + print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + } + print "\n\n"; + $found++; } -print "\n\n"; -$found++; /*if (! $found) { @@ -402,6 +444,20 @@ if($conf->expedition->enabled) { print "\n"; print "\n"; } +if($conf->reception->enabled) { + $var = !$var; + print ''; + print ''.$langs->trans("StockMustBeEnoughForReception").''; + print ''; + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_MUST_BE_ENOUGH_FOR_RECEPTION",$conf->global->STOCK_MUST_BE_ENOUGH_FOR_RECEPTION,1); + print ''; + print '
'; + print "\n"; + print "\n"; +} print ''; $virtualdiffersfromphysical=0; diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index da44eeeb6f6..8e37bee0218 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -415,7 +415,11 @@ class Conf $this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE=0; $this->global->STOCK_CALCULATE_ON_SUPPLIER_BILL=0; $this->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER=0; - $this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER=1; + if(empty($this->reception->enabled))$this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER=1; + else { + $this->global->STOCK_CALCULATE_ON_RECEPTION=1; + $this->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE=0; + } } // conf->currency diff --git a/htdocs/core/lib/fourn.lib.php b/htdocs/core/lib/fourn.lib.php index 44e7774cae6..7be7bbea94e 100644 --- a/htdocs/core/lib/fourn.lib.php +++ b/htdocs/core/lib/fourn.lib.php @@ -111,7 +111,7 @@ function ordersupplier_prepare_head($object) $head[$h][2] = 'card'; $h++; - if (! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) + if (! empty($conf->stock->enabled) && (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))) { $langs->load("stocks"); $head[$h][0] = DOL_URL_ROOT.'/fourn/commande/dispatch.php?id='.$object->id; diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index a3ce8ba52df..48e533b93d5 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -2623,8 +2623,10 @@ elseif (! empty($object->id)) } // Ship - if (! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) + + if (! empty($conf->stock->enabled) && (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))) { + if (in_array($object->statut, array(3,4))) { if ($conf->fournisseur->enabled && $user->rights->fournisseur->commande->receptionner) { print ''; diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql index 789ec3e7a9b..074dc0d4c16 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql @@ -25,6 +25,7 @@ create table llx_commande_fournisseur_dispatch fk_commande integer, fk_product integer, fk_commandefourndet integer, + fk_projet integer DEFAULT NULL, qty float, -- qty fk_entrepot integer, fk_user integer, diff --git a/htdocs/install/mysql/tables/llx_reception.key.sql b/htdocs/install/mysql/tables/llx_reception.key.sql index 736945193ff..a107c2a7d12 100644 --- a/htdocs/install/mysql/tables/llx_reception.key.sql +++ b/htdocs/install/mysql/tables/llx_reception.key.sql @@ -18,14 +18,14 @@ -- =================================================================== -ALTER TABLE llx_expedition ADD UNIQUE INDEX idx_expedition_uk_ref (ref, entity); +ALTER TABLE llx_reception ADD UNIQUE INDEX idx_reception_uk_ref (ref, entity); -ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_soc (fk_soc); -ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_user_author (fk_user_author); -ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_user_valid (fk_user_valid); -ALTER TABLE llx_expedition ADD INDEX idx_expedition_fk_shipping_method (fk_shipping_method); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_soc (fk_soc); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_user_author (fk_user_author); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_user_valid (fk_user_valid); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_shipping_method (fk_shipping_method); -ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); -ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); -ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_user_valid FOREIGN KEY (fk_user_valid) REFERENCES llx_user (rowid); -ALTER TABLE llx_expedition ADD CONSTRAINT fk_expedition_fk_shipping_method FOREIGN KEY (fk_shipping_method) REFERENCES llx_c_shipment_mode (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_user_valid FOREIGN KEY (fk_user_valid) REFERENCES llx_user (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_shipping_method FOREIGN KEY (fk_shipping_method) REFERENCES llx_c_shipment_mode (rowid); diff --git a/htdocs/install/mysql/tables/llx_reception.sql b/htdocs/install/mysql/tables/llx_reception.sql index 088e4893c06..34565f7f29a 100644 --- a/htdocs/install/mysql/tables/llx_reception.sql +++ b/htdocs/install/mysql/tables/llx_reception.sql @@ -19,7 +19,7 @@ -- -- =================================================================== -create table llx_expedition +create table llx_reception ( rowid integer AUTO_INCREMENT PRIMARY KEY, tms timestamp, @@ -30,7 +30,7 @@ create table llx_expedition ref_ext varchar(30), -- reference into an external system (not used by dolibarr) ref_int varchar(30), -- reference into an internal system (used by dolibarr to store extern id like paypal info) - ref_customer varchar(30), -- customer number + ref_supplier varchar(30), -- customer number date_creation datetime, -- date de creation fk_user_author integer, -- author of creation @@ -38,8 +38,7 @@ create table llx_expedition date_valid datetime, -- date de validation fk_user_valid integer, -- valideur date_delivery datetime DEFAULT NULL, -- date planned of delivery - date_expedition datetime, -- not used (deprecated) - fk_address integer DEFAULT NULL, -- delivery address (deprecated) + date_reception datetime, fk_shipping_method integer, tracking_number varchar(50), fk_statut smallint DEFAULT 0, -- 0 = draft, 1 = validated, 2 = billed or closed depending on WORKFLOW_BILL_ON_SHIPMENT option diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql index b539f460a08..f3a35acd8a3 100644 --- a/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql @@ -17,4 +17,4 @@ -- =================================================================== -ALTER TABLE llx_expedition_extrafields ADD INDEX idx_expedition_extrafields (fk_object); +ALTER TABLE llx_reception_extrafields ADD INDEX idx_reception_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.sql index eff8465fbf6..7a3126b2015 100644 --- a/htdocs/install/mysql/tables/llx_reception_extrafields.sql +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.sql @@ -16,7 +16,7 @@ -- -- ======================================================================== -create table llx_expedition_extrafields +create table llx_reception_extrafields ( rowid integer AUTO_INCREMENT PRIMARY KEY, tms timestamp, diff --git a/htdocs/install/mysql/tables/llx_receptiondet.key.sql b/htdocs/install/mysql/tables/llx_receptiondet.key.sql index 5f5b6a08183..3740f83d1d0 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet.key.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet.key.sql @@ -18,5 +18,5 @@ -- =================================================================== -ALTER TABLE llx_expeditiondet ADD INDEX idx_expeditiondet_fk_expedition (fk_expedition); -ALTER TABLE llx_expeditiondet ADD CONSTRAINT fk_expeditiondet_fk_expedition FOREIGN KEY (fk_expedition) REFERENCES llx_expedition (rowid); +ALTER TABLE llx_receptiondet ADD INDEX idx_receptiondet_fk_reception (fk_reception); +ALTER TABLE llx_receptiondet ADD CONSTRAINT fk_receptiondet_fk_reception FOREIGN KEY (fk_reception) REFERENCES llx_reception (rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet.sql b/htdocs/install/mysql/tables/llx_receptiondet.sql index bd05bd08898..dd726c85eab 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet.sql @@ -18,10 +18,10 @@ -- -- =================================================================== -create table llx_expeditiondet +create table llx_receptiondet ( rowid integer AUTO_INCREMENT PRIMARY KEY, - fk_expedition integer NOT NULL, + fk_reception integer NOT NULL, fk_origin_line integer, -- Correspondance de la ligne avec le document d'origine (propal, commande) fk_entrepot integer, -- Entrepot de depart du produit qty real, -- Quantity diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql index 70bfe974f34..59928d1c278 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql @@ -16,5 +16,5 @@ -- -- ============================================================================ -ALTER TABLE llx_expeditiondet_batch ADD INDEX idx_fk_expeditiondet (fk_expeditiondet); -ALTER TABLE llx_expeditiondet_batch ADD CONSTRAINT fk_expeditiondet_batch_fk_expeditiondet FOREIGN KEY (fk_expeditiondet) REFERENCES llx_expeditiondet(rowid); +ALTER TABLE llx_receptiondet_batch ADD INDEX idx_fk_receptiondet (fk_receptiondet); +ALTER TABLE llx_receptiondet_batch ADD CONSTRAINT fk_receptiondet_batch_fk_receptiondet FOREIGN KEY (fk_receptiondet) REFERENCES llx_receptiondet(rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql index 2a1234d9342..ef2537cc116 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql @@ -15,9 +15,9 @@ -- along with this program. If not, see . -- -- ============================================================================ -CREATE TABLE llx_expeditiondet_batch ( +CREATE TABLE llx_receptiondet_batch ( rowid integer AUTO_INCREMENT PRIMARY KEY, - fk_expeditiondet int NOT NULL, + fk_receptiondet int NOT NULL, eatby date DEFAULT NULL, sellby date DEFAULT NULL, batch varchar(30) DEFAULT NULL, diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql index 11e133442d5..5d5d52b5526 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql @@ -17,4 +17,4 @@ -- =================================================================== -ALTER TABLE llx_expeditiondet_extrafields ADD INDEX idx_expeditiondet_extrafields (fk_object); +ALTER TABLE llx_receptiondet_extrafields ADD INDEX idx_receptiondet_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql index e27c7f3e505..5fe823efd76 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql +++ b/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql @@ -16,7 +16,7 @@ -- -- =================================================================== -create table llx_expeditiondet_extrafields +create table llx_receptiondet_extrafields ( rowid integer AUTO_INCREMENT PRIMARY KEY, tms timestamp, diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index bfe6e81858c..e72d093d543 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -1439,11 +1439,9 @@ SendingsAbility=Prise en charge des bons d'expédition pour les livraisons clien NoNeedForDeliveryReceipts=Dans le plupart des cas, la fiche expédition est utilisée en tant que bon d'expédition (liste des produits expédiés) et bon de livraison (signée par le client). Le bon de réception est un doublon de fonctionnalité et est rarement utilisé. FreeLegalTextOnShippings=Mention complémentaire sur les expéditions ##### Reception ##### -ReceptionsSetup=Configuration du module Réception/Livraison +ReceptionsSetup=Configuration du module Réception ReceptionsReceiptModel=Modèles de bordereau de réception ReceptionsNumberingModules=Modèles de numérotation des réceptions -ReceptionsAbility=Prise en charge des bons d'réception pour les livraisons clients -NoNeedForDeliveryReceipts=Dans le plupart des cas, la fiche réception est utilisée en tant que bon d'réception (liste des produits expédiés) et bon de livraison (signée par le client). Le bon de réception est un doublon de fonctionnalité et est rarement utilisé. FreeLegalTextOnShippings=Mention complémentaire sur les réceptions ##### Deliveries ##### DeliveryOrderNumberingModules=Modèle de numérotation des bons de réception client diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index 9a79bf2f8bd..2fb7d558d8e 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -60,6 +60,8 @@ DeStockOnBill=Décrémente les stocks physiques sur validation des factures/avoi DeStockOnValidateOrder=Décrémente les stocks physiques sur validation des commandes clients DeStockOnShipment=Décrémenter les stocks physiques sur validation des expéditions DeStockOnShipmentOnClosing=Décrémenter les stocks réels au classement "clôturée" de l'expédition +StockOnReception=Incrémenter les stocks physiques sur validation des réceptions +StockOnReceptionOnClosing=Incrémenter les stocks réels au classement "clôturée" de la réception ReStockOnBill=Incrémente les stocks physiques sur validation des factures/avoirs fournisseurs ReStockOnValidateOrder=Incrémente les stocks physiques sur approbation des commandes fournisseurs ReStockOnDispatchOrder=Incrémente les stocks réels sur ventilation manuelle dans les entrepôts, après réception de la marchandise @@ -123,9 +125,10 @@ RecordMovement=Enregistrer transfert ReceivingForSameOrder=Réceptions pour cette commande StockMovementRecorded=Mouvement de stocks enregistré RuleForStockAvailability=Règles d'exigence sur les stocks -StockMustBeEnoughForInvoice=Le niveau de stock doit être suffisant pour ajouter ce produit/service à la facture (la vérification est faite sur le stock réel lors de l'ajout de la ligne de facture, quelquesoit la règle de modification automatique de stock) -StockMustBeEnoughForOrder=Le niveau de stock doit être suffisant pour ajouter ce produit/service à la commande (la vérification est faite sur le stock réel lors de l'ajout de la ligne de commande, quelquesoit la règle de modification automatique de stock) -StockMustBeEnoughForShipment= Le niveau de stock doit être suffisant pour ajouter ce produit/service à l'expédition (la vérification est faite sur le stock réel lors de l'ajout de la ligne à l'expédition, quelquesoit la règle de modification automatique de stock) +StockMustBeEnoughForInvoice=Le niveau de stock doit être suffisant pour ajouter ce produit/service à la facture (la vérification est faite sur le stock réel lors de l'ajout de la ligne de facture, quel que soit la règle de modification automatique de stock) +StockMustBeEnoughForOrder=Le niveau de stock doit être suffisant pour ajouter ce produit/service à la commande (la vérification est faite sur le stock réel lors de l'ajout de la ligne de commande, quel que soit la règle de modification automatique de stock) +StockMustBeEnoughForShipment= Le niveau de stock doit être suffisant pour ajouter ce produit/service à l'expédition (la vérification est faite sur le stock réel lors de l'ajout de la ligne à l'expédition, quel que soit la règle de modification automatique de stock) +StockMustBeEnoughForReception= Le niveau de stock doit être suffisant pour ajouter ce produit/service à la réception (la vérification est faite sur le stock réel lors de l'ajout de la ligne à la récepetion, quel que soit la règle de modification automatique de stock) MovementLabel=Libellé du mouvement InventoryCode=Code mouvement ou inventaire IsInPackage=Inclus dans un package diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 05adfc1b5c5..e11a1665866 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3839,6 +3839,9 @@ class Product extends CommonObject $this->stock_theorique=$this->stock_reel-$stock_commande_client; } // Stock Increase mode + if (! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { + $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; + } if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; } diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 5561d5778f6..3cd0b459f13 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -121,7 +121,7 @@ else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas); // Define virtualdiffersfromphysical $virtualdiffersfromphysical=0; -if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) +if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) ) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index e3983344cff..f5d8e358a66 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -75,7 +75,7 @@ if (! empty($canvas)) // Define virtualdiffersfromphysical $virtualdiffersfromphysical=0; -if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) +if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)|| ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php index f45f2b30a56..bf07fa244d2 100644 --- a/htdocs/product/stock/product.php +++ b/htdocs/product/stock/product.php @@ -638,6 +638,8 @@ if ($id > 0 || $ref) $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)?$langs->trans("ReStockOnBill").'
':''); $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)?$langs->trans("ReStockOnValidateOrder").'
':''); $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)?$langs->trans("ReStockOnDispatchOrder").'
':''); + $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)?$langs->trans("StockOnReception").'
':''); + print ''; print $form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1); print ''; diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 28786f0d324..fe74df5e35e 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -80,7 +80,9 @@ if (!$sortorder) { $virtualdiffersfromphysical=0; if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) -|| ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) +|| ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE) +|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) +|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/stock/replenishorders.php b/htdocs/product/stock/replenishorders.php index 694f9cae1ad..3763dc2e8fc 100644 --- a/htdocs/product/stock/replenishorders.php +++ b/htdocs/product/stock/replenishorders.php @@ -113,7 +113,7 @@ $sql.= ' WHERE cf.fk_soc = s.rowid '; $sql.= ' AND cf.entity = ' . $conf->entity; if ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) { $sql .= ' AND cf.fk_statut < 3'; -} elseif ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) { +} elseif ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { $sql .= ' AND cf.fk_statut < 6'; // We want also status 5, we will keep them visible if dispatching is not yet finished (tested with function dolDispatchToDo). } else { $sql .= ' AND cf.fk_statut < 5'; diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php index 324714fee7c..5aabccb8347 100644 --- a/htdocs/reception/class/reception.class.php +++ b/htdocs/reception/class/reception.class.php @@ -51,7 +51,7 @@ class Reception extends CommonObject public $picto = 'reception'; var $socid; - var $ref_customer; + var $ref_supplier; var $ref_int; var $brouillon; var $entrepot_id; @@ -201,7 +201,7 @@ class Reception extends CommonObject $sql = "INSERT INTO ".MAIN_DB_PREFIX."reception ("; $sql.= "ref"; $sql.= ", entity"; - $sql.= ", ref_customer"; + $sql.= ", ref_supplier"; $sql.= ", ref_int"; $sql.= ", date_creation"; $sql.= ", fk_user_author"; @@ -210,7 +210,7 @@ class Reception extends CommonObject $sql.= ", fk_soc"; $sql.= ", fk_projet"; $sql.= ", fk_address"; - $sql.= ", fk_reception_method"; + $sql.= ", fk_shipping_method"; $sql.= ", tracking_number"; $sql.= ", weight"; $sql.= ", size"; @@ -225,7 +225,7 @@ class Reception extends CommonObject $sql.= ") VALUES ("; $sql.= "'(PROV)'"; $sql.= ", ".$conf->entity; - $sql.= ", ".($this->ref_customer?"'".$this->db->escape($this->ref_customer)."'":"null"); + $sql.= ", ".($this->ref_supplier?"'".$this->db->escape($this->ref_supplier)."'":"null"); $sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null"); $sql.= ", '".$this->db->idate($now)."'"; $sql.= ", ".$user->id; @@ -477,10 +477,10 @@ class Reception extends CommonObject // Check parameters if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; - $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut"; + $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_supplier, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut"; $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height"; $sql.= ", e.date_reception as date_reception, e.model_pdf, e.fk_address, e.date_delivery"; - $sql.= ", e.fk_reception_method, e.tracking_number"; + $sql.= ", e.fk_shipping_method, e.tracking_number"; $sql.= ", el.fk_source as origin_id, el.sourcetype as origin"; $sql.= ", e.note_private, e.note_public"; $sql.= ', e.fk_incoterms, e.location_incoterms'; @@ -505,7 +505,7 @@ class Reception extends CommonObject $this->id = $obj->rowid; $this->ref = $obj->ref; $this->socid = $obj->socid; - $this->ref_customer = $obj->ref_customer; + $this->ref_supplier = $obj->ref_supplier; $this->ref_ext = $obj->ref_ext; $this->ref_int = $obj->ref_int; $this->statut = $obj->fk_statut; @@ -517,7 +517,7 @@ class Reception extends CommonObject $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed $this->fk_delivery_address = $obj->fk_address; $this->modelpdf = $obj->model_pdf; - $this->reception_method_id = $obj->fk_reception_method; + $this->shipping_method_id = $obj->fk_shipping_method; $this->tracking_number = $obj->tracking_number; $this->origin = ($obj->origin?$obj->origin:'commande'); // For compatibility $this->origin_id = $obj->origin_id; @@ -1007,7 +1007,7 @@ class Reception extends CommonObject if (isset($this->ref)) $this->ref=trim($this->ref); if (isset($this->entity)) $this->entity=trim($this->entity); - if (isset($this->ref_customer)) $this->ref_customer=trim($this->ref_customer); + if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier); if (isset($this->socid)) $this->socid=trim($this->socid); if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author); if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid); @@ -1035,7 +1035,7 @@ class Reception extends CommonObject $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').","; $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").","; - $sql.= " ref_customer=".(isset($this->ref_customer)?"'".$this->db->escape($this->ref_customer)."'":"null").","; + $sql.= " ref_supplier=".(isset($this->ref_supplier)?"'".$this->db->escape($this->ref_supplier)."'":"null").","; $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").","; $sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').","; $sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").","; @@ -1044,7 +1044,7 @@ class Reception extends CommonObject $sql.= " date_reception=".(dol_strlen($this->date_reception)!=0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').","; $sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').","; $sql.= " fk_address=".(isset($this->fk_delivery_address)?$this->fk_delivery_address:"null").","; - $sql.= " fk_reception_method=".((isset($this->reception_method_id) && $this->reception_method_id > 0)?$this->reception_method_id:"null").","; + $sql.= " fk_shipping_method=".((isset($this->reception_method_id) && $this->reception_method_id > 0)?$this->reception_method_id:"null").","; $sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").","; $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").","; $sql.= " height=".(($this->trueHeight != '')?$this->trueHeight:"null").","; @@ -1498,7 +1498,7 @@ class Reception extends CommonObject $result=''; $label = '' . $langs->trans("ShowReception") . ''; $label .= '
' . $langs->trans('Ref') . ': '.$this->ref; - $label .= '
'.$langs->trans('RefCustomer').': '.($this->ref_customer ? $this->ref_customer : $this->ref_client); + $label .= '
'.$langs->trans('RefCustomer').': '.($this->ref_supplier ? $this->ref_supplier : $this->ref_client); $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id; diff --git a/scripts/reception/create-table.php b/scripts/reception/create-table.php new file mode 100644 index 00000000000..a9f3401f327 --- /dev/null +++ b/scripts/reception/create-table.php @@ -0,0 +1,278 @@ + '--') + { + $buf = preg_replace('/--(.+)*/', '', $buf); + $buffer .= $buf; + } + } + fclose($fp); + + $buffer = trim($buffer); + if ($conf->db->type == 'mysql' || $conf->db->type == 'mysqli') // For Mysql 5.5+, we must replace type=innodb with ENGINE=innodb + { + $buffer = preg_replace('/type=innodb/i', 'ENGINE=innodb', $buffer); + } + else if ($conf->db->type == 'mssql') + { + $buffer = preg_replace('/type=innodb/i', '', $buffer); + $buffer = preg_replace('/ENGINE=innodb/i', '', $buffer); + } + + // Replace the prefix tables + if ($dolibarr_main_db_prefix != 'llx_') + { + $buffer = preg_replace('/llx_/i', $dolibarr_main_db_prefix, $buffer); + } + + //print "Creation de la table $name/td>"; + $requestnb++; + + $resql = $db->query($buffer, 0, 'dml'); + if ($resql) + { + // print "OK requete ==== $buffer"; + $db->free($resql); + } + else + { + if ($db->errno() == 'DB_ERROR_TABLE_ALREADY_EXISTS' || + $db->errno() == 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS') + { + //print "Deja existante"; + } + else + { + print "".$langs->trans("CreateTableAndPrimaryKey", $name); + print "
\n".$langs->trans("Request").' '.$requestnb.' : '.$buffer.'
Executed query : '.$db->lastquery; + print "\n"; + print ''.$langs->trans("ErrorSQL")." ".$db->errno()." ".$db->error().''; + $error++; + } + } + } + else + { + print "".$langs->trans("CreateTableAndPrimaryKey", $name); + print ""; + print ''.$langs->trans("Error").' Failed to open file '.$dir.$file.''; + $error++; + } +} + +if ($tablefound) +{ + if ($error == 0) + { + print ''; + print $langs->trans("TablesAndPrimaryKeysCreation").'Ok'; + $ok = 1; + } +} +else +{ + print ''.$langs->trans("ErrorFailedToFindSomeFiles", $dir).'Error'; +} + + + +// We always choose in mysql directory (Conversion is done by driver to translate SQL syntax) + + +$okkeys = 0; +$handle = opendir($dir); +$tablefound = 0; +$tabledata = array(); +if (is_resource($handle)) +{ + while (($file = readdir($handle)) !== false) + { + if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && preg_match('/\.key\.sql$/i', $file)) + { + if (strpos($file, 'reception') !== false){ + $tablefound++; + $tabledata[] = $file; + } + } + } + closedir($handle); +} + +// Sort list of sql files on alphabetical order (load order is important) +sort($tabledata); +foreach ($tabledata as $file) +{ + $name = substr($file, 0, dol_strlen($file) - 4); + //print "Creation de la table $name"; + $buffer = ''; + $fp = fopen($dir.$file, "r"); + if ($fp) + { + while (!feof($fp)) + { + $buf = fgets($fp, 4096); + + // Cas special de lignes autorisees pour certaines versions uniquement + if ($choix == 1 && preg_match('/^--\sV([0-9\.]+)/i', $buf, $reg)) + { + $versioncommande = explode('.', $reg[1]); + //print var_dump($versioncommande); + //print var_dump($versionarray); + if (count($versioncommande) && count($versionarray) && versioncompare($versioncommande, $versionarray) <= 0) + { + // Version qualified, delete SQL comments + $buf = preg_replace('/^--\sV([0-9\.]+)/i', '', $buf); + //print "Ligne $i qualifiee par version: ".$buf.'
'; + } + } + if ($choix == 2 && preg_match('/^--\sPOSTGRESQL\sV([0-9\.]+)/i', $buf, $reg)) + { + $versioncommande = explode('.', $reg[1]); + //print var_dump($versioncommande); + //print var_dump($versionarray); + if (count($versioncommande) && count($versionarray) && versioncompare($versioncommande, $versionarray) <= 0) + { + // Version qualified, delete SQL comments + $buf = preg_replace('/^--\sPOSTGRESQL\sV([0-9\.]+)/i', '', $buf); + //print "Ligne $i qualifiee par version: ".$buf.'
'; + } + } + + // Ajout ligne si non commentaire + if (!preg_match('/^--/i', $buf)) + $buffer .= $buf; + } + fclose($fp); + + // Si plusieurs requetes, on boucle sur chaque + $listesql = explode(';', $buffer); + foreach ($listesql as $req) + { + $buffer = trim($req); + if ($buffer) + { + // Replace the prefix tables + if ($dolibarr_main_db_prefix != 'llx_') + { + $buffer = preg_replace('/llx_/i', $dolibarr_main_db_prefix, $buffer); + } + + //print "Creation des cles et index de la table $name: '$buffer'"; + $requestnb++; + + $resql = $db->query($buffer, 0, 'dml'); + if ($resql) + { + //print "OK requete ==== $buffer"; + $db->free($resql); + } + else + { + if ($db->errno() == 'DB_ERROR_KEY_NAME_ALREADY_EXISTS' || + $db->errno() == 'DB_ERROR_CANNOT_CREATE' || + $db->errno() == 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS' || + $db->errno() == 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS' || + preg_match('/duplicate key name/i', $db->error())) + { + //print "Deja existante"; + $key_exists = 1; + } + else + { + print "".$langs->trans("CreateOtherKeysForTable", $name); + print "
\n".$langs->trans("Request").' '.$requestnb.' : '.$db->lastqueryerror(); + print "\n"; + print ''.$langs->trans("ErrorSQL")." ".$db->errno()." ".$db->error().''; + $error++; + } + } + } + } + } + else + { + print "".$langs->trans("CreateOtherKeysForTable", $name); + print ""; + print ''.$langs->trans("Error")." Failed to open file ".$dir.$file.""; + $error++; + } +} + +if ($tablefound && $error == 0) +{ + print ''; + print $langs->trans("OtherKeysCreation").'Ok'; + $okkeys = 1; +} + \ No newline at end of file From 00f532c43623443a8e8647f81e5a39772d9e4994 Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Thu, 4 Oct 2018 09:50:39 +0200 Subject: [PATCH 05/50] =?UTF-8?q?validation=20mod=C3=A8le=20de=20donn?= =?UTF-8?q?=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ande_fournisseur_dispatch_extrafields.php} | 4 +-- htdocs/core/lib/reception.lib.php | 2 +- .../llx_commande_fournisseur_dispatch.key.sql | 4 ++- .../llx_commande_fournisseur_dispatch.sql | 1 + ..._fournisseur_dispatch_extrafields.key.sql} | 2 +- ...ande_fournisseur_dispatch_extrafields.sql} | 2 +- .../mysql/tables/llx_receptiondet.key.sql | 22 -------------- .../install/mysql/tables/llx_receptiondet.sql | 29 ------------------- .../tables/llx_receptiondet_batch.key.sql | 20 ------------- .../mysql/tables/llx_receptiondet_batch.sql | 27 ----------------- scripts/reception/create-table.php | 4 +-- 11 files changed, 11 insertions(+), 106 deletions(-) rename htdocs/admin/{receptiondet_extrafields.php => commande_fournisseur_dispatch_extrafields.php} (95%) rename htdocs/install/mysql/tables/{llx_receptiondet_extrafields.key.sql => llx_commande_fournisseur_dispatch_extrafields.key.sql} (87%) rename htdocs/install/mysql/tables/{llx_receptiondet_extrafields.sql => llx_commande_fournisseur_dispatch_extrafields.sql} (94%) delete mode 100644 htdocs/install/mysql/tables/llx_receptiondet.key.sql delete mode 100644 htdocs/install/mysql/tables/llx_receptiondet.sql delete mode 100644 htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql delete mode 100644 htdocs/install/mysql/tables/llx_receptiondet_batch.sql diff --git a/htdocs/admin/receptiondet_extrafields.php b/htdocs/admin/commande_fournisseur_dispatch_extrafields.php similarity index 95% rename from htdocs/admin/receptiondet_extrafields.php rename to htdocs/admin/commande_fournisseur_dispatch_extrafields.php index 80bc3806b52..68246b675e5 100644 --- a/htdocs/admin/receptiondet_extrafields.php +++ b/htdocs/admin/commande_fournisseur_dispatch_extrafields.php @@ -25,7 +25,7 @@ */ /** - * \file htdocs/admin/receptiondet_extrafields.php + * \file htdocs/admin/commandefournisseurdispatch_extrafields.php * \ingroup reception * \brief Page to setup extra fields of reception */ @@ -52,7 +52,7 @@ foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); $action=GETPOST('action', 'alpha'); $attrname=GETPOST('attrname', 'alpha'); -$elementtype='receptiondet'; //Must be the $table_element of the class that manage extrafield +$elementtype='commande_fournisseur_dispatch'; //Must be the $table_element of the class that manage extrafield if (!$user->admin) accessforbidden(); diff --git a/htdocs/core/lib/reception.lib.php b/htdocs/core/lib/reception.lib.php index 34cd46026ed..b3c32ee60b4 100644 --- a/htdocs/core/lib/reception.lib.php +++ b/htdocs/core/lib/reception.lib.php @@ -85,7 +85,7 @@ function reception_admin_prepare_head() if (! empty($conf->global->MAIN_SUBMODULE_RECEPTION)) { - $head[$h][0] = DOL_URL_ROOT.'/admin/receptiondet_extrafields.php'; + $head[$h][0] = DOL_URL_ROOT.'/admin/commande_fournisseur_dispatch_extrafields.php'; $head[$h][1] = $langs->trans("ExtraFieldsLines"); $head[$h][2] = 'attributeslines_reception'; $h++; diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql index ba7c02280ec..369a25f2b32 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql @@ -16,4 +16,6 @@ -- -- =================================================================== -ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_commande (fk_commande); \ No newline at end of file +ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_commande (fk_commande); +ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_reception (fk_reception); +ALTER TABLE llx_commande_fournisseur_dispatch ADD CONSTRAINT fk_commande_fournisseur_dispatch_fk_reception FOREIGN KEY (fk_reception) REFERENCES llx_reception (rowid); \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql index 074dc0d4c16..9a6e05d1af1 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql @@ -26,6 +26,7 @@ create table llx_commande_fournisseur_dispatch fk_product integer, fk_commandefourndet integer, fk_projet integer DEFAULT NULL, + fk_reception integer DEFAULT NULL, qty float, -- qty fk_entrepot integer, fk_user integer, diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql similarity index 87% rename from htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql rename to htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql index 5d5d52b5526..c836fbaea6a 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.key.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql @@ -17,4 +17,4 @@ -- =================================================================== -ALTER TABLE llx_receptiondet_extrafields ADD INDEX idx_receptiondet_extrafields (fk_object); +ALTER TABLE llx_commande_fournisseur_dispatch_extrafields ADD INDEX idx_commande_fournisseur_dispatch_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql similarity index 94% rename from htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql rename to htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql index 5fe823efd76..f00eabf42fa 100644 --- a/htdocs/install/mysql/tables/llx_receptiondet_extrafields.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql @@ -16,7 +16,7 @@ -- -- =================================================================== -create table llx_receptiondet_extrafields +create table llx_commande_fournisseur_dispatch_extrafields ( rowid integer AUTO_INCREMENT PRIMARY KEY, tms timestamp, diff --git a/htdocs/install/mysql/tables/llx_receptiondet.key.sql b/htdocs/install/mysql/tables/llx_receptiondet.key.sql deleted file mode 100644 index 3740f83d1d0..00000000000 --- a/htdocs/install/mysql/tables/llx_receptiondet.key.sql +++ /dev/null @@ -1,22 +0,0 @@ --- =================================================================== --- Copyright (C) 2005 Laurent Destailleur --- Copyright (C) 2008 Regis Houssin --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 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 . --- --- =================================================================== - - -ALTER TABLE llx_receptiondet ADD INDEX idx_receptiondet_fk_reception (fk_reception); -ALTER TABLE llx_receptiondet ADD CONSTRAINT fk_receptiondet_fk_reception FOREIGN KEY (fk_reception) REFERENCES llx_reception (rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet.sql b/htdocs/install/mysql/tables/llx_receptiondet.sql deleted file mode 100644 index dd726c85eab..00000000000 --- a/htdocs/install/mysql/tables/llx_receptiondet.sql +++ /dev/null @@ -1,29 +0,0 @@ --- =================================================================== --- Copyright (C) 2003 Rodolphe Quiedeville --- Copyright (C) 2008 Regis Houssin --- Copyright (C) 2011 Laurent Destailleur --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 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 . --- --- =================================================================== - -create table llx_receptiondet -( - rowid integer AUTO_INCREMENT PRIMARY KEY, - fk_reception integer NOT NULL, - fk_origin_line integer, -- Correspondance de la ligne avec le document d'origine (propal, commande) - fk_entrepot integer, -- Entrepot de depart du produit - qty real, -- Quantity - rang integer DEFAULT 0 -)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql deleted file mode 100644 index 59928d1c278..00000000000 --- a/htdocs/install/mysql/tables/llx_receptiondet_batch.key.sql +++ /dev/null @@ -1,20 +0,0 @@ --- ============================================================================ --- Copyright (C) 2014 Cédric GROSS --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 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 . --- --- ============================================================================ - -ALTER TABLE llx_receptiondet_batch ADD INDEX idx_fk_receptiondet (fk_receptiondet); -ALTER TABLE llx_receptiondet_batch ADD CONSTRAINT fk_receptiondet_batch_fk_receptiondet FOREIGN KEY (fk_receptiondet) REFERENCES llx_receptiondet(rowid); diff --git a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql b/htdocs/install/mysql/tables/llx_receptiondet_batch.sql deleted file mode 100644 index ef2537cc116..00000000000 --- a/htdocs/install/mysql/tables/llx_receptiondet_batch.sql +++ /dev/null @@ -1,27 +0,0 @@ --- ============================================================================ --- Copyright (C) 2014 Cédric GROSS --- --- This program is free software; you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation; either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- 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 . --- --- ============================================================================ -CREATE TABLE llx_receptiondet_batch ( - rowid integer AUTO_INCREMENT PRIMARY KEY, - fk_receptiondet int NOT NULL, - eatby date DEFAULT NULL, - sellby date DEFAULT NULL, - batch varchar(30) DEFAULT NULL, - qty double NOT NULL DEFAULT '0', - fk_origin_stock integer NOT NULL -) ENGINE=InnoDB; - diff --git a/scripts/reception/create-table.php b/scripts/reception/create-table.php index a9f3401f327..c65292da04b 100644 --- a/scripts/reception/create-table.php +++ b/scripts/reception/create-table.php @@ -47,7 +47,7 @@ if (is_resource($handle)) { if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && !preg_match('/\.key\.sql$/i', $file)) { - if (strpos($file, 'reception') !== false){ + if (strpos($file, 'reception') !== false || strpos($file, 'commande_fournisseur_dispatch') !== false){ $tablefound++; $tabledata[] = $file; } @@ -160,7 +160,7 @@ if (is_resource($handle)) { if (preg_match('/\.sql$/i', $file) && preg_match('/^llx_/i', $file) && preg_match('/\.key\.sql$/i', $file)) { - if (strpos($file, 'reception') !== false){ + if (strpos($file, 'reception') !== false || strpos($file, 'commande_fournisseur_dispatch') !== false){ $tablefound++; $tabledata[] = $file; } From bc07936d4249b8eb2a60a91c8e8366cff33b30bc Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Thu, 4 Oct 2018 10:17:18 +0200 Subject: [PATCH 06/50] NEW list on dispatch --- htdocs/fourn/commande/dispatch.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index f4f05f96b78..0436c33f3ad 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -46,6 +46,7 @@ $langs->load('bills'); $langs->load('deliveries'); $langs->load('products'); $langs->load('stocks'); +$langs->load('receptions'); if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); @@ -738,6 +739,7 @@ if ($id > 0 || ! empty($ref)) { $sql = "SELECT p.ref, p.label,"; $sql .= " e.rowid as warehouse_id, e.label as entrepot,"; $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status"; + if($conf->reception->enabled)$sql.=" ,cfd.fk_reception"; $sql .= " FROM " . MAIN_DB_PREFIX . "product as p,"; $sql .= " " . MAIN_DB_PREFIX . "commande_fournisseur_dispatch as cfd"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "entrepot as e ON cfd.fk_entrepot = e.rowid"; @@ -759,6 +761,7 @@ if ($id > 0 || ! empty($ref)) { print ''; print ''; + if($conf->reception->enabled)print ''; print ''; if (! empty($conf->productbatch->enabled)) { print ''; @@ -769,7 +772,7 @@ if ($id > 0 || ! empty($ref)) { print ''; print ''; print ''; - if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) || !empty($conf->reception->enabled)) print ''; print "\n"; @@ -777,9 +780,18 @@ if ($id > 0 || ! empty($ref)) { while ( $i < $num ) { $objp = $db->fetch_object($resql); - + + + print ""; print '"; + print '\n"; @@ -805,7 +817,7 @@ if ($id > 0 || ! empty($ref)) { print ''; // Status - if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) { + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) { print ''; + }else if(!empty($conf->reception->enabled)){ + print ''; + print ''; + } print "\n"; From 5fe767d7bdcf9007af06d834222bd169334401e5 Mon Sep 17 00:00:00 2001 From: atm-quentin Date: Thu, 4 Oct 2018 12:27:10 +0200 Subject: [PATCH 07/50] debut card create --- .../class/fournisseur.commande.class.php | 48 ++ htdocs/fourn/commande/dispatch.php | 39 +- htdocs/langs/fr_FR/receptions.lang | 30 +- htdocs/reception/card.php | 434 ++++++++++-------- 4 files changed, 328 insertions(+), 223 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 073f399e324..aa596170cbf 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -2936,6 +2936,54 @@ class CommandeFournisseur extends CommonOrder } return 0; } + + /** + * Load array this->receptions of lines of shipments with nb of products sent for each order line + * Note: For a dedicated shipment, the fetch_lines can be used to load the qty_asked and qty_shipped. This function is use to return qty_shipped cumulated for the order + * + * @param int $filtre_statut Filter on shipment status + * @return int <0 if KO, Nb of lines found if OK + */ + function loadReceptions($filtre_statut=-1) + { + $this->receptions = array(); + + $sql = 'SELECT cd.rowid, cd.fk_product,'; + $sql.= ' sum(cfd.qty) as qty'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch as cfd,'; + if ($filtre_statut >= 0) $sql.= ' '.MAIN_DB_PREFIX.'reception as e,'; + $sql.= ' '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd'; + $sql.= ' WHERE'; + if ($filtre_statut >= 0) $sql.= ' cfd.fk_reception = e.rowid AND'; + $sql.= ' cfd.commandefourndet = cd.rowid'; + $sql.= ' AND cd.fk_commande =' .$this->id; + if ($this->fk_product > 0) $sql.= ' AND cd.fk_product = '.$this->fk_product; + if ($filtre_statut >= 0) $sql.=' AND e.fk_statut >= '.$filtre_statut; + $sql.= ' GROUP BY cd.rowid, cd.fk_product'; + //print $sql; + + dol_syslog(get_class($this)."::loadReceptions", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); + $this->receptions[$obj->rowid] = $obj->qty; + $i++; + } + $this->db->free(); + return $num; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + + } } diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 0436c33f3ad..eba1df3bbf6 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -382,8 +382,8 @@ if ($id > 0 || ! empty($ref)) { $morehtmlref.=' : '; if ($action == 'classify') { //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); - $morehtmlref.='
'; - $morehtmlref.=''; + $morehtmlref.=''; + $morehtmlref.=''; $morehtmlref.=''; $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); $morehtmlref.=''; @@ -452,9 +452,13 @@ if ($id > 0 || ! empty($ref)) { $entrepot = new Entrepot($db); $listwarehouses = $entrepot->list_array(1); - print ''; + if(empty($conf->reception->enabled))print ''; + else print ''; + print ''; - print ''; + + if(empty($conf->reception->enabled))print ''; + else print ''; print '
'; print '
' . $langs->trans("Reception") . '' . $langs->trans("Product") . '' . $langs->trans("batch_number") . '' . $langs->trans("Warehouse") . '' . $langs->trans("Comment") . '' . $langs->trans("Status") . '
'; + if(!empty($conf->reception->enabled) && !empty($objp->fk_reception)){ + $reception = new Reception($db); + $reception->fetch($objp->fk_reception); + print $reception->getNomUrl(); + } + print "'; print '' . img_object($langs->trans("ShowProduct"), 'product') . ' ' . $objp->ref . ''; print ' - ' . $objp->label; print "' . $objp->comment . ''; $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status); // print $supplierorderdispatch->status; @@ -841,6 +853,15 @@ if ($id > 0 || ! empty($ref)) { } } print ''; + if(!empty($reception->rowid)){ + print $reception->getLibStatut(5); + } + print ''; + print '
'; @@ -703,7 +707,7 @@ if ($id > 0 || ! empty($ref)) { if ($nbproduct) { - $checkboxlabel=$langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv($object->statuts[5])); + $checkboxlabel=$langs->trans("CloseReceivedSupplierOrdersAutomatically", $langs->transnoentitiesnoconv($object->statuts[5])); print '
'; print $langs->trans("Comment") . ' : '; @@ -712,9 +716,11 @@ if ($id > 0 || ! empty($ref)) { // print ' / '.$object->ref_supplier; // Not yet available print '" class="flat">
'; - print ' '.$checkboxlabel; - - print '
reception->enabled))print ' '.$checkboxlabel; + + empty($conf->reception->enabled)?$dispatchBt=$langs->trans("DispatchVerb"):$dispatchBt=$langs->trans("Receive"); + + print '
'; @@ -784,13 +790,18 @@ if ($id > 0 || ! empty($ref)) { print "
"; - print '"; } - print ""; + print ''; print "\n"; - // Ref client print ''; print ''; @@ -1073,8 +1075,8 @@ if ($action == 'create') // Delivery method print ""; print '\n"; @@ -1086,7 +1088,7 @@ if ($action == 'create') // Other attributes $parameters = array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"', 'socid'=>$socid); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$expe,$action); // Note that $action and $object may have been modified by hook + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$recept,$action); // Note that $action and $object may have been modified by hook print $hookmanager->resPrint; if (empty($reshook) && ! empty($extrafields->attribute_label)) { @@ -1094,7 +1096,7 @@ if ($action == 'create') $orderExtrafields = new Extrafields($db); $orderExtrafieldLabels = $orderExtrafields->fetch_name_optionals_label($object->table_element); if ($object->fetch_optionals($object->id, $orderExtrafieldLabels) > 0) { - $expe->array_options = array_merge($expe->array_options, $object->array_options); + $recept->array_options = array_merge($recept->array_options, $object->array_options); } print $object->showOptionals($extrafields, 'edit'); } @@ -1111,13 +1113,13 @@ if ($action == 'create') } // Document model - include_once DOL_DOCUMENT_ROOT . '/core/modules/expedition/modules_expedition.php'; - $liste = ModelePdfExpedition::liste_modeles($db); + include_once DOL_DOCUMENT_ROOT . '/core/modules/reception/modules_reception.php'; + $liste = ModelePdfReception::liste_modeles($db); if (count($liste) > 1) { print ""; print '\n"; } @@ -1126,9 +1128,48 @@ if ($action == 'create') dol_fiche_end(); - // Shipment lines + // Reception lines + $numAsked=0; + $dispatchLines = array(); + foreach ($_POST as $key => $value) + { + // without batch module enabled + if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) + { + - $numAsked = count($object->lines); + // $numline=$reg[2] + 1; // line of product + $numline = $numAsked; + $prod = "product_".$reg[1].'_'.$reg[2]; + $qty = "qty_".$reg[1].'_'.$reg[2]; + $ent = "entrepot_".$reg[1].'_'.$reg[2]; + $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount + $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2]; + $dispatchLines[$numAsked]=array('prod' => GETPOST($prod, 'int'), 'qty' =>GETPOST($qty), 'ent' =>GETPOST($ent, 'int'), 'pu' =>GETPOST($pu), 'comment' =>GETPOST('comment'),'fk_commandefourndet' => GETPOST($fk_commandefourndet, 'int')); + + $numAsked ++; + } + // with batch module enabled + if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) + { + + + // eat-by date dispatch + // $numline=$reg[2] + 1; // line of product + $numline = $numAsked; + $prod = 'product_batch_'.$reg[1].'_'.$reg[2]; + $qty = 'qty_'.$reg[1].'_'.$reg[2]; + $ent = 'entrepot_'.$reg[1].'_'.$reg[2]; + $pu = 'pu_'.$reg[1].'_'.$reg[2]; + $lot = 'lot_number_'.$reg[1].'_'.$reg[2]; + $dDLUO = dol_mktime(12, 0, 0, $_POST['dluo_'.$reg[1].'_'.$reg[2].'month'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'day'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'year']); + $dDLC = dol_mktime(12, 0, 0, $_POST['dlc_'.$reg[1].'_'.$reg[2].'month'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'day'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'year']); + $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2]; + $dispatchLines[$numAsked]=array('prod' => GETPOST($prod, 'int'), 'qty' =>GETPOST($qty), 'ent' =>GETPOST($ent, 'int'), 'pu' =>GETPOST($pu), 'comment' =>GETPOST('comment'),'fk_commandefourndet' => GETPOST($fk_commandefourndet, 'int'),'DLC'=> $dDLC,'DLUO'=> $dDLUO,'lot'=> GETPOST($lot, 'alpha')); + $numAsked ++; + } + } + $numAsked --; print '
'; - if(!empty($conf->reception->enabled) && !empty($objp->fk_reception)){ - $reception = new Reception($db); - $reception->fetch($objp->fk_reception); - print $reception->getNomUrl(); + + if(!empty($conf->reception->enabled) ){ + print ''; + if (!empty($objp->fk_reception)){ + $reception = new Reception($db); + $reception->fetch($objp->fk_reception); + print $reception->getNomUrl(); + } + + print "'; print '' . img_object($langs->trans("ShowProduct"), 'product') . ' ' . $objp->ref . ''; print ' - ' . $objp->label; diff --git a/htdocs/langs/fr_FR/receptions.lang b/htdocs/langs/fr_FR/receptions.lang index 7522dc6eb51..0939ae18319 100644 --- a/htdocs/langs/fr_FR/receptions.lang +++ b/htdocs/langs/fr_FR/receptions.lang @@ -3,8 +3,8 @@ RefReception=Réf. réception Reception=Réception Receptions=Réceptions AllReceptions=Toutes les réceptions -Shipment=Réception -Shipments=Réceptions +Reception=Réception +Receptions=Réceptions ShowReception=Afficher Réceptions Receivings=Bons de réceptions ReceptionsArea=Espace réceptions @@ -13,15 +13,15 @@ ReceptionMethod=Méthode d'réception LastReceptions=Les %s dernières réceptions StatisticsOfReceptions=Statistiques des réceptions NbOfReceptions=Nombre d'réceptions -NumberOfShipmentsByMonth=Nombre d'réceptions par mois +NumberOfReceptionsByMonth=Nombre d'réceptions par mois ReceptionCard=Fiche réception NewReception=Nouvelle réception -CreateShipment=Créer réception +CreateReception=Créer réception QtyShipped=Qté. expédiée QtyPreparedOrShipped=Quantité préparée ou envoyée -QtyToShip=Qté. à expédier +QtyToReceive=Qté. à recevoir QtyReceived=Qté. reçue -QtyInOtherShipments=Qté dans les autres réceptions +QtyInOtherReceptions=Qté dans les autres réceptions KeepToShip=Reste à expédier OtherReceptionsForSameOrder=Autres réceptions pour cette commande ReceptionsAndReceivingForSameOrder=Réceptions et réceptions pour cette commande @@ -39,24 +39,24 @@ ConfirmValidateReception=Êtes-vous sûr de vouloir valider cette réception sou ConfirmCancelReception=Êtes-vous sûr de vouloir annuler cette réception ? DocumentModelMerou=Modèle Merou A5 WarningNoQtyLeftToSend=Alerte, aucun produit en attente d'réception. -StatsOnShipmentsOnlyValidated=Statistiques effectuées sur les réceptions validées uniquement. La date prise en compte est la date de validation (la date de prévision de livraison n'étant pas toujours renseignée). +StatsOnReceptionsOnlyValidated=Statistiques effectuées sur les réceptions validées uniquement. La date prise en compte est la date de validation (la date de prévision de livraison n'étant pas toujours renseignée). DateDeliveryPlanned=Date prévue de livraison RefDeliveryReceipt=Ref bon de réception StatusReceipt=Status du bon de réception DateReceived=Date de réception réelle -SendShippingByEMail=Envoyer bon d'réception par email -SendShippingRef=Envoi du bordereau d'réception %s -ActionsOnShipping=Événements sur l'réception +SendReceptionByEMail=Envoyer bon d'réception par email +SendReceptionRef=Envoi du bordereau d'réception %s +ActionsOnReception=Événements sur l'réception LinkToTrackYourPackage=Lien pour le suivi de votre colis -ShipmentCreationIsDoneFromOrder=Pour le moment, la création d'une nouvelle réception se fait depuis la fiche commande. -ShipmentLine=Ligne d'réception +ReceptionCreationIsDoneFromOrder=Pour le moment, la création d'une nouvelle réception se fait depuis la fiche commande fournisseur. +ReceptionLine=Ligne d'réception ProductQtyInCustomersOrdersRunning=Quantité de produit en commandes client ouvertes ProductQtyInSuppliersOrdersRunning=Quantité de produit en commandes fournisseur ouvertes -ProductQtyInShipmentAlreadySent=Quantité de produit en commande client ouverte déjà expédiée -ProductQtyInSuppliersShipmentAlreadyRecevied=Quantité de produit déjà reçu en commandes fournisseur ouvertes +ProductQtyInReceptionAlreadySent=Quantité de produit en commande client ouverte déjà expédiée +ProductQtyInSuppliersReceptionAlreadyRecevied=Quantité de produit déjà reçu en commandes fournisseur ouvertes NoProductToShipFoundIntoStock=Aucun produit à expédier n'a été trouver dans l'entrepôt %s. Corrigez l'inventaire ou retourner choisir un autre entrepôt. WeightVolShort=Poids/vol. -ValidateOrderFirstBeforeShipment=Vous devez d'abord valider la commande pour pouvoir créer une réception. +ValidateOrderFirstBeforeReception=Vous devez d'abord valider la commande pour pouvoir créer une réception. # Reception methods # ModelDocument diff --git a/htdocs/reception/card.php b/htdocs/reception/card.php index fbe7d81622c..4be1dc7f822 100644 --- a/htdocs/reception/card.php +++ b/htdocs/reception/card.php @@ -27,41 +27,42 @@ */ /** - * \file htdocs/expedition/card.php - * \ingroup expedition - * \brief Card of a shipment + * \file htdocs/reception/card.php + * \ingroup reception + * \brief Card of a reception */ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; -require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/sendings.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; -if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +if (! empty($conf->fournisseur->enabled)) require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.class.php'; if (! empty($conf->projet->enabled)) { require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; } -$langs->loadLangs(array("sendings","companies","bills",'deliveries','orders','stocks','other','propal')); +$langs->loadLangs(array("receptions","companies","bills",'deliveries','orders','stocks','other','propal')); if (!empty($conf->incoterm->enabled)) $langs->load('incoterm'); if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); -$origin = GETPOST('origin','alpha')?GETPOST('origin','alpha'):'expedition'; // Example: commande, propal +$origin = GETPOST('origin','alpha')?GETPOST('origin','alpha'):'reception'; // Example: commande, propal $origin_id = GETPOST('id','int')?GETPOST('id','int'):''; $id = $origin_id; if (empty($origin_id)) $origin_id = GETPOST('origin_id','int'); // Id of order or propal if (empty($origin_id)) $origin_id = GETPOST('object_id','int'); // Id of order or propal +if (empty($origin_id)) $origin_id = GETPOST('originid','int'); // Id of order or propal $ref=GETPOST('ref','alpha'); $line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; @@ -69,10 +70,12 @@ $line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; $socid=''; if ($user->societe_id) $socid=$user->societe_id; -if ($origin == 'expedition') $result=restrictedArea($user, $origin, $id); +if ($origin == 'reception') $result=restrictedArea($user, $origin, $id); else { - $result=restrictedArea($user, 'expedition'); - if (empty($user->rights->{$origin}->lire) && empty($user->rights->{$origin}->read)) accessforbidden(); + $result=restrictedArea($user, 'reception'); + if($origin == 'supplierorder'){ + if (empty($user->rights->fournisseur->commande->lire) && empty($user->rights->fournisseur->commande->read)) accessforbidden(); + }else if (empty($user->rights->{$origin}->lire) && empty($user->rights->{$origin}->read)) accessforbidden(); } $action = GETPOST('action','alpha'); @@ -84,7 +87,7 @@ $hidedetails = (GETPOST('hidedetails','int') ? GETPOST('hidedetails','int') : (! $hidedesc = (GETPOST('hidedesc','int') ? GETPOST('hidedesc','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0)); $hideref = (GETPOST('hideref','int') ? GETPOST('hideref','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0)); -$object = new Expedition($db); +$object = new Reception($db); $extrafields = new ExtraFields($db); $extrafieldsline = new ExtraFields($db); @@ -99,9 +102,9 @@ $extralabelslines=$extrafieldsline->fetch_name_optionals_label($object->table_el include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context -$hookmanager->initHooks(array('expeditioncard','globalcard')); +$hookmanager->initHooks(array('receptioncard','globalcard')); -$permissiondellink=$user->rights->expedition->livraison->creer; // Used by the include of actions_dellink.inc.php +$permissiondellink=$user->rights->reception->livraison->creer; // Used by the include of actions_dellink.inc.php //var_dump($object->lines[0]->detail_batch); @@ -118,20 +121,20 @@ if (empty($reshook)) if ($cancel) { $action = ''; - $object->fetch($id); // show shipment also after canceling modification + $object->fetch($id); // show reception also after canceling modification } include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once // Reopen - if ($action == 'reopen' && $user->rights->expedition->creer) + if ($action == 'reopen' && $user->rights->reception->creer) { $object->fetch($id); $result = $object->reOpen(); } // Confirm back to draft status - if ($action == 'modif' && $user->rights->expedition->creer) + if ($action == 'modif' && $user->rights->reception->creer) { $result = $object->set_draft($user); if ($result >= 0) @@ -167,7 +170,7 @@ if (empty($reshook)) setEventMessages($object->error, $object->errors, 'errors'); } - $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer','alpha'), '', null, 'text', '', $user, 'SHIPMENT_MODIFY'); + $result = $object->setValueFrom('ref_customer', GETPOST('ref_customer','alpha'), '', null, 'text', '', $user, 'RECEPTION_MODIFY'); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); $action = 'editref_customer'; @@ -188,7 +191,7 @@ if (empty($reshook)) { // Actions on extra fields (by external module or standard code) // TODO le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('expeditiondao')); + $hookmanager->initHooks(array('receptiondao')); $parameters = array('id' => $object->id); $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { @@ -206,8 +209,8 @@ if (empty($reshook)) $action = 'edit_extras'; } - // Create shipment - if ($action == 'add' && $user->rights->expedition->creer) + // Create reception + if ($action == 'add' && $user->rights->reception->creer) { $error=0; $predef=''; @@ -227,7 +230,7 @@ if (empty($reshook)) $date_delivery = dol_mktime(GETPOST('date_deliveryhour','int'), GETPOST('date_deliverymin','int'), 0, GETPOST('date_deliverymonth','int'), GETPOST('date_deliveryday','int'), GETPOST('date_deliveryyear','int')); - // On va boucler sur chaque ligne du document d'origine pour completer objet expedition + // On va boucler sur chaque ligne du document d'origine pour completer objet reception // avec info diverses + qte a livrer $classname = ucfirst($object->origin); $objectsrc = new $classname($db); @@ -238,7 +241,7 @@ if (empty($reshook)) $object->model_pdf = GETPOST('model'); $object->date_delivery = $date_delivery; // Date delivery planed $object->fk_delivery_address = $objectsrc->fk_delivery_address; - $object->shipping_method_id = GETPOST('shipping_method_id','int'); + $object->reception_method_id = GETPOST('reception_method_id','int'); $object->tracking_number = GETPOST('tracking_number','alpha'); $object->ref_int = GETPOST('ref_int','alpha'); $object->note_private = GETPOST('note_private','none'); @@ -269,7 +272,7 @@ if (empty($reshook)) { if (isset($_POST[$batch])) { - //shipment line with batch-enable product + //reception line with batch-enable product $qty .= '_'.$j; while (isset($_POST[$batch])) { @@ -305,7 +308,7 @@ if (empty($reshook)) } else if (isset($_POST[$stockLocation])) { - //shipment line from multiple stock locations + //reception line from multiple stock locations $qty .= '_'.$j; while (isset($_POST[$stockLocation])) { @@ -324,7 +327,7 @@ if (empty($reshook)) else { //var_dump(GETPOST($qty,'int')); var_dump($_POST); var_dump($batch);exit; - //shipment line for product with no batch management and no multiple stock location + //reception line for product with no batch management and no multiple stock location if (GETPOST($qty,'int') > 0) $totalqty+=GETPOST($qty,'int'); } @@ -354,7 +357,7 @@ if (empty($reshook)) // not batch mode if (isset($stockLine[$i])) { - //shipment from multiple stock locations + //reception from multiple stock locations $nbstockline = count($stockLine[$i]); for($j = 0; $j < $nbstockline; $j++) { @@ -371,7 +374,7 @@ if (empty($reshook)) } else { - if (GETPOST($qty,'int') > 0 || (GETPOST($qty,'int') == 0 && $conf->global->SHIPMENT_GETS_ALL_ORDER_PRODUCTS)) + if (GETPOST($qty,'int') > 0 || (GETPOST($qty,'int') == 0 && $conf->global->RECEPTION_GETS_ALL_ORDER_PRODUCTS)) { $ent = "entl".$i; $idl = "idl".$i; @@ -408,7 +411,7 @@ if (empty($reshook)) if (! $error) { - $ret=$object->create($user); // This create shipment (like Odoo picking) and line of shipments. Stock movement will when validating shipment. + $ret=$object->create($user); // This create reception (like Odoo picking) and line of receptions. Stock movement will when validating reception. if ($ret <= 0) { setEventMessages($object->error, $object->errors, 'errors'); @@ -418,7 +421,7 @@ if (empty($reshook)) } else { - setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("QtyToShip").'/'.$langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); + setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("QtyToReceive").'/'.$langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); $error++; } @@ -439,7 +442,7 @@ if (empty($reshook)) /* * Build a receiving receipt */ - else if ($action == 'create_delivery' && $conf->livraison_bon->enabled && $user->rights->expedition->livraison->creer) + else if ($action == 'create_delivery' && $conf->livraison_bon->enabled && $user->rights->reception->livraison->creer) { $result = $object->create_delivery($user); if ($result > 0) @@ -454,8 +457,8 @@ if (empty($reshook)) } else if ($action == 'confirm_valid' && $confirm == 'yes' && - ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->creer)) - || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->expedition->shipping_advance->validate))) + ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate))) ) { $object->fetch_thirdparty(); @@ -489,12 +492,12 @@ if (empty($reshook)) } } - else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->expedition->supprimer) + else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->reception->supprimer) { $result = $object->delete(); if ($result > 0) { - header("Location: ".DOL_URL_ROOT.'/expedition/index.php'); + header("Location: ".DOL_URL_ROOT.'/reception/index.php'); exit; } else @@ -503,7 +506,7 @@ if (empty($reshook)) } } // TODO add alternative status - /*else if ($action == 'reopen' && (! empty($user->rights->expedition->creer) || ! empty($user->rights->expedition->shipping_advance->validate))) + /*else if ($action == 'reopen' && (! empty($user->rights->reception->creer) || ! empty($user->rights->reception->reception_advance->validate))) { $result = $object->setStatut(0); if ($result < 0) @@ -512,7 +515,7 @@ if (empty($reshook)) } }*/ - else if ($action == 'setdate_livraison' && $user->rights->expedition->creer) + else if ($action == 'setdate_livraison' && $user->rights->reception->creer) { //print "x ".$_POST['liv_month'].", ".$_POST['liv_day'].", ".$_POST['liv_year']; $datedelivery=dol_mktime(GETPOST('liv_hour','int'), GETPOST('liv_min','int'), 0, GETPOST('liv_month','int'), GETPOST('liv_day','int'), GETPOST('liv_year','int')); @@ -531,7 +534,7 @@ if (empty($reshook)) || $action == 'settrueWidth' || $action == 'settrueHeight' || $action == 'settrueDepth' - || $action == 'setshipping_method_id') + || $action == 'setreception_method_id') { $error=0; @@ -547,7 +550,7 @@ if (empty($reshook)) $object->size_units = GETPOST('size_units','int'); } if ($action == 'settrueDepth') $object->trueDepth = trim(GETPOST('trueDepth','int')); - if ($action == 'setshipping_method_id') $object->shipping_method_id = trim(GETPOST('shipping_method_id','int')); + if ($action == 'setreception_method_id') $object->reception_method_id = trim(GETPOST('reception_method_id','int')); if (! $error) { @@ -572,7 +575,7 @@ if (empty($reshook)) $outputlangs = $langs; $newlang=''; if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$shipment->thirdparty->default_lang; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$reception->thirdparty->default_lang; if (! empty($newlang)) { $outputlangs = new Translate("",$conf); @@ -591,7 +594,7 @@ if (empty($reshook)) { require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - $upload_dir = $conf->expedition->dir_output . "/sending"; + $upload_dir = $conf->reception->dir_output . "/reception"; $file = $upload_dir . '/' . GETPOST('file'); $ret=dol_delete_file($file,0,0,0,$object); if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); @@ -625,7 +628,7 @@ if (empty($reshook)) { $object->fetch($id); $lines = $object->lines; - $line = new ExpeditionLigne($db); + $line = new ReceptionLigne($db); $num_prod = count($lines); for ($i = 0 ; $i < $num_prod ; $i++) @@ -669,7 +672,7 @@ if (empty($reshook)) /* * Update a line */ - else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('save')) + else if ($action == 'updateline' && $user->rights->reception->creer && GETPOST('save')) { // Clean parameters $qty=0; @@ -682,7 +685,7 @@ if (empty($reshook)) { if ($lines[$i]->id == $line_id) // we have found line to update { - $line = new ExpeditionLigne($db); + $line = new ReceptionLigne($db); // Extrafields Lines $extrafieldsline = new ExtraFields($db); $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); @@ -700,21 +703,21 @@ if (empty($reshook)) foreach ($lines[$i]->detail_batch as $detail_batch) { $lotStock = new Productbatch($db); - $batch="batchl".$detail_batch->fk_expeditiondet."_".$detail_batch->fk_origin_stock; - $qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id; + $batch="batchl".$detail_batch->fk_receptiondet."_".$detail_batch->fk_origin_stock; + $qty = "qtyl".$detail_batch->fk_receptiondet.'_'.$detail_batch->id; $batch_id = GETPOST($batch,'int'); $batch_qty = GETPOST($qty, 'int'); if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->dluo_qty)) { - if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0) // $line is ExpeditionLine + if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_receptiondet) > 0) // $line is ReceptionLine { if ($lines[$i]->entrepot_id != 0) { - // allow update line entrepot_id if not multi warehouse shipping + // allow update line entrepot_id if not multi warehouse reception $line->entrepot_id = $lotStock->warehouseid; } - // detail_batch can be an object with keys, or an array of ExpeditionLineBatch + // detail_batch can be an object with keys, or an array of ReceptionLineBatch if (empty($line->detail_batch)) $line->detail_batch=new stdClass(); $line->detail_batch->fk_origin_stock = $batch_id; @@ -750,7 +753,7 @@ if (empty($reshook)) // check if lotStock warehouse id is same as line warehouse id if ($lines[$i]->entrepot_id > 0) { - // single warehouse shipment line + // single warehouse reception line if ($lines[i]->entrepot_id == $lotStock->warehouseid) { $lineIdToAddLot = $line_id; @@ -758,7 +761,7 @@ if (empty($reshook)) } else if (count($lines[$i]->details_entrepot) > 1) { - // multi warehouse shipment lines + // multi warehouse reception lines foreach ($lines[$i]->details_entrepot as $detail_entrepot) { if ($detail_entrepot->entrepot_id == $lotStock->warehouseid) @@ -792,7 +795,7 @@ if (empty($reshook)) // create new line with new lot $line->origin_line_id = $lines[$i]->origin_line_id; $line->entrepot_id = $lotStock->warehouseid; - $line->detail_batch[0] = new ExpeditionLineBatch($db); + $line->detail_batch[0] = new ReceptionLineBatch($db); $line->detail_batch[0]->fk_origin_stock = $batch_id; $line->detail_batch[0]->batch = $lotStock->batch; $line->detail_batch[0]->entrepot_id = $lotStock->warehouseid; @@ -818,7 +821,7 @@ if (empty($reshook)) // line without lot if ($lines[$i]->entrepot_id > 0) { - // single warehouse shipment line + // single warehouse reception line $stockLocation="entl".$line_id; $qty = "qtyl".$line_id; $line->id = $line_id; @@ -833,7 +836,7 @@ if (empty($reshook)) } else if (count($lines[$i]->details_entrepot) > 1) { - // multi warehouse shipment lines + // multi warehouse reception lines foreach ($lines[$i]->details_entrepot as $detail_entrepot) { if (! $error) { @@ -899,7 +902,7 @@ if (empty($reshook)) } } - else if ($action == 'updateline' && $user->rights->expedition->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { + else if ($action == 'updateline' && $user->rights->reception->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition exit(); } @@ -908,9 +911,9 @@ if (empty($reshook)) // Actions to send emails if (empty($id)) $id=$facid; - $trigger_name='SHIPPING_SENTBYMAIL'; + $trigger_name='RECEPTION_SENTBYMAIL'; $paramname='id'; - $mode='emailfromshipment'; + $mode='emailfromreception'; $trackid='shi'.$object->id; include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; @@ -921,7 +924,7 @@ if (empty($reshook)) * View */ -llxHeader('',$langs->trans('Shipment'),'Expedition'); +llxHeader('',$langs->trans('Reception'),'Reception'); $form = new Form($db); $formfile = new FormFile($db); @@ -929,22 +932,22 @@ $formproduct = new FormProduct($db); if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } $product_static = new Product($db); -$shipment_static = new Expedition($db); +$reception_static = new Reception($db); $warehousestatic = new Entrepot($db); if ($action == 'create2') { - print load_fiche_titre($langs->trans("CreateShipment")).'
'; - print $langs->trans("ShipmentCreationIsDoneFromOrder"); + print load_fiche_titre($langs->trans("CreateReception")).'
'; + print $langs->trans("ReceptionCreationIsDoneFromOrder"); $action=''; $id=''; $ref=''; } // Mode creation. if ($action == 'create') { - $expe = new Expedition($db); + $recept = new Reception($db); - print load_fiche_titre($langs->trans("CreateShipment")); + print load_fiche_titre($langs->trans("CreateReception")); if (! $origin) { setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors'); @@ -952,8 +955,9 @@ if ($action == 'create') if ($origin) { - $classname = ucfirst($origin); - + if($origin == 'supplierorder')$classname = 'CommandeFournisseur'; + else $classname = ucfirst($origin); + $object = new $classname($db); if ($object->fetch($origin_id)) // This include the fetch_lines { @@ -982,9 +986,9 @@ if ($action == 'create') // Ref print '
'; - if ($origin == 'commande' && ! empty($conf->commande->enabled)) + if ($origin == 'supplierorder' && ! empty($conf->fournisseur->enabled)) { - print $langs->trans("RefOrder").''.img_object($langs->trans("ShowOrder"),'order').' '.$object->ref; + print $langs->trans("RefOrder").''.img_object($langs->trans("ShowOrder"),'order').' '.$object->ref; } if ($origin == 'propal' && ! empty($conf->propal->enabled)) { @@ -992,14 +996,12 @@ if ($action == 'create') } print '
'; - if ($origin == 'commande') print $langs->trans('RefCustomerOrder'); - else if ($origin == 'propal') print $langs->trans('RefCustomerOrder'); - else print $langs->trans('RefCustomer'); + if ($origin == 'supplier_order') print $langs->trans('RefSupplierOrder'); + else print $langs->trans('RefSupplier'); print ''; - print ''; + print ''; print '
".$langs->trans("DeliveryMethod")."'; - $expe->fetch_delivery_methods(); - print $form->selectarray("shipping_method_id", $expe->meths, GETPOST('shipping_method_id','int'),1,0,0,"",1); + $recept->fetch_delivery_methods(); + print $form->selectarray("reception_method_id", $recept->meths, GETPOST('reception_method_id','int'),1,0,0,"",1); if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); print "
".$langs->trans("DefaultModel")."'; - print $form->selectarray('model', $liste, $conf->global->EXPEDITION_ADDON_PDF); + print $form->selectarray('model', $liste, $conf->global->RECEPTION_ADDON_PDF); print "