// Date delivery real / Received // TODO Can edit this date, even if delivery validated. print '<tr><td>'.$langs->trans("DateReceived").'</td>'; print '<td colspan="3">'.dol_print_date($delivery->date_delivery,'daytext')."</td>\n"; print '</tr>'; // Statut print '<tr><td>'.$langs->trans("Status").'</td>'; print '<td colspan="3">'.$delivery->getLibStatut(4)."</td>\n"; print '</tr>'; if (!$conf->expedition_bon->enabled && $conf->stock->enabled) { // Entrepot $entrepot = new Entrepot($db); $entrepot->fetch($delivery->entrepot_id); print '<tr><td width="20%">'.$langs->trans("Warehouse").'</td>'; print '<td colspan="3"><a href="'.DOL_URL_ROOT.'/product/stock/fiche.php?id='.$entrepot->id.'">'.$entrepot->libelle.'</a></td>'; print '</tr>'; } print "</table><br>\n"; /* * Lignes produits */ $num_prod = sizeof($delivery->lines); $i = 0; $total = 0; print '<table class="noborder" width="100%">';
$bankcash->label = $bankcash->ref; $bankcashLink = $bankcash->getNomUrl(1); } if (!empty($_SESSION["CASHDESK_ID_BANKACCOUNT_CB"])) { $bankcb = new Account($db); $bankcb->fetch($_SESSION["CASHDESK_ID_BANKACCOUNT_CB"]); $bankcbLink = $bankcb->getNomUrl(1); } if (!empty($_SESSION["CASHDESK_ID_BANKACCOUNT_CHEQUE"])) { $bankcheque = new Account($db); $bankcheque->fetch($_SESSION["CASHDESK_ID_BANKACCOUNT_CHEQUE"]); $bankchequeLink = $bankcheque->getNomUrl(1); } if (!empty($_SESSION["CASHDESK_ID_WAREHOUSE"]) && !empty($conf->stock->enabled)) { $warehouse = new Entrepot($db); $warehouse->fetch($_SESSION["CASHDESK_ID_WAREHOUSE"]); $warehouseLink = $warehouse->getNomUrl(1); } $langs->load("cashdesk"); $langs->load("main"); print '<div class="menu_bloc">'; print '<ul class="menu">'; // Link to new sell print '<li class="menu_choix1"><a href="affIndex.php?menu=facturation&id=NOUV"><span>' . $langs->trans("NewSell") . '</span></a></li>'; // Open new tab on backoffice (this is not a disconnect from POS) print '<li class="menu_choix2"><a href=".." target="backoffice"><span>' . $langs->trans("BackOffice") . '</span></a></li>'; // Disconnect print '<li class="menu_choix0">' . $langs->trans("User") . ': ' . $_SESSION['firstname'] . ' ' . $_SESSION['lastname']; print ' <a href="deconnexion.php">' . img_picto($langs->trans('Logout'), 'logout.png') . '</a><br>'; print $langs->trans("CashDeskThirdParty") . ': ' . $companyLink . '<br>'; /*print $langs->trans("CashDeskBankCash").': '.$bankcashLink.'<br>';
$sql .= " AND m.checked = 1"; } else { $sql .= " AND m.checked = -1"; } $sql .= $db->order($sortfield, $sortorder); $sql .= $db->plimit($conf->liste_limit + 1, $offset); $resql = $db->query($sql); if ($resql) { $num = $db->num_rows($resql); if ($idproduct) { $product = new Product($db); $product->fetch($idproduct); } if ($id > 0) { $entrepot = new Entrepot($db); $result = $entrepot->fetch($id); if ($result < 0) { dol_print_error($db); } } $i = 0; $help_url = 'EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; $texte = $langs->trans("ListOfStockMovements"); if ($id) { $texte .= ' (' . $langs->trans("ForThisWarehouse") . ')'; } llxHeader("", $texte, $help_url); /* * Show tab only if we ask a particular warehouse */ if ($id) {
// Size //print '<td align="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume").'</td>'; // Entrepot source if (!empty($conf->stock->enabled)) { print '<td align="left">'; 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) . '<br/>'; } } print $form->textwithtooltip($langs->trans("DetailWarehouseNumber"), $detail); } } print '</td>'; } // Batch number managment if (!empty($conf->productbatch->enabled)) { if (isset($lines[$i]->detail_batch)) { print '<td>'; if ($lines[$i]->product_tobatch) { $detail = ''; foreach ($lines[$i]->detail_batch as $dbatch) {
require("../../main.inc.php"); require_once(DOL_DOCUMENT_ROOT."/product/stock/class/entrepot.class.php"); require_once(DOL_DOCUMENT_ROOT."/core/lib/functions2.lib.php"); require_once(DOL_DOCUMENT_ROOT."/core/lib/stock.lib.php"); $langs->load("stocks"); /* * View */ $help_url='EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; llxHeader("",$langs->trans("Stocks"),$help_url); $entrepot = new Entrepot($db); $entrepot->fetch($_GET["id"]); $entrepot->info($_GET["id"]); $head = stock_prepare_head($entrepot); dol_fiche_head($head, 'info', $langs->trans("Warehouse"), 0, 'stock'); print '<table width="100%"><tr><td>'; dol_print_object_info($entrepot); print '</td></tr></table>'; print '</div>'; llxFooter();
<div onclick="_TPV.searchByStock(-6,_TPV.warehouseId);" class="botonStats" align="center" title=" " style="width: 48%"> <span ><?php echo $langs->trans('WorstSell'); ?> </span> <span id="stockWorst" style="font-size:22px">0</span> </div> <?php $list = array(); $list = POS::getWarehouse(); $num = count($list); $i = 0; $warehouse = new Entrepot($db); while ($i < $num) { $warehouse->fetch($list[$i]['id']); $ret = $warehouse->nb_products(); ?> <div onclick="_TPV.searchByStock(1,<?php echo $list[$i]['id']; ?> );" class="botonStats" align="center" title=" " style="width: 48%"> <span><?php echo $warehouse->libelle; ?> </span> <span style="font-size:22px"><?php echo $ret['nb']; ?> </span> </div>
print '</td></tr>'; print '</table>'; print '<center><br><input type="submit" class="button" value="'.$langs->trans("Create").'"></center>'; print '</form>'; } else { if ($_GET["id"]) { dol_htmloutput_mesg($mesg); $object = new Entrepot($db); $result = $object->fetch($_GET["id"]); if ($result < 0) { dol_print_error($db); } /* * Affichage fiche */ if ($action <> 'edit' && $action <> 're-edit') { $head = stock_prepare_head($object); dol_fiche_head($head, 'card', $langs->trans("Warehouse"), 0, 'stock'); // Confirm delete third party
$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $cash->id, $cash->fk_modepaybank_extra, 'none'); print "</td>"; print '</tr>'; } else { print '<tr>'; print '<td>' . $langs->trans('PaymentBankExtra') . '</td>'; print '<td colspan="3">'; //print $bankline->getNomUrl(1,0,'showall'); print '</td>'; print '</tr>'; } } //Stock if ($conf->stock->enabled) { $stock = new Entrepot($db); $stock->fetch($cash->fk_warehouse); print '<tr><td>' . $langs->trans("CashDeskIdWareHouse") . '</td>'; print '<td colspan="3">'; print '<a href="' . DOL_URL_ROOT . '/product/stock/fiche.php?id=' . $stock->id . '">' . img_object($langs->trans("ShowWarehouse"), 'stock') . ' ' . $stock->libelle . '</a>'; print '</td></tr>'; } //Soc $soc = new Societe($db, $cash->fk_soc); $soc->fetch($cash->fk_soc); print '<tr><td>' . $langs->trans("CashDeskThirdPartyForSell") . '</td>'; print '<td>'; print $soc->getNomUrl(1, 'compta'); print '</td></tr>'; if ($conf->global->POS_USER_TERMINAL) { // Liste les commerciaux print '<tr><td valign="top">' . $langs->trans("Users") . '</td>';
print "</td></tr>"; // Note Private print '<tr><td>' . $langs->trans("NotePrivate") . '</td>'; print '<td colspan="3">'; print nl2br($object->note_private); /*$doleditor = new DolEditor('note_pprivate', $object->note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); print $doleditor->Create(1);*/ print "</td></tr>"; // Statut print '<tr><td>' . $langs->trans("Status") . '</td>'; print '<td colspan="3">' . $object->getLibStatut(4) . "</td>\n"; print '</tr>'; if (!$conf->expedition_bon->enabled && !empty($conf->stock->enabled)) { // Entrepot $entrepot = new Entrepot($db); $entrepot->fetch($object->entrepot_id); print '<tr><td width="20%">' . $langs->trans("Warehouse") . '</td>'; print '<td colspan="3"><a href="' . DOL_URL_ROOT . '/product/stock/card.php?id=' . $entrepot->id . '">' . $entrepot->libelle . '</a></td>'; print '</tr>'; } print "</table><br>\n"; /* * Lignes produits */ $num_prod = count($object->lines); $i = 0; $total = 0; print '<table class="noborder" width="100%">'; if ($num_prod) { $i = 0; print '<tr class="liste_titre">';
// Out warehouse print '<td>'; print $formproduct->selectWarehouses($id_tw, 'id_tw', '', 1); print '</td>'; // Qty print '<td align="center"><input type="text" size="4" class="flat" name="qty" value="' . $qty . '"></td>'; // Button to add line if (!$listofdata) { print '<td align="right"><input type="submit" class="button" name="addline" value="' . dol_escape_htmltag($titletoadd) . '"></td>'; } print '</tr>'; foreach ($listofdata as $key => $val) { $var = !$var; $productstatic->fetch($val['id_product']); $warehousestatics->fetch($val['id_sw']); $warehousestatict->fetch($val['id_tw']); print '<tr ' . $bc[$var] . '>'; print '<td>' . $productstatic->getNomUrl(1) . '</td>'; print '<td>'; $oldref = $productstatic->ref; $productstatic->ref = $productstatic->label; print $productstatic->getNomUrl(1); $productstatic->ref = $oldref; print '</td>'; print '<td>'; print $warehousestatics->getNomUrl(1); print '</td>'; print '<td>'; print $warehousestatict->getNomUrl(1); print '</td>'; print '<td align="center">' . $val['qty'] . '</td>';
/* * View */ $help_url='EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; llxHeader("",$langs->trans("WarehouseCard"),$help_url); $form=new Form($db); if ($_GET["id"]) { if ($mesg) print $mesg; $entrepot = new Entrepot($db); $result = $entrepot->fetch($_GET["id"]); if ($result < 0) { dol_print_error($db); } /* * Affichage fiche */ if ($_GET["action"] <> 'edit' && $_GET["action"] <> 're-edit') { $head = stock_prepare_head($entrepot); dol_fiche_head($head, 'user', $langs->trans("Warehouse"), 0, 'stock');
/** * testEntrepotDelete * * @param int $id Id of entrepot * @return void * * @depends testEntrepotOther * The depends says test is run only if previous is ok */ public function testEntrepotDelete($id) { global $conf, $user, $langs, $db; $conf = $this->savconf; $user = $this->savuser; $langs = $this->savlangs; $db = $this->savdb; $localobject = new Entrepot($this->savdb); $result = $localobject->fetch($id); $result = $localobject->delete($id); print __METHOD__ . " id=" . $id . " result=" . $result . "\n"; $this->assertLessThan($result, 0); return $result; }
/** * Update a product or service * * @param array $authentication Array of authentication information * @param Product $product Product * @return array Array result */ function updateProductOrService($authentication, $product) { global $db, $conf, $langs; $now = dol_now(); dol_syslog("Function: updateProductOrService login="******"You must choose between price or price_net to provide price."; } if ($product['barcode'] && !$product['barcode_type']) { $errror++; $errorcode = 'KO'; $errorlabel = "You must set a barcode type when setting a barcode."; } if (!$error) { include_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; $newobject = new Product($db); $newobject->fetch($product['id']); if (isset($product['ref'])) { $newobject->ref = $product['ref']; } if (isset($product['ref_ext'])) { $newobject->ref_ext = $product['ref_ext']; } $newobject->type = $product['type']; $newobject->libelle = $product['label']; // @deprecated $newobject->label = $product['label']; $newobject->description = $product['description']; $newobject->note = $product['note']; $newobject->status = $product['status_tosell']; $newobject->status_buy = $product['status_tobuy']; $newobject->price = $product['price_net']; $newobject->price_ttc = $product['price']; $newobject->tva_tx = $product['vat_rate']; $newobject->price_base_type = $product['price_base_type']; $newobject->date_creation = $now; if ($product['barcode']) { $newobject->barcode = $product['barcode']; $newobject->barcode_type = $product['barcode_type']; } $newobject->stock_reel = $product['stock_real']; $newobject->pmp = $product['pmp']; $newobject->seuil_stock_alert = $product['stock_alert']; $newobject->country_id = $product['country_id']; if ($product['country_code']) { $newobject->country_id = getCountry($product['country_code'], 3); } $newobject->customcode = $product['customcode']; $newobject->canvas = $product['canvas']; /*foreach($product['lines'] as $line) { $newline=new FactureLigne($db); $newline->type=$line['type']; $newline->desc=$line['desc']; $newline->fk_product=$line['fk_product']; $newline->total_ht=$line['total_net']; $newline->total_vat=$line['total_vat']; $newline->total_ttc=$line['total']; $newline->vat=$line['vat_rate']; $newline->qty=$line['qty']; $newline->fk_product=$line['product_id']; }*/ //var_dump($product['ref_ext']); //var_dump($product['lines'][0]['type']); $extrafields = new ExtraFields($db); $extralabels = $extrafields->fetch_name_optionals_label('product', true); foreach ($extrafields->attribute_label as $key => $label) { $key = 'options_' . $key; $newobject->array_options[$key] = $product[$key]; } $db->begin(); $result = $newobject->update($newobject->id, $fuser); if ($result <= 0) { $error++; } else { // Update stock if stock count is provided and differs from database after creation or update if (isset($product['stock_real']) && $product['stock_real'] != '' && !empty($conf->global->stock->enabled)) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php'; $savstockreal = $newobject->stock_reel; $newobject->load_stock(); // This overwrite ->stock_reel $getstockreal = $newobject->stock_reel; if ($savstockreal != $getstockreal) { $warehouse = new Entrepot($this->db); $warehouse->fetch(0, $product['warehouse_ref']); if ($warehouse->id > 0) { if ($savstockreal - $getstockreal > 0) { $result = $newobject->correct_stock($fuser, $warehouse->id, $savstockreal - $getstockreal, 0, 'Correction from external call (Web Service)', 0, 'WS' . dol_print_date($now, 'dayhourlog')); } if ($savstockreal - $getstockreal > 0) { $result = $newobject->correct_stock($fuser, $warehouse->id, $savstockreal - $getstockreal, 1, 'Correction from external call (Web Service)', 0, 'WS' . dol_print_date($now, 'dayhourlog')); } if ($result <= 0) { $error++; $newobject->error = 'You set a different value for stock, but correction of stock count (before=' . $getstockreal . ', after=' . $savstockreal . ') fails with error ' . $newobject->error; } } else { $error++; $newobject->error = 'You set a different value for stock but we failed to find warehouse ' . $product['warehouse_ref'] . ' to make correction.'; } } } } if (!$error) { if ($newobject->price_base_type == 'HT') { $result = $newobject->updatePrice($newobject->price, $newobject->price_base_type, $fuser); if ($result <= 0) { $error++; } } elseif ($newobject->price_base_type == 'TTC') { $result = $newobject->updatePrice($newobject->price_ttc, $newobject->price_base_type); if ($result <= 0) { $error++; } } } if (!$error) { $db->commit(); $objectresp = array('result' => array('result_code' => 'OK', 'result_label' => ''), 'id' => $newobject->id, 'ref' => $newobject->ref); } else { $db->rollback(); $error++; $errorcode = 'KO'; $errorlabel = $newobject->error; } } if ($error) { $objectresp = array('result' => array('result_code' => $errorcode, 'result_label' => $errorlabel)); } return $objectresp; }
print $regs[1] . ' ' . $langs->trans("DurationYear"); } elseif (preg_match('/([0-9]+)m/i', $objp->duration, $regs)) { print $regs[1] . ' ' . $langs->trans("DurationMonth"); } elseif (preg_match('/([0-9]+)d/i', $objp->duration, $regs)) { print $regs[1] . ' ' . $langs->trans("DurationDay"); } else { print $objp->duration; } print '</td>'; } //print '<td align="right">'.$objp->stock_theorique.'</td>'; //print '<td align="right">'.$objp->seuil_stock_alerte.'</td>'; //print '<td align="right">'.$objp->desiredstock.'</td>'; // Warehouse print '<td>'; $warehousetmp->fetch($obj->fk_entrepot); print $warehousetmp->getNomUrl(1); print '</td>'; print '<td align="center">' . $objp->batch . '</td>'; print '<td align="center">' . dol_print_date($db->jdate($objp->eatby), 'day') . '</td>'; print '<td align="center">' . dol_print_date($db->jdate($objp->sellby), 'day') . '</td>'; print '<td align="right">'; //if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' '; print $objp->stock_physique; print '</td>'; print '<td align="right"><a href="' . DOL_URL_ROOT . '/product/stock/mouvement.php?idproduct=' . $product_static->id . '&search_batch=' . $objp->batch . '">' . $langs->trans("Movements") . '</a></td>'; print '<td align="right" class="nowrap">' . $product_static->LibStatut($objp->statut, 5, 0) . '</td>'; print '<td align="right" class="nowrap">' . $product_static->LibStatut($objp->tobuy, 5, 1) . '</td>'; print "</tr>\n"; $i++; }
print '</td></tr>'; print '<tr><td>' . $langs->trans("Status") . '</td><td colspan="3">'; print '<select name="statut" class="flat">'; print '<option value="0">' . $langs->trans("WarehouseClosed") . '</option>'; print '<option value="1" selected="selected">' . $langs->trans("WarehouseOpened") . '</option>'; print '</select>'; print '</td></tr>'; print '</table>'; print '<center><br><input type="submit" class="button" value="' . $langs->trans("Create") . '"></center>'; print '</form>'; } else { $id = GETPOST("id", 'int'); if ($id) { dol_htmloutput_mesg($mesg); $object = new Entrepot($db); $result = $object->fetch($id); if ($result < 0) { dol_print_error($db); } /* * Affichage fiche */ if ($action != 'edit' && $action != 're-edit') { $head = stock_prepare_head($object); dol_fiche_head($head, 'card', $langs->trans("Warehouse"), 0, 'stock'); // Confirm delete third party if ($action == 'delete') { print $form->formconfirm($_SERVER["PHP_SELF"] . "?id=" . $object->id, $langs->trans("DeleteAWarehouse"), $langs->trans("ConfirmDeleteWarehouse", $object->libelle), "confirm_delete", '', 0, 2); } print '<table class="border" width="100%">'; $linkback = '<a href="' . DOL_URL_ROOT . '/product/stock/liste.php">' . $langs->trans("BackToList") . '</a>';
// Volume print '<td align="center">'; if ($lines[$i]->fk_product_type == 0) { print $lines[$i]->volume * $lines[$i]->qty_shipped . ' ' . measuring_units_string($lines[$i]->volume_units, "volume"); } else { print ' '; } print '</td>'; // Size //print '<td align="center">'.$lines[$i]->volume*$lines[$i]->qty_shipped.' '.measuring_units_string($lines[$i]->volume_units,"volume").'</td>'; // Entrepot source if ($conf->stock->enabled) { print '<td align="left">'; if ($lines[$i]->entrepot_id > 0) { $entrepot = new Entrepot($db); $entrepot->fetch($lines[$i]->entrepot_id); print $entrepot->getNomUrl(1); } print '</td>'; } print "</tr>"; $var = !$var; } } print "</table>\n"; print "\n</div>\n"; /* * Boutons actions */ if ($user->societe_id == 0) { print '<div class="tabsAction">';
/** Return next value * @param objsoc Object third party * @param ticket Object ticket * @param mode 'next' for next value or 'last' for last value * @return string Value if OK, 0 if KO */ function getNextValue($objsoc, $facsim, $mode = 'next') { global $db, $conf; require_once DOL_DOCUMENT_ROOT . "/core/lib/functions2.lib.php"; // Get Mask value $mask = ''; if (is_object($facsim) && $facsim->type == 2) { $mask = $conf->global->FACSIM_MURO_MASK_CREDIT; } else { $mask = $conf->global->FACSIM_MURO_MASK; } if (!$mask) { $this->error = 'NotConfigured'; return 0; } $where = ''; //ww para warehouse if (preg_match('/\\{(w+)\\}/i', $mask, $regWare)) { dol_include_once("/pos/class/cash.class.php"); require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php'; $terminal = new Cash($db); $terminal->fetch($facsim->fk_cash); $warehouse = new Entrepot($db); $warehouse->fetch($terminal->fk_warehouse); $maskware = $regWare[1]; $maskware_value = substr($warehouse->libelle, 0, dol_strlen($regWare[1])); //get n first characters of warehouse ref where n is length in mask $maskware_value = str_pad($maskware_value, dol_strlen($regWare[1]), "#", STR_PAD_RIGHT); $maskware_maskbefore = '{' . $maskware . '}'; $maskware_maskafter = $maskware_value; $mask = str_replace($maskware_maskbefore, $maskware_maskafter, $mask); } //kk para terminal if (preg_match('/\\{(k+)\\}/i', $mask, $regTerm)) { dol_include_once("/pos/class/cash.class.php"); $terminal = new Cash($db); $terminal->fetch($facsim->fk_cash); $maskterm = $regTerm[1]; $maskterm_value = substr($terminal->ref, 0, dol_strlen($regTerm[1])); //get n first characters of warehouse ref where n is length in mask $maskterm_value = str_pad($maskterm_value, dol_strlen($regTerm[1]), "#", STR_PAD_RIGHT); $maskterm_maskbefore = '{' . $maskterm . '}'; $maskterm_maskafter = $maskterm_value; $mask = str_replace($maskterm_maskbefore, $maskterm_maskafter, $mask); } $numFinal = get_next_value($db, $mask, 'facture', 'facnumber', $where, $objsoc, time(), $mode); if (!preg_match('/([0-9])+/', $numFinal)) { $this->error = $numFinal; } return $numFinal; }
/** * Display form to select warehouse * * @param string $page Page * @param int $selected Id of warehouse * @param string $htmlname Name of select html field * @param int $addempty 1=Add an empty value in list, 2=Add an empty value in list only if there is more than 2 entries. * @return void */ function formSelectWarehouses($page, $selected = '', $htmlname = 'warehouse_id', $addempty = 0) { global $langs; if ($htmlname != "none") { print '<form method="POST" action="' . $page . '">'; print '<input type="hidden" name="action" value="setwarehouse">'; print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">'; print '<table class="nobordernopadding" cellpadding="0" cellspacing="0">'; print '<tr><td>'; print $this->selectWarehouses($selected, $htmlname, '', $addempty); print '</td>'; print '<td align="left"><input type="submit" class="button" value="' . $langs->trans("Modify") . '"></td>'; print '</tr></table></form>'; } else { if ($selected) { require_once DOL_DOCUMENT_ROOT . '/product/stock/class/entrepot.class.php'; $warehousestatic = new Entrepot($this->db); $warehousestatic->fetch($selected); print $warehousestatic->getNomUrl(); } else { print " "; } } }