diff --git a/htdocs/accountancy/journal/sellsjournal.php b/htdocs/accountancy/journal/sellsjournal.php index 5bb1f989a92987c57f86542a494b4f629def9f46..8a0318473c9f8727a678a30842de44f97ae97cb7 100644 --- a/htdocs/accountancy/journal/sellsjournal.php +++ b/htdocs/accountancy/journal/sellsjournal.php @@ -7,6 +7,7 @@ * Copyright (C) 2013-2014 Alexandre Spangaro <alexandre.spangaro@gmail.com> * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro> * Copyright (C) 2013-2014 Olivier Geffroy <jeff@jeffinfo.com> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -100,9 +101,9 @@ if (! empty($conf->multicompany->enabled)) { } $sql .= " AND f.fk_statut > 0"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) - $sql .= " AND f.type IN (0,1,2)"; + $sql .= " AND f.type IN (0,1,2,5)"; else - $sql .= " AND f.type IN (0,1,2,3)"; + $sql .= " AND f.type IN (0,1,2,3,5)"; $sql .= " AND fd.product_type IN (0,1)"; if ($date_start && $date_end) $sql .= " AND f.datef >= '" . $db->idate($date_start) . "' AND f.datef <= '" . $db->idate($date_end) . "'"; @@ -136,6 +137,16 @@ if ($result) { $cpttva = (! empty($conf->global->ACCOUNTING_VAT_ACCOUNT)) ? $conf->global->ACCOUNTING_VAT_ACCOUNT : $langs->trans("CodeNotDef"); $compta_tva = (! empty($obj->account_tva) ? $obj->account_tva : $cpttva); + // Situation invoices handling + $line = new FactureLigne($db); + $line->fetch($obj->id); + $prev_progress = $line->get_prev_progress(); + if ($obj->situation_percent == 0) { // Avoid divide by 0 + $situation_ratio = 0; + } else { + $situation_ratio = ($obj->situation_percent - $prev_progress) / $obj->situation_percent; + } + // Invoice lines $tabfac[$obj->rowid]["date"] = $obj->df; $tabfac[$obj->rowid]["ref"] = $obj->facnumber; @@ -148,9 +159,9 @@ if ($result) { $tabht[$obj->rowid][$compta_prod] = 0; if (! isset($tabtva[$obj->rowid][$compta_tva])) $tabtva[$obj->rowid][$compta_tva] = 0; - $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc; - $tabht[$obj->rowid][$compta_prod] += $obj->total_ht; - $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva; + $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc * $situation_ratio; + $tabht[$obj->rowid][$compta_prod] += $obj->total_ht * $situation_ratio; + $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio; $tabcompany[$obj->rowid] = array ( 'id' => $obj->socid, 'name' => $obj->name, @@ -471,4 +482,4 @@ if ($action == 'export_csv') { // End of page llxFooter(); } -$db->close(); \ No newline at end of file +$db->close(); diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 9f104180defb6310ecb9b8a0a2b4f5e913fe3fce..3feb30cdb27cf8704e76c4ccba2c93b4fe9633ae 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -7,9 +7,10 @@ * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr> * Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2013 Jean-Francois FERRY <jfefe@aternatik.fr> * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro> - * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr> * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es> * * This program is free software; you can redistribute it and/or modify @@ -802,7 +803,7 @@ else if ($action == 'add' && $user->rights->facture->creer) } // Standard or deposit or proforma invoice - if (($_POST['type'] == Facture::TYPE_STANDARD || $_POST['type'] == Facture::TYPE_DEPOSIT || $_POST['type'] == Facture::TYPE_PROFORMA) && $_POST['fac_rec'] <= 0) + if (($_POST['type'] == Facture::TYPE_STANDARD || $_POST['type'] == Facture::TYPE_DEPOSIT || $_POST['type'] == Facture::TYPE_PROFORMA || ($_POST['type'] == Facture::TYPE_SITUATION && empty($_POST['situations']))) && $_POST['fac_rec'] <= 0) { if (GETPOST('socid', 'int') < 1) { @@ -837,6 +838,12 @@ else if ($action == 'add' && $user->rights->facture->creer) $object->remise_absolue = $_POST['remise_absolue']; $object->remise_percent = $_POST['remise_percent']; + if($_POST['type'] == Facture::TYPE_SITUATION) { + $object->situation_counter = 1; + $object->situation_final = 0; + $object->situation_cycle_ref = $object->newCycle(); + } + $object->fetch_thirdparty(); // If creation from another object of another module (Example: origin=propal, originid=1) @@ -987,6 +994,7 @@ else if ($action == 'add' && $user->rights->facture->creer) $label=(! empty($lines[$i]->label)?$lines[$i]->label:''); $desc=(! empty($lines[$i]->desc)?$lines[$i]->desc:$lines[$i]->libelle); + if ($object->situation_counter == 1) $lines[$i]->situation_percent = 0; if ($lines[$i]->subprice < 0) { @@ -1040,7 +1048,7 @@ else if ($action == 'add' && $user->rights->facture->creer) $array_option = $lines[$i]->array_options; } - $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_option); + $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_option, $lines[$i]->situation_percent, $lines[$i]->fk_prev_id); if ($result > 0) { $lineid = $result; @@ -1089,6 +1097,44 @@ else if ($action == 'add' && $user->rights->facture->creer) } } + if ($_POST['type'] == Facture::TYPE_SITUATION && (!empty($_POST['situations']))) { + $datefacture = dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + if (empty($datefacture)) { + $error++; + $mesg = '<div class="error">' . $langs->trans("ErrorFieldRequired", $langs->trans("Date")) . '</div>'; + } + + if (!($_POST['situations'] > 0)) { + $error++; + $mesg = '<div class="error">' . $langs->trans("ErrorFieldRequired", $langs->trans("InvoiceSituation")) . '</div>'; + } + + if (!$error) { + $result = $object->fetch($_POST['situations']); + $object->fk_facture_source = $_POST['situations']; + $object->type = Facture::TYPE_SITUATION; + + $object->fetch_thirdparty(); + $object->date = $datefacture; + $object->note_public = trim($_POST['note_public']); + $object->note = trim($_POST['note']); + $object->ref_client = $_POST['ref_client']; + $object->ref_int = $_POST['ref_int']; + $object->modelpdf = $_POST['model']; + $object->fk_project = $_POST['projectid']; + $object->cond_reglement_id = $_POST['cond_reglement_id']; + $object->mode_reglement_id = $_POST['mode_reglement_id']; + $object->remise_absolue = $_POST['remise_absolue']; + $object->remise_percent = $_POST['remise_percent']; + + // Proprietes particulieres a facture de remplacement + + $object->situation_counter = $object->situation_counter + 1; + $id = $object->createFromCurrent($user); + if ($id <= 0) $mesg = $object->error; + } + } + // End of object creation, we show it if ($id > 0 && ! $error) { @@ -1312,7 +1358,7 @@ else if ($action == 'addline' && $user->rights->facture->creer) setEventMessage($mesg, 'errors'); } else { // Insert line - $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $date_start, $date_end, 0, $info_bits, '', $price_base_type, $pu_ttc, $type, - 1, $special_code, '', 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_option); + $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $date_start, $date_end, 0, $info_bits, '', $price_base_type, $pu_ttc, $type, - 1, $special_code, '', 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_option, $_POST['progress']); if ($result > 0) { @@ -1363,6 +1409,9 @@ else if ($action == 'addline' && $user->rights->facture->creer) unset($_POST['date_endday']); unset($_POST['date_endmonth']); unset($_POST['date_endyear']); + + unset($_POST['situations']); + unset($_POST['progress']); } else { setEventMessage($object->error, 'errors'); } @@ -1413,6 +1462,17 @@ elseif ($action == 'updateligne' && $user->rights->facture->creer && ! GETPOST(' } } + $line = new FactureLigne($db); + $line->fetch(GETPOST('lineid')); + $percent = $line->get_prev_progress(); + + if (GETPOST('progress') < $percent) { + $mesg = '<div class="warning">' . $langs->trans("CantBeLessThanMinPercent") . '</div>'; + setEventMessages($mesg, null, 'warnings'); + $error++; + $result = -1; + } + // Check minimum price $productid = GETPOST('productid', 'int'); if (! empty($productid)) { @@ -1450,7 +1510,7 @@ elseif ($action == 'updateligne' && $user->rights->facture->creer && ! GETPOST(' // Update line if (! $error) { - $result = $object->updateline(GETPOST('lineid'), $description, $pu_ht, $qty, GETPOST('remise_percent'), $date_start, $date_end, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $info_bits, $type, GETPOST('fk_parent_line'), 0, $fournprice, $buyingprice, $label, 0, $array_option); + $result = $object->updateline(GETPOST('lineid'), $description, $pu_ht, $qty, GETPOST('remise_percent'), $date_start, $date_end, $vat_rate, $localtax1_rate, $localtax2_rate, 'HT', $info_bits, $type, GETPOST('fk_parent_line'), 0, $fournprice, $buyingprice, $label, 0, $array_option, GETPOST('progress')); if ($result >= 0) { if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { @@ -1484,12 +1544,28 @@ elseif ($action == 'updateligne' && $user->rights->facture->creer && ! GETPOST(' unset($_POST['buying_price']); unset($_POST['np_marginRate']); unset($_POST['np_markRate']); + unset($_POST['situations']); + unset($_POST['progress']); } else { setEventMessage($object->error, 'errors'); } } } +else if ($action == 'updatealllines' && $user->rights->facture->creer && $_POST['all_percent'] == $langs->trans('Modifier')) { + if (!$object->fetch($id) > 0) dol_print_error($db); + if (!is_null(GETPOST('all_progress')) && GETPOST('all_progress') != "") { + foreach ($object->lines as $line) { + $percent = $line->get_prev_progress(); + if (GETPOST('all_progress') < $percent) { + $mesg = '<div class="warning">' . $langs->trans("CantBeLessThanMinPercent") . '</div>'; + $result = -1; + } else + $object->update_percent($line, $_POST['all_progress']); + } + } +} + else if ($action == 'updateligne' && $user->rights->facture->creer && $_POST['cancel'] == $langs->trans('Cancel')) { header('Location: ' . $_SERVER["PHP_SELF"] . '?facid=' . $id); // Pour reaffichage de la fiche en cours d'edition exit(); @@ -1800,6 +1876,8 @@ if ($action == 'create') require_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; print ajax_combobox('fac_replacement'); print ajax_combobox('fac_avoir'); + print ajax_combobox('situations'); + } print '<form name="add" action="' . $_SERVER["PHP_SELF"] . '" method="POST">'; @@ -1961,6 +2039,29 @@ if ($action == 'create') if ($socid > 0) { + // First situation invoice + print '<tr height="18"><td width="16px" valign="middle">'; + print '<input type="radio" name="type" value="5"' . (GETPOST('type') == 5 ? ' checked="checked"' : '') . '>'; + print '</td><td valign="middle">'; + $desc = $form->textwithpicto($langs->trans("InvoiceFirstSituationAsk"), $langs->transnoentities("InvoiceFirstSituationDesc"), 1); + print $desc; + print '</td></tr>' . "\n"; + + // Next situation invoice + $opt = $form->load_situation_invoices(GETPOST('originid'), $socid); + print '<tr height="18"><td valign="middle">'; + print '<input type="radio" name="type" value="5"' . (GETPOST('type') == 5 && GETPOST('originid') ? ' checked="checked"' : '') . ' '; + if ($opt == '<option value ="0" selected="selected">' . $langs->trans('NoSituations') . '</option>' || (GETPOST('origin') && GETPOST('origin') != 'facture')) print 'disabled="disabled"'; + print '>'; + print '</td><td valign="middle">'; + $text = $langs->trans("InvoiceSituationAsk") . ' '; + $text .= '<select class="flat" id="situations" name="situations">'; + $text .= $opt; + $text .= '</select>'; + $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceSituationDesc"), 1); + print $desc; + print '</td></tr>' . "\n"; + // Replacement print '<tr height="18"><td valign="middle">'; print '<input type="radio" name="type" id="radio_replacement" value="1"' . (GETPOST('type') == 1 ? ' checked="checked"' : ''); @@ -3093,6 +3194,50 @@ if ($action == 'create') print "</td>"; print '</tr>'; + // Situations + if ($object->type == 5 && ($object->situation_counter > 1)) { + $prevsits = $object->get_prev_sits(); + print '<tr><td>'; + print $langs->trans('SituationAmount'); + print ' '; + + print $prevsits[0]->situation_counter; + for ($i = 1; $i < count($prevsits); $i++) { + print ' + '; + print $prevsits[$i]->situation_counter; + } + print ' + '; + print $object->situation_counter; + + print '</td>'; + print '<td align="right" colspan="2" nowrap>'; + + $prevsits_total_amount = 0; + foreach ($prevsits as $situation) { + $prevsits_total_amount += $situation->total_ht; + } + $prevsits_total_amount += $object->total_ht; + + print price($prevsits_total_amount); + print '</td>'; + print '<td>' . $langs->trans('Currency' . $conf->currency) . '</td></tr>'; + + // Previous situation(s) deduction(s) + for ($i = 0; $i < count($prevsits); $i++) { + print '<tr><td>'; + print '<a href="' . $_SERVER['PHP_SELF'] . '?facid=' . $prevsits[$i]->id . '">'; + print $langs->trans('SituationDeduction'); + print ' '; + print $prevsits[$i]->situation_counter; + print '</a></td>'; + + print '<td align="right" colspan="2" nowrap>'; + print '- ' . price($prevsits[$i]->total_ht); + print '</td>'; + print '<td>' . $langs->trans('Currency' . $conf->currency) . '</td></tr>'; + } + } + // Amount print '<tr><td>' . $langs->trans('AmountHT') . '</td>'; print '<td align="right" colspan="3" nowrap>' . price($object->total_ht, 1, '', 1, - 1, - 1, $conf->currency) . '</td></tr>'; @@ -3190,6 +3335,58 @@ if ($action == 'create') // Lines $result = $object->getLinesArray(); + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; + } + + print '<table id="tablelines" class="noborder noshadow" width="100%">'; + + // Show global modifiers + if ($object->situation_cycle_ref && $object->statut == 0) { + print '<tr class="liste_titre nodrag nodrop">'; + print '<form name="updatealllines" id="updatealllines" action="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '"#updatealllines" method="POST">'; + print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '" />'; + print '<input type="hidden" name="action" value="updatealllines" />'; + print '<input type="hidden" name="id" value="' . $object->id . '" />'; + + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { + print '<td align="center" width="5"> </td>'; + } + print '<td>' . $langs->trans('ModifyAllLines') . '</td>'; + print '<td align="right" width="50"> </td>'; + print '<td align="right" width="80"> </td>'; + if ($inputalsopricewithtax) print '<td align="right" width="80"> </td>'; + print '<td align="right" width="50"> </td>'; + print '<td align="right" width="50"> </td>'; + print '<td align="right" width="50">' . $langs->trans('Progress') . '</td>'; + if (! empty($conf->margin->enabled) && empty($user->societe_id)) + { + print '<td align="right" class="margininfos" width="80"> </td>'; + if ((! empty($conf->global->DISPLAY_MARGIN_RATES) || ! empty($conf->global->DISPLAY_MARK_RATES)) && $user->rights->margins->liretous) { + print '<td align="right" class="margininfos" width="50"> </td>'; + } + } + print '<td align="right" width="50"> </td>'; + print '<td> </td>'; + print '<td width="10"> </td>'; + print '<td width="10"> </td>'; + print "</tr>\n"; + + if (!empty($conf->global->MAIN_VIEW_LINE_NUMBER)) { + print '<td align="center" width="5"> </td>'; + } + print '<tr width="100%" height="18" class="nodrag nodrop">'; + print '<td> </td>'; + print '<td width="50"> </td>'; + print '<td width="80"> </td>'; + print '<td width="50"> </td>'; + print '<td width="50"> </td>'; + print '<td align="right" class="nowrap"><input type="text" size="1" value="" name="all_progress">%</td>'; + print '<td colspan="4" align="right"><input class="button" type="submit" name="all_percent" value="Modifier" /></td>'; + print '</tr>'; + print '</form>'; + } + print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '#add' : '#line_' . GETPOST('lineid')) . '" method="POST"> <input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '"> <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateligne') . '"> @@ -3197,18 +3394,12 @@ if ($action == 'create') <input type="hidden" name="id" value="' . $object->id . '"> '; - if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { - include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; - } - - print '<table id="tablelines" class="noborder noshadow" width="100%">'; - // Show object lines if (! empty($object->lines)) $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 1); // Form to add new line - if ($object->statut == 0 && $user->rights->facture->creer && $action != 'valid' && $action != 'editline') + if ($object->statut == 0 && $user->rights->facture->creer && $action != 'valid' && $action != 'editline' && ($object->is_first() || !$object->situation_cycle_ref)) { if ($action != 'editline') { @@ -3245,12 +3436,14 @@ if ($action == 'create') $ventilExportCompta = $object->getVentilExportCompta(); if ($resteapayer == $object->total_ttc && $object->paye == 0 && $ventilExportCompta == 0) { - if (! $objectidnext) { + if (! $objectidnext && $object->is_last_in_cycle()) { if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && $user->rights->facture->valider) || $user->rights->facture->invoice_advance->unvalidate) { print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?facid=' . $object->id . '&action=modif">' . $langs->trans('Modify') . '</a></div>'; } else { print '<div class="inline-block divButAction"><span class="butActionRefused" title="' . $langs->trans("NotEnoughPermissions") . '">' . $langs->trans('Modify') . '</span></div>'; } + } else if (!$object->is_last_in_cycle()) { + print '<div class="inline-block divButAction"><span class="butActionRefused" title="' . $langs->trans("NotLastInCycle") . '">' . $langs->trans('Modify') . '</span></div>'; } else { print '<div class="inline-block divButAction"><span class="butActionRefused" title="' . $langs->trans("DisabledBecauseReplacedInvoice") . '">' . $langs->trans('Modify') . '</span></div>'; } @@ -3273,7 +3466,7 @@ if ($action == 'create') } // Validate - if ($object->statut == 0 && count($object->lines) > 0 && ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && (! empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) || ($object->type == Facture::TYPE_CREDIT_NOTE && $object->total_ttc <= 0))) { + if ($object->statut == 0 && count($object->lines) > 0 && ((($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_REPLACEMENT || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA|| $object->type == Facture::TYPE_SITUATION) && (! empty($conf->global->FACTURE_ENABLE_NEGATIVE) || $object->total_ttc >= 0)) || ($object->type == Facture::TYPE_CREDIT_NOTE && $object->total_ttc <= 0))) { if ($user->rights->facture->valider) { print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?facid=' . $object->id . '&action=valid">' . $langs->trans('Validate') . '</a></div>'; } @@ -3385,6 +3578,17 @@ if ($action == 'create') } } + //Create next situation invoice + if ($user->rights->facture->creer && ($object->type == 5) && ($object->statut == 1 || $object->statut == 2)) { + if ($object->is_last_in_cycle() && $object->situation_final != 1) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=create&type=5&origin=facture&originid=' . $object->id . '&socid=' . $object->socid . '" >' . $langs->trans('CreateNextSituationInvoice') . '</a></div>'; + } else if (!$object->is_last_in_cycle()) { + print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseNotLastInCycle") . '">' . $langs->trans('CreateNextSituationInvoice') . '</a></div>'; + } else { + print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="' . $langs->trans("DisabledBecauseFinal") . '">' . $langs->trans('CreateNextSituationInvoice') . '</a></div>'; + } + } + // Delete if ($user->rights->facture->supprimer) { diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index f81fb37849f9221d25c4075c038109363482a8a8..f28f068c2558e6d400a4985373fdf2c4edd63090 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -10,6 +10,8 @@ * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr> * Copyright (C) 2012-2014 Marcos García <marcosgdf@gmail.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2013 Cedric Gross <c.gross@kreiz-it.fr> * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> * @@ -122,6 +124,21 @@ class Facture extends CommonInvoice var $fac_rec; + /** + * @var int Situation cycle reference number + */ + public $situation_cycle_ref; + + /** + * @var int Situation counter inside the cycle + */ + public $situation_counter; + + /** + * @var bool Final situation flag + */ + public $situation_final; + /** * Standard invoice */ @@ -147,6 +164,11 @@ class Facture extends CommonInvoice */ const TYPE_PROFORMA = 4; + /** + * Situation invoice + */ + const TYPE_SITUATION = 5; + /** * Constructor * @@ -180,6 +202,17 @@ class Facture extends CommonInvoice if (! $this->cond_reglement_id) $this->cond_reglement_id = 0; if (! $this->mode_reglement_id) $this->mode_reglement_id = 0; $this->brouillon = 1; + if (empty($this->situation_cycle_ref)) { + $this->situation_cycle_ref = 'null'; + } + + if (empty($this->situation_counter)) { + $this->situation_counter = 'null'; + } + + if (empty($this->situation_final)) { + $this->situation_final = '0'; + } dol_syslog(get_class($this)."::create user=".$user->id); @@ -248,6 +281,7 @@ class Facture extends CommonInvoice $sql.= ", fk_account"; $sql.= ", fk_facture_source, fk_user_author, fk_projet"; $sql.= ", fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf"; + $sql.= ", situation_cycle_ref, situation_counter, situation_final"; $sql.= ")"; $sql.= " VALUES ("; $sql.= "'(PROV)'"; @@ -269,7 +303,11 @@ class Facture extends CommonInvoice $sql.= ",".($this->fk_project?$this->fk_project:"null"); $sql.= ','.$this->cond_reglement_id; $sql.= ",".$this->mode_reglement_id; - $sql.= ", '".$this->db->idate($datelim)."', '".$this->modelpdf."')"; + $sql.= ", '".$this->db->idate($datelim)."', '".$this->modelpdf."'"; + $sql.= ", ".$this->situation_cycle_ref; + $sql.= ", ".$this->situation_counter; + $sql.= ", ".$this->situation_final; + $sql.=")"; dol_syslog(get_class($this)."::create", LOG_DEBUG); $resql=$this->db->query($sql); @@ -399,7 +437,9 @@ class Facture extends CommonInvoice $this->lines[$i]->fk_fournprice, $this->lines[$i]->pa_ht, $this->lines[$i]->label, - $this->lines[$i]->array_options + $this->lines[$i]->array_options, + $this->lines[$i]->situation_percent, + $this->lines[$i]->fk_prev_id ); if ($result < 0) { @@ -451,7 +491,9 @@ class Facture extends CommonInvoice 0, null, 0, - $_facrec->lines[$i]->label + $_facrec->lines[$i]->label, + null, + $_facrec->lines[$i]->situation_percent ); if ( $result_insert < 0) @@ -556,10 +598,14 @@ class Facture extends CommonInvoice $facture->lines = $this->lines; // Tableau des lignes de factures $facture->products = $this->lines; // Tant que products encore utilise + $facture->situation_counter = $this->situation_counter; + $facture->situation_cycle_ref=$this->situation_cycle_ref; + $facture->situation_final = $this->situation_final; // Loop on each line of new invoice foreach($facture->lines as $i => $line) { + $facture->lines[$i]->fk_prev_id = $this->lines[$i]->rowid; if ($invertdetail) { $facture->lines[$i]->subprice = -$facture->lines[$i]->subprice; @@ -827,6 +873,7 @@ class Facture extends CommonInvoice if ($this->type == self::TYPE_REPLACEMENT) $label=$langs->transnoentitiesnoconv("ShowInvoiceReplace").': '.$this->ref; if ($this->type == self::TYPE_CREDIT_NOTE) $label=$langs->transnoentitiesnoconv("ShowInvoiceAvoir").': '.$this->ref; if ($this->type == self::TYPE_DEPOSIT) $label=$langs->transnoentitiesnoconv("ShowInvoiceDeposit").': '.$this->ref; + if ($this->type == self::TYPE_SITUATION) $label=$langs->transnoentitiesnoconv("ShowInvoiceSituation").': '.$this->ref; if ($moretitle) $label.=' - '.$moretitle; $linkstart='<a href="'.$url.'">'; @@ -863,6 +910,7 @@ class Facture extends CommonInvoice $sql.= ', f.note_private, f.note_public, f.fk_statut, f.paye, f.close_code, f.close_note, f.fk_user_author, f.fk_user_valid, f.model_pdf'; $sql.= ', f.fk_facture_source'; $sql.= ', f.fk_mode_reglement, f.fk_cond_reglement, f.fk_projet, f.extraparams'; + $sql.= ', f.situation_cycle_ref, f.situation_counter, f.situation_final'; $sql.= ', f.fk_account'; $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle'; $sql.= ', c.code as cond_reglement_code, c.libelle as cond_reglement_libelle, c.libelle_facture as cond_reglement_libelle_doc'; @@ -923,7 +971,9 @@ class Facture extends CommonInvoice $this->user_author = $obj->fk_user_author; $this->user_valid = $obj->fk_user_valid; $this->modelpdf = $obj->model_pdf; - + $this->situation_cycle_ref = $obj->situation_cycle_ref; + $this->situation_counter = $obj->situation_counter; + $this->situation_final = $obj->situation_final; $this->extraparams = (array) json_decode($obj->extraparams, true); if ($this->statut == 0) $this->brouillon = 1; @@ -974,6 +1024,7 @@ class Facture extends CommonInvoice $this->lines=array(); $sql = 'SELECT l.rowid, l.fk_product, l.fk_parent_line, l.label as custom_label, l.description, l.product_type, l.price, l.qty, l.tva_tx, '; + $sql .= ' l.situation_percent, l.fk_prev_id,'; $sql.= ' l.localtax1_tx, l.localtax2_tx, l.localtax1_type, l.localtax2_type, l.remise_percent, l.fk_remise_except, l.subprice,'; $sql.= ' l.rang, l.special_code,'; $sql.= ' l.date_start as date_start, l.date_end as date_end,'; @@ -1033,6 +1084,8 @@ class Facture extends CommonInvoice $line->rang = $objp->rang; $line->special_code = $objp->special_code; $line->fk_parent_line = $objp->fk_parent_line; + $line->situation_percent= $objp->situation_percent; + $line->fk_prev_id = $objp->fk_prev_id; $this->lines[$i] = $line; @@ -1073,6 +1126,17 @@ class Facture extends CommonInvoice if (isset($this->note_public)) $this->note_public=trim($this->note_public); if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf); if (isset($this->import_key)) $this->import_key=trim($this->import_key); + if (empty($this->situation_cycle_ref)) { + $this->situation_cycle_ref = 'null'; + } + + if (empty($this->situation_counter)) { + $this->situation_counter = 'null'; + } + + if (empty($this->situation_final)) { + $this->situation_final = '0'; + } // Check parameters // Put here code to add control on parameters values @@ -1110,7 +1174,10 @@ class Facture extends CommonInvoice $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.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null").""; + $sql.= " import_key=".(isset($this->import_key)?"'".$this->db->escape($this->import_key)."'":"null"); + $sql.= ", situation_cycle_ref=".$this->situation_cycle_ref; + $sql.= ", situation_counter=".$this->situation_counter; + $sql.= ", situation_final=".$this->situation_final; $sql.= " WHERE rowid=".$this->id; @@ -1808,6 +1875,15 @@ class Facture extends CommonInvoice $this->statut=1; $this->brouillon=0; $this->date_validation=$now; + $i = 0; + $final = True; + while ($i < count($this->lines) && $final == True) { + $final = ($this->lines[$i]->situation_percent == 100); + $i++; + } + if ($final) { + $this->setFinal(); + } } } else @@ -1947,9 +2023,11 @@ class Facture extends CommonInvoice * @param int $pa_ht Buying price of line (to calculate margin) or '' * @param string $label Label of the line (deprecated, do not use) * @param array $array_option extrafields array + * @param int $situation_percent Situation advance percentage + * @param int $fk_prev_id Previous situation line id reference * @return int <0 if KO, Id of line if OK */ - function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=self::TYPE_STANDARD, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='', $array_option=0) + function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $date_start='', $date_end='', $ventil=0, $info_bits=0, $fk_remise_except='', $price_base_type='HT', $pu_ttc=0, $type=self::TYPE_STANDARD, $rang=-1, $special_code=0, $origin='', $origin_id=0, $fk_parent_line=0, $fk_fournprice=null, $pa_ht=0, $label='', $array_option=0, $situation_percent=0, $fk_prev_id='') { global $mysoc, $conf, $langs; @@ -1966,6 +2044,8 @@ class Facture extends CommonInvoice if (empty($txlocaltax1)) $txlocaltax1=0; if (empty($txlocaltax2)) $txlocaltax2=0; if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; + if (empty($fk_prev_id)) $fk_prev_id = 'null'; + if (is_null($situation_percent) || $situation_percent > 100) $situation_percent = 100; $remise_percent=price2num($remise_percent); $qty=price2num($qty); @@ -1999,7 +2079,7 @@ class Facture extends CommonInvoice $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty, $mysoc); - $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type); + $tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $mysoc, $localtaxes_type, $situation_percent); $total_ht = $tabprice[0]; $total_tva = $tabprice[1]; @@ -2060,6 +2140,8 @@ class Facture extends CommonInvoice $this->line->fk_parent_line=$fk_parent_line; $this->line->origin=$origin; $this->line->origin_id=$origin_id; + $this->line->situation_percent = $situation_percent; + $this->line->fk_prev_id = $fk_prev_id; // infos marge $this->line->fk_fournprice = $fk_fournprice; @@ -2121,9 +2203,10 @@ class Facture extends CommonInvoice * @param string $label Label of the line (deprecated, do not use) * @param int $special_code Special code (also used by externals modules!) * @param array $array_option extrafields array + * @param int $situation_percent Situation advance percentage * @return int < 0 if KO, > 0 if OK */ - function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type= self::TYPE_STANDARD, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_option=0) + function updateline($rowid, $desc, $pu, $qty, $remise_percent, $date_start, $date_end, $txtva, $txlocaltax1=0, $txlocaltax2=0, $price_base_type='HT', $info_bits=0, $type= self::TYPE_STANDARD, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=null, $pa_ht=0, $label='', $special_code=0, $array_option=0, $situation_percent=0) { include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; @@ -2139,6 +2222,8 @@ class Facture extends CommonInvoice if (empty($qty)) $qty=0; if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; if (empty($special_code) || $special_code == 3) $special_code=0; + if ($situation_percent > 100 || is_null($situation_percent) || $situation_percent == "") $situation_percent = 100; + $remise_percent = price2num($remise_percent); $qty = price2num($qty); @@ -2157,7 +2242,7 @@ class Facture extends CommonInvoice $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty, $mysoc); - $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type,'',$localtaxes_type); + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type,'',$localtaxes_type, $situation_percent); $total_ht = $tabprice[0]; $total_tva = $tabprice[1]; $total_ttc = $tabprice[2]; @@ -2205,6 +2290,8 @@ class Facture extends CommonInvoice $this->line->product_type = $type; $this->line->fk_parent_line = $fk_parent_line; $this->line->skip_update_total = $skip_update_total; + $this->line->situation_percent = $situation_percent; + // infos marge if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) { @@ -2247,6 +2334,28 @@ class Facture extends CommonInvoice } } + /** + * @param FactureLigne $line Invoice line + * @param int $percent + */ + function update_percent($line, $percent) + { + include_once(DOL_DOCUMENT_ROOT . '/core/lib/price.lib.php'); + + // Cap percentages to 100 + if ($percent > 100) $percent = 100; + $line->situation_percent = $percent; + $tabprice = calcul_price_total($line->qty, $line->subprice, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->product_type, 'HT', 0, 0, '', '', $percent); + $line->total_ht = $tabprice[0]; + $line->total_tva = $tabprice[1]; + $line->total_ttc = $tabprice[2]; + $line->total_localtax1 = $tabprice[9]; + $line->total_localtax2 = $tabprice[10]; + $line->update(); + $this->update_price(1); + $this->db->commit(); + } + /** * Delete line in database * @@ -2647,6 +2756,10 @@ class Facture extends CommonInvoice if ($maxfacnumber == '' && $ventilExportCompta == 0) return 1; // If invoice to delete is last one and not already dispatched, we can delete if ($maxfacnumber == $this->ref && $ventilExportCompta == 0) return 1; + if ($this->situation_cycle_ref) { + $last = $this->is_last_in_cycle(); + return $last; + } } else if ($this->statut == 0 && $facref == 'PROV') // Si facture brouillon et provisoire { @@ -3206,6 +3319,7 @@ class Facture extends CommonInvoice { $sql = 'SELECT l.rowid, l.label as custom_label, l.description, l.fk_product, l.product_type, l.qty, l.tva_tx,'; $sql.= ' l.fk_remise_except, l.localtax1_tx, l.localtax2_tx,'; + $sql .= ' l.situation_percent, l.fk_prev_id,'; $sql.= ' l.remise_percent, l.subprice, l.info_bits, l.rang, l.special_code, l.fk_parent_line,'; $sql.= ' l.total_ht, l.total_tva, l.total_ttc, l.fk_product_fournisseur_price as fk_fournprice, l.buy_price_ht as pa_ht,'; $sql.= ' l.date_start, l.date_end,'; @@ -3247,6 +3361,8 @@ class Facture extends CommonInvoice $this->lines[$i]->total_tva = $obj->total_tva; $this->lines[$i]->total_ttc = $obj->total_ttc; $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; + $this->lines[$i]->situation_percent = $obj->situation_percent; + $this->lines[$i]->fk_prev_id = $obj->fk_prev_id; $this->lines[$i]->special_code = $obj->special_code; $this->lines[$i]->rang = $obj->rang; $this->lines[$i]->date_start = $this->db->jdate($obj->date_start); @@ -3304,11 +3420,118 @@ class Facture extends CommonInvoice return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); } + /** + * Gets the smallest reference available for a new cycle + * + * @return int >= 1 if OK, -1 if error + * + * + */ + function newCycle() + { + $sql = 'SELECT max(situation_cycle_ref) FROM ' . MAIN_DB_PREFIX . 'facture'; + $resql = $this->db->query($sql); + if ($resql) { + if ($resql->num_rows > 0) { + $res = $this->db->fetch_array($resql); + $ref = $res['max(situation_cycle_ref)']; + $ref++; + } else { + $ref = 1; + } + $this->db->free($resql); + return $ref; + } else { + $this->error = $this->db->error(); + dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR); + return -1; + } + } + /** + * Checks if the invoice is the first of a cycle + * + */ + function is_first() + { + return ($this->situation_counter == 1); + } -} + /** + * Returns an array containing the previous situations as Facture objects + * + */ + function get_prev_sits() + { + + $sql = 'SELECT rowid FROM ' . MAIN_DB_PREFIX . 'facture'; + $sql .= ' where situation_cycle_ref = ' . $this->situation_cycle_ref; + $sql .= ' and situation_counter < ' . $this->situation_counter; + $resql = $this->db->query($sql); + $res = array(); + if ($resql && $resql->num_rows > 0) { + while ($row = $this->db->fetch_object($resql)) { + $id = $row->rowid; + $situation = new Facture($this->db); + $situation->fetch($id); + $res[] = $situation; + } + } else { + $this->error = $this->db->error(); + dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR); + return -1; + } + + return $res; + } + + /** + * Sets the invoice as a final situation + * + * @return int 1 if ok, -1 if error + */ + function setFinal() + { + global $conf, $langs, $user; + $this->situation_final = 1; + $sql = 'update ' . MAIN_DB_PREFIX . 'facture set situation_final = ' . $this->situation_final . ' where rowid = ' . $this->id; + $resql = $this->db->query($sql); + if ($resql) { + // FIXME: call triggers? + $this->db->commit(); + return 1; + } else { + $this->error = $this->db->error(); + dol_syslog(get_class($this) . "::update Error setFinal " . $sql, LOG_ERR); + $this->db->rollback(); + return -1; + } + } + /** + * Checks if the invoice is the last in its cycle + * + * @return int 0 or 1 if OK, -1 if error + * + */ + + function is_last_in_cycle() + { + $sql = 'SELECT max(situation_counter) FROM ' . MAIN_DB_PREFIX . 'facture WHERE situation_cycle_ref = ' . $this->situation_cycle_ref; + $resql = $this->db->query($sql); + if ($resql && $resql->num_rows > 0) { + $res = $this->db->fetch_array($resql); + $last = $res['max(situation_counter)']; + return ($last == $this->situation_counter); + } else { + $this->error = $this->db->error(); + dol_syslog(get_class($this) . "::select Error " . $this->error, LOG_ERR); + $this->db->rollback(); + return -1; + } + } +} /** * Class to manage invoice lines. @@ -3391,6 +3614,16 @@ class FactureLigne extends CommonInvoiceLine var $skip_update_total; // Skip update price total for special lines + /** + * @var int Situation advance percentage + */ + public $situation_percent; + + /** + * @var int Previous situation line id reference + */ + public $fk_prev_id; + /** * Constructor * @@ -3414,6 +3647,7 @@ class FactureLigne extends CommonInvoiceLine $sql.= ' fd.date_start as date_start, fd.date_end as date_end, fd.fk_product_fournisseur_price as fk_fournprice, fd.buy_price_ht as pa_ht,'; $sql.= ' fd.info_bits, fd.special_code, fd.total_ht, fd.total_tva, fd.total_ttc, fd.total_localtax1, fd.total_localtax2, fd.rang,'; $sql.= ' fd.fk_code_ventilation,'; + $sql.= ' fd.situation_percent, fd.fk_prev_id,'; $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc'; $sql.= ' FROM '.MAIN_DB_PREFIX.'facturedet as fd'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON fd.fk_product = p.rowid'; @@ -3461,6 +3695,9 @@ class FactureLigne extends CommonInvoiceLine $this->product_label = $objp->product_libelle; $this->product_desc = $objp->product_desc; + $this->situation_percent = $objp->situation_percent; + $this->fk_prev_id = $objp->fk_prev_id; + $this->db->free($result); } else @@ -3498,6 +3735,8 @@ class FactureLigne extends CommonInvoiceLine if (empty($this->subprice)) $this->subprice=0; if (empty($this->special_code)) $this->special_code=0; if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (empty($this->fk_prev_id)) $this->fk_prev_id = 'null'; + if (empty($this->situation_percent)) $this->situation_percent = 0; if (empty($this->pa_ht)) $this->pa_ht=0; @@ -3541,7 +3780,8 @@ class FactureLigne extends CommonInvoiceLine $sql.= ' fk_product, product_type, remise_percent, subprice, fk_remise_except,'; $sql.= ' date_start, date_end, fk_code_ventilation, '; $sql.= ' rang, special_code, fk_product_fournisseur_price, buy_price_ht,'; - $sql.= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2)'; + $sql.= ' info_bits, total_ht, total_tva, total_ttc, total_localtax1, total_localtax2,'; + $sql.= ' situation_percent, fk_prev_id)'; $sql.= " VALUES (".$this->fk_facture.","; $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").","; $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").","; @@ -3570,6 +3810,8 @@ class FactureLigne extends CommonInvoiceLine $sql.= " ".price2num($this->total_ttc).","; $sql.= " ".price2num($this->total_localtax1).","; $sql.= " ".price2num($this->total_localtax2); + $sql .= ", " . $this->situation_percent; + $sql .= ", " . $this->fk_prev_id; $sql.= ')'; dol_syslog(get_class($this)."::insert", LOG_DEBUG); @@ -3687,6 +3929,7 @@ class FactureLigne extends CommonInvoiceLine if (empty($this->special_code)) $this->special_code=0; if (empty($this->product_type)) $this->product_type=0; if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (is_null($this->situation_percent)) $this->situation_percent=100; // Check parameters if ($this->product_type < 0) return -1; @@ -3732,6 +3975,7 @@ class FactureLigne extends CommonInvoiceLine $sql.= " , buy_price_ht='".price2num($this->pa_ht)."'"; $sql.= ",fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null"); if (! empty($this->rang)) $sql.= ", rang=".$this->rang; + $sql .= ", situation_percent=" . $this->situation_percent; $sql.= " WHERE rowid = ".$this->rowid; dol_syslog(get_class($this)."::update", LOG_DEBUG); @@ -3846,5 +4090,29 @@ class FactureLigne extends CommonInvoiceLine return -2; } } -} + /** + * Returns situation_percent of the previous line + * + * @return int >= 0 + */ + + function get_prev_progress() + { + if (is_null($this->fk_prev_id) || empty($this->fk_prev_id) || $this->fk_prev_id == "") { + return 0; + } else { + $sql = 'SELECT situation_percent FROM ' . MAIN_DB_PREFIX . 'facturedet WHERE rowid=' . $this->fk_prev_id; + $resql = $this->db->query($sql); + if ($resql && $resql->num_rows > 0) { + $res = $this->db->fetch_array($resql); + return $res['situation_percent']; + } else { + $this->error = $this->db->error(); + dol_syslog(get_class($this) . "::select Error " . $this->error, LOG_ERR); + $this->db->rollback(); + return -1; + } + } + } +} diff --git a/htdocs/compta/facture/impayees.php b/htdocs/compta/facture/impayees.php index a010e7d74011ad39929659a115881cc95cceedef..0c6b2af84f0f0836847f1ed1f1112fb2054b6b5f 100644 --- a/htdocs/compta/facture/impayees.php +++ b/htdocs/compta/facture/impayees.php @@ -3,6 +3,8 @@ * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> * Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -408,7 +410,7 @@ $sql.= ",".MAIN_DB_PREFIX."facture as f"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid=pf.fk_facture "; $sql.= " WHERE f.fk_soc = s.rowid"; $sql.= " AND f.entity = ".$conf->entity; -$sql.= " AND f.type IN (0,1,3) AND f.fk_statut = 1"; +$sql.= " AND f.type IN (0,1,3,5) AND f.fk_statut = 1"; $sql.= " AND f.paye = 0"; if ($option == 'late') $sql.=" AND f.date_lim_reglement < '".$db->idate(dol_now() - $conf->facture->client->warning_delay)."'"; if (! $user->rights->societe->client->voir && ! $socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; diff --git a/htdocs/compta/journal/sellsjournal.php b/htdocs/compta/journal/sellsjournal.php index e249d3fe55479afd8a282a75a0eb70329efeb8fb..9fd0d411d8ee06afae1004a2cb4871bd5de9b433 100644 --- a/htdocs/compta/journal/sellsjournal.php +++ b/htdocs/compta/journal/sellsjournal.php @@ -4,7 +4,9 @@ * Copyright (C) 2011-2014 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2011-2012 Alexandre Spangaro <alexandre.spangaro@gmail.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> * Copyright (C) 2013 Marcos García <marcosgdf@gmail.com> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -101,7 +103,7 @@ $p = explode(":", $conf->global->MAIN_INFO_SOCIETE_COUNTRY); $idpays = $p[0]; $sql = "SELECT f.rowid, f.facnumber, f.type, f.datef, f.ref_client,"; -$sql.= " fd.product_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.total_ttc, fd.localtax1_tx, fd.localtax2_tx, fd.total_localtax1, fd.total_localtax2,"; +$sql.= " fd.product_type, fd.total_ht, fd.total_tva, fd.tva_tx, fd.total_ttc, fd.localtax1_tx, fd.localtax2_tx, fd.total_localtax1, fd.total_localtax2, fd.rowid as id, fd.situation_percent,"; $sql.= " s.rowid as socid, s.nom as name, s.code_compta, s.client,"; $sql.= " p.rowid as pid, p.ref as pref, p.accountancy_code_sell,"; $sql.= " ct.accountancy_code_sell as account_tva, ct.recuperableonly"; @@ -112,8 +114,8 @@ $sql.= " JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = f.fk_soc"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_tva ct ON fd.tva_tx = ct.taux AND fd.info_bits = ct.recuperableonly AND ct.fk_pays = '".$idpays."'"; $sql.= " WHERE f.entity = ".$conf->entity; $sql.= " AND f.fk_statut > 0"; -if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; -else $sql.= " AND f.type IN (0,1,2,3)"; +if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; +else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND fd.product_type IN (0,1)"; if ($date_start && $date_end) $sql .= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql.= " ORDER BY f.rowid"; @@ -157,6 +159,16 @@ if ($result) $account_localtax2=getLocalTaxesFromRate($obj->tva_tx, 2, $obj->thirdparty, $mysoc); $compta_localtax2= (! empty($account_localtax2[3])?$account_localtax2[3]:$langs->trans("CodeNotDef")); + // Situation invoices handling + $line = new FactureLigne($db); + $line->fetch($obj->id); + $prev_progress = $line->get_prev_progress(); + if ($obj->situation_percent == 0) { // Avoid divide by 0 + $situation_ratio = 0; + } else { + $situation_ratio = ($obj->situation_percent - $prev_progress) / $obj->situation_percent; + } + //la ligne facture $tabfac[$obj->rowid]["date"] = $obj->datef; $tabfac[$obj->rowid]["ref"] = $obj->facnumber; @@ -166,9 +178,9 @@ if ($result) if (! isset($tabtva[$obj->rowid][$compta_tva])) $tabtva[$obj->rowid][$compta_tva]=0; if (! isset($tablocaltax1[$obj->rowid][$compta_localtax1])) $tablocaltax1[$obj->rowid][$compta_localtax1]=0; if (! isset($tablocaltax2[$obj->rowid][$compta_localtax2])) $tablocaltax2[$obj->rowid][$compta_localtax2]=0; - $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc; - $tabht[$obj->rowid][$compta_prod] += $obj->total_ht; - if($obj->recuperableonly != 1) $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva; + $tabttc[$obj->rowid][$compta_soc] += $obj->total_ttc * $situation_ratio; + $tabht[$obj->rowid][$compta_prod] += $obj->total_ht * $situation_ratio; + if($obj->recuperableonly != 1) $tabtva[$obj->rowid][$compta_tva] += $obj->total_tva * $situation_ratio; $tablocaltax1[$obj->rowid][$compta_localtax1] += $obj->total_localtax1; $tablocaltax2[$obj->rowid][$compta_localtax2] += $obj->total_localtax2; $tabcompany[$obj->rowid]=array('id'=>$obj->socid, 'name'=>$obj->name, 'client'=>$obj->client); diff --git a/htdocs/compta/paiement.php b/htdocs/compta/paiement.php index 0ccf0dee6bfc06174afc620d060cda6c096330b0..fabf656c89543bef36bce13292fb799de24e5fb1 100644 --- a/htdocs/compta/paiement.php +++ b/htdocs/compta/paiement.php @@ -4,6 +4,8 @@ * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com> * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2007 Franky Van Liedekerke <franky.van.liedekerke@telenet.be> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2014 Teddy Andreotti <125155@supinfo.com> * * This program is free software; you can redistribute it and/or modify @@ -469,7 +471,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie $sql.= ' AND f.fk_statut = 1'; // Statut=0 => not validated, Statut=2 => canceled if ($facture->type != 2) { - $sql .= ' AND type IN (0,1,3)'; // Standard invoice, replacement, deposit + $sql .= ' AND type IN (0,1,3,5)'; // Standard invoice, replacement, deposit, situation } else { diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index 95503db6ff97aeea6d5f3497b33ae83e8cc4524b..6c3743f70a60f09a0538d4b79ffa5667dab6d526 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -2,6 +2,8 @@ /* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -212,13 +214,14 @@ class Paiement extends CommonObject //Invoice types that are eligible for changing status to paid $affected_types = array( - 0, - 1, - 2, - 3 + Facture::TYPE_STANDARD, + Facture::TYPE_REPLACEMENT, + Facture::TYPE_CREDIT_NOTE, + Facture::TYPE_DEPOSIT, + Facture::TYPE_SITUATION ); - if (!in_array($invoice->type, $affected_types)) dol_syslog("Invoice ".$facid." is not a standard, nor replacement invoice, nor credit note, nor deposit invoice. We do nothing more."); + if (!in_array($invoice->type, $affected_types)) dol_syslog("Invoice ".$facid." is not a standard, nor replacement invoice, nor credit note, nor deposit invoice, nor situation invoice. We do nothing more."); else if ($remaintopay) dol_syslog("Remain to pay for invoice ".$facid." not null. We do nothing more."); else if ($mustwait) dol_syslog("There is ".$mustwait." differed payment to process, we do nothing more."); else diff --git a/htdocs/compta/resultat/clientfourn.php b/htdocs/compta/resultat/clientfourn.php index 9122ece2ed9216cf205732f3c8dd303985b41296..8c522df75d4dd10008bf99b9785c1646432bdc63 100644 --- a/htdocs/compta/resultat/clientfourn.php +++ b/htdocs/compta/resultat/clientfourn.php @@ -2,6 +2,8 @@ /* Copyright (C) 2002-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org> * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Dourseanud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es> * Copyright (C) 2014 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2014 Florian Henry <florian.henry@open-concept.pro> @@ -166,9 +168,9 @@ if ($modecompta == 'CREANCES-DETTES') $sql.= " WHERE f.fk_soc = s.rowid"; $sql.= " AND f.fk_statut IN (1,2)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) - $sql.= " AND f.type IN (0,1,2)"; + $sql.= " AND f.type IN (0,1,2,5)"; else - $sql.= " AND f.type IN (0,1,2,3)"; + $sql.= " AND f.type IN (0,1,2,3,5)"; if (! empty($date_start) && ! empty($date_end)) $sql.= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; } @@ -693,9 +695,9 @@ if ($modecompta == 'CREANCES-DETTES') $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql.= " WHERE f.fk_statut IN (1,2)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) - $sql.= " AND f.type IN (0,1,2)"; + $sql.= " AND f.type IN (0,1,2,5)"; else - $sql.= " AND f.type IN (0,1,2,3)"; + $sql.= " AND f.type IN (0,1,2,3,5)"; if (! empty($date_start) && ! empty($date_end)) $sql.= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; $sql.= " AND f.entity = ".$conf->entity; diff --git a/htdocs/compta/resultat/index.php b/htdocs/compta/resultat/index.php index b586241c11ece86fd053ffc7eb8a35e3252d6d41..ec29d25a76ecaca214a0f8aa4cb0171bc6d8e09a 100644 --- a/htdocs/compta/resultat/index.php +++ b/htdocs/compta/resultat/index.php @@ -103,8 +103,8 @@ if ($modecompta == 'CREANCES-DETTES') $sql.= ", ".MAIN_DB_PREFIX."facture as f"; $sql.= " WHERE f.fk_soc = s.rowid"; $sql.= " AND f.fk_statut IN (1,2)"; - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; } else { @@ -246,8 +246,8 @@ if ($modecompta == 'CREANCES-DETTES') $sql = "SELECT sum(f.tva) as amount, date_format(f.datef,'%Y-%m') as dm"; $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql.= " WHERE f.fk_statut IN (1,2)"; - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND f.entity = ".$conf->entity; $sql.= " GROUP BY dm"; diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index 8263dc76cb8b4ed021ac8214e2e8cc6b697e392c..61f0bbb590d44411aa3897e1f06f46eec3fff428 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -193,9 +193,9 @@ if ($modecompta == 'CREANCES-DETTES') $sql.= " AND l.fk_facture = f.rowid"; $sql.= " AND f.fk_statut in (1,2)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { - $sql.= " AND f.type IN (0,1,2)"; + $sql.= " AND f.type IN (0,1,2,5)"; } else { - $sql.= " AND f.type IN (0,1,2,3)"; + $sql.= " AND f.type IN (0,1,2,3,5)"; } if ($date_start && $date_end) { $sql.= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; diff --git a/htdocs/compta/stats/cabyuser.php b/htdocs/compta/stats/cabyuser.php index e88d370a0c6b93d1ed2f8e02defd52bed871c08d..066967cc2c3f97da102b707d3b3d379cb9b2200d 100644 --- a/htdocs/compta/stats/cabyuser.php +++ b/htdocs/compta/stats/cabyuser.php @@ -178,9 +178,9 @@ if ($modecompta == 'CREANCES-DETTES') { $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON f.fk_user_author = u.rowid"; $sql.= " WHERE f.fk_statut in (1,2)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { - $sql.= " AND f.type IN (0,1,2)"; + $sql.= " AND f.type IN (0,1,2,5)"; } else { - $sql.= " AND f.type IN (0,1,2,3)"; + $sql.= " AND f.type IN (0,1,2,3,5)"; } if ($date_start && $date_end) { $sql.= " AND f.datef >= '".$db->idate($date_start)."' AND f.datef <= '".$db->idate($date_end)."'"; diff --git a/htdocs/compta/stats/casoc.php b/htdocs/compta/stats/casoc.php index 1d34f78a181ca76071585092cc3137fd8e54df7c..a4c4663dc40052c0ffc652d262c0e99854721a65 100644 --- a/htdocs/compta/stats/casoc.php +++ b/htdocs/compta/stats/casoc.php @@ -191,9 +191,9 @@ if ($modecompta == 'CREANCES-DETTES') { } $sql.= " WHERE f.fk_statut in (1,2)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { - $sql.= " AND f.type IN (0,1,2)"; + $sql.= " AND f.type IN (0,1,2,5)"; } else { - $sql.= " AND f.type IN (0,1,2,3)"; + $sql.= " AND f.type IN (0,1,2,3,5)"; } $sql.= " AND f.fk_soc = s.rowid"; if ($date_start && $date_end) { diff --git a/htdocs/compta/stats/index.php b/htdocs/compta/stats/index.php index cfd816c29b6b1ddd0dba75d8ddeda9e338471cf4..f704ca90f73ed400c1c9c9ded356219554e0caba 100644 --- a/htdocs/compta/stats/index.php +++ b/htdocs/compta/stats/index.php @@ -91,8 +91,8 @@ if ($modecompta == 'CREANCES-DETTES') $sql = "SELECT date_format(f.datef,'%Y-%m') as dm, sum(f.total) as amount, sum(f.total_ttc) as amount_ttc"; $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql.= " WHERE f.fk_statut in (1,2)"; - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; } else { diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 90ad3e196e3a627cf39c49b1eb9863b9291778c2..991601a4fbd3ba5c82a9d50a84a9bcaf0f026115 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -1,5 +1,7 @@ <?php -/* Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com> +/* Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -143,11 +145,12 @@ abstract class CommonInvoice extends CommonObject function getLibType() { global $langs; - if ($this->type == 0) return $langs->trans("InvoiceStandard"); - if ($this->type == 1) return $langs->trans("InvoiceReplacement"); - if ($this->type == 2) return $langs->trans("InvoiceAvoir"); - if ($this->type == 3) return $langs->trans("InvoiceDeposit"); - if ($this->type == 4) return $langs->trans("InvoiceProForma"); + if ($this->type == Facture::TYPE_STANDARD) return $langs->trans("InvoiceStandard"); + if ($this->type == Facture::TYPE_REPLACEMENT) return $langs->trans("InvoiceReplacement"); + if ($this->type == Facture::TYPE_CREDIT_NOTE) return $langs->trans("InvoiceAvoir"); + if ($this->type == Facture::TYPE_DEPOSIT) return $langs->trans("InvoiceDeposit"); + if ($this->type == Facture::TYPE_PROFORMA) return $langs->trans("InvoiceProForma"); + if ($this->type == Facture::TYPE_SITUATION) return $langs->trans("InvoiceSituation"); return $langs->trans("Unknown"); } diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 0dedb135298610778354952281ca7cdbed65d674..81a4946208a40a87bbed00c550c88c95905bbbcc 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -7,6 +7,7 @@ * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr> * Copyright (C) 2011-2014 Philippe Grand <philippe.grand@atoo-net.com> * Copyright (C) 2012-2014 Marcos García <marcosgdf@gmail.com> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -1740,6 +1741,19 @@ abstract class CommonObject // Add revenue stamp to total $this->total_ttc += isset($this->revenuestamp)?$this->revenuestamp:0; + // Situations totals + if ($this->situation_cycle_ref && $this->situation_counter > 1) { + $prev_sits = $this->get_prev_sits(); + + foreach ($prev_sits as $sit) { + $this->total_ht -= $sit->total_ht; + $this->total_tva -= $sit->total_tva; + $this->total_localtax1 -= $sit->total_localtax1; + $this->total_localtax2 -= $sit->total_localtax2; + $this->total_ttc -= $sit->total_ttc; + } + } + $this->db->free($resql); // Now update global field total_ht, total_ttc and tva @@ -2568,6 +2582,10 @@ abstract class CommonObject // Reduction short print '<td align="right" width="50"><label for="remise_percent">'.$langs->trans('ReductionShort').'</label></td>'; + if ($this->situation_cycle_ref) { + print '<td align="right" width="50"><label for="progress">' . $langs->trans('Progress') . '</label></td>'; + } + if (! empty($conf->margin->enabled) && empty($user->societe_id)) { if ($conf->global->MARGIN_TYPE == "1") diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 491e590403cb993b254bcbc736b61a22f4d7539a..9ce830ac513969804aa505ec5d1dc2f06b4b3792 100755 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -13,7 +13,8 @@ * Copyright (C) 2010-2014 Philippe Grand <philippe.grand@atoo-net.com> * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com> * Copyright (C) 2012-2014 Marcos García <marcosgdf@gmail.com> - * Copyright (C) 2013 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> + * Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2014 Alexandre Spangaro <alexandre.spangaro@gmail.com> * * This program is free software; you can redistribute it and/or modify @@ -2657,6 +2658,57 @@ class Form } } + /** + * Creates HTML last in cycle situation invoices selector + * + * @param string $selected Preselected ID + * @param int $socid Company ID + * + * @return string HTML select + */ + function load_situation_invoices($selected = '', $socid) + { + global $langs; + + $langs->load('bills'); + + $opt = '<option value ="" selected="selected"></option>'; + $sql = 'SELECT rowid, facnumber, situation_cycle_ref, situation_counter, situation_final, fk_soc FROM ' . MAIN_DB_PREFIX . 'facture WHERE situation_counter>=1'; + $sql .= ' order by situation_cycle_ref, situation_counter desc'; + $resql = $this->db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + // Last seen cycle + $ref = 0; + while ($res = $this->db->fetch_array($resql, MYSQL_NUM)) { + //Same company ? + if ($socid == $res[5]) { + //Same cycle ? + if ($res[2] != $ref) { + // Just seen this cycle + $ref = $res[2]; + //not final ? + if ($res[4] != 1) { + //Not prov? + if (substr($res[1], 1, 4) != 'PROV') { + if ($selected == $res[0]) { + $opt .= '<option value="' . $res[0] . '" selected="selected">' . $res[1] . '</option>'; + } else { + $opt .= '<option value="' . $res[0] . '">' . $res[1] . '</option>'; + } + } + } + } + } + } + } else { + dol_syslog("Error sql=" . $sql . ", error=" . $this->error, LOG_ERR); + } + if ($opt == '<option value ="" selected="selected"></option>') { + $opt = '<option value ="0" selected="selected">' . $langs->trans('NoSituations') . '</option>'; + } + return $opt; + } + /** * Return a HTML select list of bank accounts * diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 129d32fc7d9a691eebec697cb57910e252926692..4f1c8f71c5ae40fc1f2d1e8a98d6698f52a113a5 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -5,6 +5,8 @@ * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2014 Cedric GROSS <c.gross@kreiz-it.fr> * Copyright (C) 2014 Teddy Andreotti <125155@supinfo.com> * @@ -1448,6 +1450,31 @@ function pdf_getlineremisepercent($object,$i,$outputlangs,$hidedetails=0) } } +/** + * Return line percent + * + * @param Object $object Object + * @param int $i Current line number + * @param Translate $outputlangs Object langs for output + * @param int $hidedetails Hide details (0=no, 1=yes, 2=just special lines) + * @param HookManager $hookmanager Hook manager instance + * @return void + */ +function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = null) +{ + if ($object->lines[$i]->special_code != 3) { + if (is_object($hookmanager) && (($object->lines[$i]->product_type == 9 && !empty($object->lines[$i]->special_code)) || !empty($object->lines[$i]->fk_parent_line))) { + $special_code = $object->lines[$i]->special_code; + if (!empty($object->lines[$i]->fk_parent_line)) $special_code = $object->getSpecialCode($object->lines[$i]->fk_parent_line); + $parameters = array('i' => $i, 'outputlangs' => $outputlangs, 'hidedetails' => $hidedetails, 'special_code' => $special_code); + $action = ''; + return $hookmanager->executeHooks('pdf_getlineprogress', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + } else { + if (empty($hidedetails) || $hidedetails > 1) return $object->lines[$i]->situation_percent . '%'; + } + } +} + /** * Return line total excluding tax * diff --git a/htdocs/core/lib/price.lib.php b/htdocs/core/lib/price.lib.php index 00144db74e5adf0357281835ac5cfbae010207cf..aa3a1e11a46141757d91216e8496d2924402ade4 100644 --- a/htdocs/core/lib/price.lib.php +++ b/htdocs/core/lib/price.lib.php @@ -3,6 +3,8 @@ * Copyright (C) 2006-2008 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -47,6 +49,7 @@ * @param int $type 0/1=Product/service * @param Societe $seller Thirdparty seller (we need $seller->country_id property). Provided only if seller is the supplier, otherwise $seller will be $mysoc. * @param array $localtaxes_array Array with localtaxes info (loaded by getLocalTaxesFromRate function). + * @param float $progress Situation invoices progress * @return result[ 0=total_ht, * 1=total_vat, * 2=total_ttc, @@ -64,7 +67,7 @@ * 14=amount tax1 for total_ht_without_discount, * 15=amount tax2 for total_ht_without_discount] */ -function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller = '',$localtaxes_array='') +function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller = '', $localtaxes_array='', $progress=100) { global $conf,$mysoc,$db; @@ -128,7 +131,7 @@ function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocalt else dol_print_error($db); } // initialize total (may be HT or TTC depending on price_base_type) - $tot_sans_remise = $pu * $qty; + $tot_sans_remise = $pu * $qty * $progress / 100; $tot_avec_remise_ligne = $tot_sans_remise * (1 - ($remise_percent_ligne / 100)); $tot_avec_remise = $tot_avec_remise_ligne * (1 - ($remise_percent_global / 100)); diff --git a/htdocs/core/lib/tax.lib.php b/htdocs/core/lib/tax.lib.php index cc9478f5d6157fff7b8cecec4bba88503517f7de..1c048c7d6f592ec0e60e725fe65c591f7e2f7a53 100644 --- a/htdocs/core/lib/tax.lib.php +++ b/htdocs/core/lib/tax.lib.php @@ -3,6 +3,8 @@ * Copyright (C) 2006-2007 Yannick Warnier <ywarnier@beeznest.org> * Copyright (C) 2011 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -133,8 +135,8 @@ function vat_by_thirdparty($db, $y, $date_start, $date_end, $modetax, $direction $sql.= " ".MAIN_DB_PREFIX."societe as s"; $sql.= " WHERE f.entity = " . $conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // Validated or paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; if ($y && $m) { $sql.= " AND f.datef >= '".$db->idate(dol_get_first_day($y,$m,false))."'"; @@ -170,8 +172,8 @@ function vat_by_thirdparty($db, $y, $date_start, $date_end, $modetax, $direction $sql.= " FROM ".MAIN_DB_PREFIX.$invoicetable." as f, ".MAIN_DB_PREFIX.$invoicetable." as fd, ".MAIN_DB_PREFIX."societe as s"; $sql.= " WHERE "; $sql.= " f.fk_statut in (2)"; // Paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; if ($y && $m) { $sql.= " AND f.datef >= '".$db->idate(dol_get_first_day($y,$m,false))."'"; @@ -294,8 +296,8 @@ function vat_by_date($db, $y, $q, $date_start, $date_end, $modetax, $direction, $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on d.fk_product = p.rowid"; $sql.= " WHERE f.entity = " . $conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // Validated or paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND f.rowid = d.".$fk_facture; if ($y && $m) { @@ -339,8 +341,8 @@ function vat_by_date($db, $y, $q, $date_start, $date_end, $modetax, $direction, $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on d.fk_product = p.rowid"; $sql.= " WHERE f.entity = " . $conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // Validated or paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND f.rowid = d.".$fk_facture; if ($y && $m) { @@ -452,8 +454,8 @@ function vat_by_date($db, $y, $q, $date_start, $date_end, $modetax, $direction, $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on d.fk_product = p.rowid"; $sql.= " WHERE f.entity = " . $conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // Validated or paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND f.rowid = d.".$fk_facture; if ($y && $m) { @@ -500,8 +502,8 @@ function vat_by_date($db, $y, $q, $date_start, $date_end, $modetax, $direction, $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p on d.fk_product = p.rowid"; $sql.= " WHERE f.entity = " . $conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // Paid (partially or completely) - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2)"; - else $sql.= " AND f.type IN (0,1,2,3)"; + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; + else $sql.= " AND f.type IN (0,1,2,3,5)"; $sql.= " AND f.rowid = d.".$fk_facture;; $sql.= " AND pf.".$fk_facture2." = f.rowid"; $sql.= " AND pa.rowid = pf.".$fk_payment; diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index 6d1f5636b851ac0c6a9d9c88b6b3c463be3774df..06c3df85f4d04818cadaeaebc3b53014a2e11c12 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -4,6 +4,8 @@ * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr> * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -56,6 +58,16 @@ class pdf_crabe extends ModelePDFFactures var $emetteur; // Objet societe qui emet + /** + * @var bool Situation invoice type + */ + public $situationinvoice; + + /** + * @var float X position for the situation progress column + */ + public $posxprogress; + /** * Constructor @@ -107,6 +119,7 @@ class pdf_crabe extends ModelePDFFactures $this->posxup=126; $this->posxqty=145; $this->posxdiscount=162; + $this->posxprogress=174; // Only displayed for situation invoices $this->postotalht=174; if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) $this->posxtva=$this->posxup; $this->posxpicture=$this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images @@ -125,6 +138,7 @@ class pdf_crabe extends ModelePDFFactures $this->localtax2=array(); $this->atleastoneratenotnull=0; $this->atleastonediscount=0; + $this->situationinvoice=False; } @@ -278,6 +292,17 @@ class pdf_crabe extends ModelePDFFactures //$this->postotalht; } + // Situation invoice handling + if ($object->situation_cycle_ref) { + $this->situationinvoice = True; + $progress_width = 14; + $this->posxtva -= $progress_width; + $this->posxup -= $progress_width; + $this->posxqty -= $progress_width; + $this->posxdiscount -= $progress_width; + $this->posxprogress -= $progress_width; + } + // New page $pdf->AddPage(); if (! empty($tplidx)) $pdf->useTemplate($tplidx); @@ -444,16 +469,27 @@ class pdf_crabe extends ModelePDFFactures { $pdf->SetXY($this->posxdiscount-2, $curY); $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails); - $pdf->MultiCell($this->postotalht-$this->posxdiscount+2, 3, $remise_percent, 0, 'R'); + $pdf->MultiCell($this->posxprogress-$this->posxdiscount+2, 3, $remise_percent, 0, 'R'); } + // Situation progress + $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxprogress, $curY); + $pdf->MultiCell($this->postotalht-$this->posxprogress, 3, $progress, 0, 'R'); // Enough for 6 chars + // Total HT line $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); $pdf->SetXY($this->postotalht, $curY); $pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalht, 3, $total_excl_tax, 0, 'R', 0); // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva - $tvaligne=$object->lines[$i]->total_tva; + $prev_progress = $object->lines[$i]->get_prev_progress(); + if ($prev_progress > 0) // Compute progress from previous situation + { + $tvaligne = $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + } else { + $tvaligne = $object->lines[$i]->total_tva; + } $localtax1ligne=$object->lines[$i]->total_localtax1; $localtax2ligne=$object->lines[$i]->total_localtax2; $localtax1_rate=$object->lines[$i]->localtax1_tx; @@ -912,7 +948,7 @@ class pdf_crabe extends ModelePDFFactures $pdf->SetFont('','', $default_font_size - 1); // Tableau total - $col1x = 120; $col2x = 170; + $col1x = 120; $col2x = $this->postotalht; if ($this->page_largeur < 210) // To work with US executive format { $col2x-=20; @@ -922,11 +958,44 @@ class pdf_crabe extends ModelePDFFactures $useborder=0; $index = 0; + // Previous situations summary + if ($object->situation_cycle_ref && $object->situation_counter > 1) { + // Situations total w/out VAT + $counter = ' 1'; + for ($i = 2; $i <= $object->situation_counter; $i++) { + $counter .= ' + ' . $i; + } + + $prevsits = $object->get_prev_sits(); + $prevsits_total_amount = 0; + foreach ($prevsits as $situation) { + $prevsits_total_amount += $situation->total_ht; + } + $prevsits_total_amount += $object->total_ht; + + $pdf->SetFillColor(255, 255, 255); + $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("SituationAmount") . $counter, 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($prevsits_total_amount), 0, 'R', 1); + + // Previous situations deduction + $pdf->Line($col2x, 0, $col2x, 100000); + for ($i = 0; $i < count($prevsits); $i++) { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x - $col1x, $tab2_hl, $outputlangs->transnoentities("SituationDeduction") . ' ' . ($i + 1) . ' (' . $prevsits[$i]->ref . ')', 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, ' - ' . price($prevsits[$i]->total_ht), 0, 'R', 1); + } + $index++; + } + // Total HT $pdf->SetFillColor(255,255,255); - $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); - $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); $pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($object->total_ht + (! empty($object->remise)?$object->remise:0)), 0, $outputlangs), 0, 'R', 1); // Show VAT by rates and total @@ -1265,19 +1334,21 @@ class pdf_crabe extends ModelePDFFactures $pdf->SetXY($this->posxqty-1, $tab_top+1); $pdf->MultiCell($this->posxdiscount-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); } - $pdf->line($this->posxdiscount-1, $tab_top, $this->posxdiscount-1, $tab_top + $tab_height); - if (empty($hidetop)) - { - if ($this->atleastonediscount) - { - $pdf->SetXY($this->posxdiscount-1, $tab_top+1); - $pdf->MultiCell($this->postotalht-$this->posxdiscount+1,2, $outputlangs->transnoentities("ReductionShort"),'','C'); + if ($this->atleastonediscount) { + $pdf->line($this->posxprogress, $tab_top, $this->posxprogress, $tab_top + $tab_height); + if (empty($hidetop)) { + $pdf->SetXY($this->posxdiscount - 1, $tab_top + 1); + $pdf->MultiCell($this->posxprogress - $this->posxdiscount + 1, 2, $outputlangs->transnoentities("ReductionShort"), '', 'C'); } } - if ($this->atleastonediscount) - { + + if ($this->situationinvoice) { $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height); + if (empty($hidetop)) { + $pdf->SetXY($this->posxprogress - 1, $tab_top + 1); + $pdf->MultiCell($this->postotalht - $this->posxprogress - 1, 2, $outputlangs->transnoentities("Progress"), '', 'C'); + } } if (empty($hidetop)) { @@ -1353,6 +1424,8 @@ class pdf_crabe extends ModelePDFFactures if ($object->type == 2) $title=$outputlangs->transnoentities("InvoiceAvoir"); if ($object->type == 3) $title=$outputlangs->transnoentities("InvoiceDeposit"); if ($object->type == 4) $title=$outputlangs->transnoentities("InvoiceProFormat"); + if ($object->type == 5 && $object->situation_final == 0) $title = $outputlangs->transnoentities("InvoiceSituation").' n°'.$object->situation_counter; + if ($object->type == 5 && $object->situation_final == 1) $title = 'Situation n°'.$object->situation_counter.' : '.$outputlangs->transnoentities("InvoiceSituationLast"); $pdf->MultiCell(100, 3, $title, '', 'R'); $pdf->SetFont('','B',$default_font_size); diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 6037f6c77c92610467ac39f3d19505ffed94d798..d90526aba067e8e47f4ce690503cd5f3b25ff158 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -2,7 +2,9 @@ /* Copyright (C) 2010-2012 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2010-2014 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> + * Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * * 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 @@ -58,6 +60,9 @@ if (in_array($object->element,array('propal','facture','invoice','commande','ord <td align="right"><?php echo $langs->trans('Qty'); ?></td> <td align="right"><?php echo $langs->trans('ReductionShort'); ?></td> <?php + if ($this->situation_cycle_ref) { + print '<td align="right">' . $langs->trans('Progress') . '</td>'; + } if (! empty($usemargins)) { ?> @@ -214,8 +219,11 @@ else { <td align="right"><input type="text" size="2" name="qty" id="qty" class="flat" value="<?php echo (isset($_POST["qty"])?$_POST["qty"]:1); ?>"> </td> <td align="right" class="nowrap"><input type="text" size="1" name="remise_percent" id="remise_percent" class="flat" value="<?php echo (isset($_POST["remise_percent"])?$_POST["remise_percent"]:$buyer->remise_percent); ?>"><span class="hideonsmartphone">%</span></td> - <?php + if ($this->situation_cycle_ref) { + $coldisplay++; + print '<td align="right" class="nowrap"><input type="text" size="1" value="0" name="progress">%</td>'; + } if (! empty($usemargins)) { ?> @@ -277,6 +285,7 @@ if (! empty($conf->service->enabled) && $dateSelector && GETPOST('type') != '0') { if(! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) $colspan = 10; else $colspan = 9; + if($this->situation_cycle_ref) $colspan++; if (! empty($inputalsopricewithtax)) $colspan++; // We add 1 if col total ttc if (in_array($object->element,array('propal','facture','invoice','commande','order'))) $colspan++; // With this, there is a column move button diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index fbe2870a6a4adbfc90f7bd55abb488a0d79e8d6e..fd2e3e0d469059dd627ac6f596045f8e1dc2a9a5 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -2,6 +2,8 @@ /* Copyright (C) 2010-2012 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2010-2012 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> * * This program is free software; you can redistribute it and/or modify @@ -83,22 +85,44 @@ $coldisplay=-1; // We remove first td $reshook=$hookmanager->executeHooks('formEditProductOptions',$parameters,$this,$action); } - // editeur wysiwyg - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $nbrows=ROWS_2; - if (! empty($conf->global->MAIN_INPUT_DESC_HEIGHT)) $nbrows=$conf->global->MAIN_INPUT_DESC_HEIGHT; - $enable=(isset($conf->global->FCKEDITOR_ENABLE_DETAILS)?$conf->global->FCKEDITOR_ENABLE_DETAILS:0); - $doleditor=new DolEditor('product_desc',$line->description,'',164,'dolibarr_details','',false,true,$enable,$nbrows,'98%'); - $doleditor->Create(); + // Do not allow editing during a situation cycle + if ($this->situation_counter == 1 || !$this->situation_cycle_ref) { + // editeur wysiwyg + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $nbrows=ROWS_2; + if (! empty($conf->global->MAIN_INPUT_DESC_HEIGHT)) $nbrows=$conf->global->MAIN_INPUT_DESC_HEIGHT; + $enable=(isset($conf->global->FCKEDITOR_ENABLE_DETAILS)?$conf->global->FCKEDITOR_ENABLE_DETAILS:0); + $doleditor=new DolEditor('product_desc',$line->description,'',164,'dolibarr_details','',false,true,$enable,$nbrows,'98%'); + $doleditor->Create(); + } else { + print '<textarea id="desc" class="flat" name="desc" readonly="readonly" style="width: 200px; height:80px;">' . $line->description . '</textarea>'; + } ?> </td> - <td align="right"><?php $coldisplay++; ?><?php echo $form->load_tva('tva_tx',$line->tva_tx,$seller,$buyer,0,$line->info_bits,$line->product_type); ?></td> + <?php + $coldisplay++; + if ($this->situation_counter == 1 || !$this->situation_cycle_ref) { + print '<td align="right">' . $form->load_tva('tva_tx',$line->tva_tx,$seller,$buyer,0,$line->info_bits,$line->product_type) . '</td>'; + } else { + print '<td align="right"><input size="1" type="text" class="flat" name="tva_tx" value="' . price($line->tva_tx) . '" readonly="readonly" />%</td>'; + } - <td align="right"><?php $coldisplay++; ?><input type="text" class="flat" size="8" id="price_ht" name="price_ht" value="<?php echo price($line->subprice,0,'',0); ?>"></td> - <?php if ($inputalsopricewithtax) { ?> - <td align="right"><?php $coldisplay++; ?><input type="text" class="flat" size="8" id="price_ttc" name="price_ttc" value="<?php echo price($pu_ttc,0,'',0); ?>"></td> - <?php } ?> + $coldisplay++; + print '<td align="right"><input type="text" class="flat" size="8" id="price_ht" name="price_ht" value="' . price($line->subprice,0,'',0) . '" '; + if ($this->situation_counter > 1) { + print 'readonly="readonly" '; + } + print '></td>'; + + if ($inputalsopricewithtax) { + $coldisplay++; + print '<td align="right"><input type="text" class="flat" size="8" id="price_ttc" name="price_ttc" value="' . price($pu_ttc,0,'',0) . '"'; + if ($this->situation_counter > 1) { + print 'readonly="readonly" '; + } + print '></td>'; + } ?> <td align="right"><?php $coldisplay++; ?> <?php if (($line->info_bits & 2) != 2) { @@ -106,22 +130,32 @@ $coldisplay=-1; // We remove first td // for example always visible on invoice but must be visible only if stock module on and stock decrease option is on invoice validation and status is not validated // must also not be output for most entities (proposal, intervention, ...) //if($line->qty > $line->stock) print img_picto($langs->trans("StockTooLow"),"warning", 'style="vertical-align: bottom;"')." "; - ?> - <input size="3" type="text" class="flat" name="qty" id="qty" value="<?php echo $line->qty; ?>"> - <?php } else { ?> + print '<input size="3" type="text" class="flat" name="qty" id="qty" value="' . $line->qty . '" '; + if ($this->situation_counter > 1) { + print 'readonly="readonly" '; + } + print '/>'; + } else { ?> <?php } ?> </td> <td align="right" nowrap><?php $coldisplay++; ?> - <?php if (($line->info_bits & 2) != 2) { ?> - <input size="1" type="text" class="flat" name="remise_percent" id="remise_percent" value="<?php echo $line->remise_percent; ?>">% - <?php } else { ?> + <?php if (($line->info_bits & 2) != 2) { + print '<input size="1" type="text" class="flat" name="remise_percent" id="remise_percent" value="' . $line->remise_percent . '" '; + if ($this->situation_counter > 1) { + print 'readonly="readonly" '; + } + print '/>%'; + } else { ?> <?php } ?> </td> - <?php + if ($this->situation_cycle_ref) { + $coldisplay++; + print '<td align="right" nowrap><input type="text" size="1" value="' . $line->situation_percent . '" name="progress">%</td>'; + } if (! empty($usemargins)) { ?> diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index 3d2ea127b8506947c2c17f31e53b8a88b2bcbc12..2e1cc0f3678e95a33f7558cf0db4832201ce748a 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -2,6 +2,8 @@ /* Copyright (C) 2010-2013 Regis Houssin <regis.houssin@capnetworks.com> * Copyright (C) 2010-2011 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> + * Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> * * This program is free software; you can redistribute it and/or modify @@ -138,6 +140,11 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0; <td><?php $coldisplay++; ?> </td> <?php } + if ($this->situation_cycle_ref) { + $coldisplay++; + print '<td align="right" nowrap="nowrap">' . $line->situation_percent . '%</td>'; + } + if (! empty($conf->margin->enabled) && empty($user->societe_id)) { $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT,$conf->global->MAIN_MAX_DECIMALS_TOT); ?> @@ -167,12 +174,16 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0; </td> <td align="center"><?php $coldisplay++; ?> - <a href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&action=ask_deleteline&lineid='.$line->id; ?>"> - <?php echo img_delete(); ?> - </a> + <?php + if ($this->situation_counter == 1 || !$this->situation_cycle_ref) { + print '<a href="' . $_SERVER["PHP_SELF"] . '?id=' . $this->id . '&action=ask_deleteline&lineid=' . $line->id . '">'; + print img_delete(); + print '</a>'; + } + ?> </td> - <?php if ($num > 1 && empty($conf->browser->phone)) { ?> + <?php if ($num > 1 && empty($conf->browser->phone) && ($this->situation_counter == 1 || !$this->situation_cycle_ref)) { ?> <td align="center" class="tdlineupdown"><?php $coldisplay++; ?> <?php if ($i > 0) { ?> <a class="lineupdown" href="<?php echo $_SERVER["PHP_SELF"].'?id='.$this->id.'&action=up&rowid='.$line->id; ?>"> diff --git a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql index 755195c2a61a5bd8112539abc57d934c12903a2b..02265ff86c87a341a34b4e49f5a315647177d9f0 100755 --- a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql +++ b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql @@ -30,3 +30,10 @@ ALTER TABLE llx_product_fournisseur_price ADD fk_price_expression integer DEFAUL -- Taiwan VAT Rates insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 2131, 213, '5', '0', 'VAT 5%', 1); + +-- Add situation invoices +ALTER TABLE llx_facture ADD situation_cycle_ref smallint UNSIGNED; +ALTER TABLE llx_facture ADD situation_counter tinyint UNSIGNED; +ALTER TABLE llx_facture ADD situation_final boolean; +ALTER TABLE llx_facturedet ADD situation_percent real; +ALTER TABLE llx_facturedet ADD fk_prev_id integer; diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql index 9757f749cd0a51764601d7f03352bf04bf18b519..144cd349dd6c8548169631f1d36c100e8df272b3 100644 --- a/htdocs/install/mysql/tables/llx_facture.sql +++ b/htdocs/install/mysql/tables/llx_facture.sql @@ -3,6 +3,8 @@ -- Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net> -- Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> -- Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es> +-- Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> +-- Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> -- -- 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 @@ -74,6 +76,10 @@ create table llx_facture note_public text, model_pdf varchar(255), import_key varchar(14), - extraparams varchar(255) -- for stock other parameters with json format + extraparams varchar(255), -- for stock other parameters with json format + + situation_cycle_ref smallint UNSIGNED, -- situation cycle reference + situation_counter tinyint UNSIGNED, -- situation counter + situation_final boolean -- is the situation final ? )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facturedet.sql b/htdocs/install/mysql/tables/llx_facturedet.sql index 6a328d4688edeb67d31cf55fc52b4422f4e2e082..2c01234f4b943eb394f22d47a882552a4b53e99b 100644 --- a/htdocs/install/mysql/tables/llx_facturedet.sql +++ b/htdocs/install/mysql/tables/llx_facturedet.sql @@ -3,6 +3,8 @@ -- Copyright (C) 2004-2005 Laurent Destailleur <eldy@users.sourceforge.net> -- Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> -- Copyright (C) 2010 Juanjo Menent <jmenent@2byte.es> +-- Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr> +-- Copyright (C) 2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr> -- -- 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 @@ -55,8 +57,11 @@ create table llx_facturedet fk_code_ventilation integer DEFAULT 0 NOT NULL, special_code integer UNSIGNED DEFAULT 0, -- code pour les lignes speciales rang integer DEFAULT 0, -- ordre d'affichage - import_key varchar(14) - + import_key varchar(14), + + situation_percent real, -- % progression of lines invoicing + fk_prev_id integer -- id of the line in the previous situation + )ENGINE=innodb; -- diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 12778d6b9ead0d185e4ce96fb9564459b5253f25..ccf994aff95c946fa2033cb020ea8f97139e1492 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -389,7 +389,7 @@ DisabledBecausePayments=Not possible since there are some payments CantRemovePaymentWithOneInvoicePaid=Can't remove payment since there is at least one invoice classified paid ExpectedToPay=Expected payment PayedByThisPayment=Paid by this payment -ClosePaidInvoicesAutomatically=Classify "Paid" all standard or replacement invoices entirely paid. +ClosePaidInvoicesAutomatically=Classify "Paid" all standard, situation or replacement invoices entirely paid. ClosePaidCreditNotesAutomatically=Classify "Paid" all credit notes entirely paid back. AllCompletelyPayedInvoiceWillBeClosed=All invoice with no remain to pay will be automatically closed to status "Paid". ToMakePayment=Pay @@ -411,3 +411,20 @@ TypeContact_invoice_supplier_internal_SALESREPFOLL=Representative following-up s TypeContact_invoice_supplier_external_BILLING=Supplier invoice contact TypeContact_invoice_supplier_external_SHIPPING=Supplier shipping contact TypeContact_invoice_supplier_external_SERVICE=Supplier service contact +# Situation invoices +InvoiceFirstSituationAsk=First situation invoice +InvoiceFirstSituationDesc=The <b>situation invoices</b> are tied to situations related to a progression, for example the progression of a construction. Each situation is tied to an invoice. +InvoiceSituation=Situation invoice +InvoiceSituationAsk=Invoice following the situation +InvoiceSituationDesc=Create a new situation following an already existing one +SituationAmount=Situation invoice amount(net) +SituationDeduction=Situation subtraction +Progress=Progress +ModifyAllLines=Modify all lines +CreateNextSituationInvoice=Create next situation +NotLastInCycle=This invoice in not the last in cycle and must not be modified. +DisabledBecauseNotLastInCycle=The next situation already exists. +DisabledBecauseFinal=This situation is final. +CantBeLessThanMinPercent=The progress can't be smaller than its value in the previous situation. +NoSituations=No opened situations +InvoiceSituationLast=Final and general invoice diff --git a/htdocs/langs/fr_FR/bills.lang b/htdocs/langs/fr_FR/bills.lang index 24ebe5ff923f79cef4d13cc59d80f0087b5a39a1..22c80d41300dcb9143fb1e1b2997ed1032f4e2c5 100644 --- a/htdocs/langs/fr_FR/bills.lang +++ b/htdocs/langs/fr_FR/bills.lang @@ -410,3 +410,21 @@ TypeContact_invoice_supplier_internal_SALESREPFOLL=Responsable suivi facture fou TypeContact_invoice_supplier_external_BILLING=Contact fournisseur facturation TypeContact_invoice_supplier_external_SHIPPING=Contact fournisseur livraison TypeContact_invoice_supplier_external_SERVICE=Contact fournisseur prestation +# Factures de situation +InvoiceFirstSituationAsk=Facture de première situation +InvoiceFirstSituationDesc=Les <b>factures de situation</b> correspondent aux situations liées à un avancement, par exemple l'avancement des travaux dans le cadre d’un chantier (BTP). Chaque situation correspond à une facture. +InvoiceFirstSituation=Facture de première situation +InvoiceSituationAsk=Facture suivant la situation +InvoiceSituationDesc=Création d'une nouvelle situation qui fera suite à une situation déjà ouverte. +InvoiceSituation=Facture de situation +SituationAmount=Montant HT situation +SituationDeduction=Déduction situation +Progress=Avanct. +ModifyAllLines=Modifier toutes les lignes +CreateNextSituationInvoice=Créer situation suivante +NotLastInCycle=Cette facture n'est pas la dernière du cycle, il ne faut pas la modifier. +DisabledBecauseNotLastInCycle=La situation suivante existe déjà. +DisabledBecauseFinal=Cette situation est finale. +CantBeLessThanMinPercent=L'avancement d'une ligne ne peut pas être inférieur à sa valeur à la situation précédente. +NoSituations=Pas de situations en cours +InvoiceSituationLast=Décompte général et définitif