From 732fb2fa048e0413360d6026faafb09e930cf5f1 Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Wed, 18 Oct 2023 03:33:14 +0300 Subject: [PATCH] NEW: Invoice subtypes for customers and vendors (#26233) * NEW: Invoice subtypes for customers and vendors * fix PHPCS * fix PHPCS * fix PHPCS * fix PHPCS * fix possible SQL Injection * remove hardcoded tests * remove hardcoded tests * fix travis ci error --- htdocs/compta/facture/card.php | 175 ++++++++++-------- htdocs/compta/facture/class/facture.class.php | 24 ++- htdocs/compta/facture/list.php | 34 +++- htdocs/core/class/commoninvoice.class.php | 79 ++++++++ htdocs/core/class/html.form.class.php | 95 ++++++++++ .../fourn/class/fournisseur.facture.class.php | 80 ++++---- htdocs/fourn/facture/card.php | 73 +++++--- htdocs/fourn/facture/list.php | 39 +++- htdocs/langs/en_US/admin.lang | 1 + htdocs/langs/en_US/bills.lang | 1 + htdocs/langs/en_US/main.lang | 2 + 11 files changed, 455 insertions(+), 148 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 91864f3e363..da0730be401 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -16,6 +16,7 @@ * Copyright (C) 2015-2016 Marcos García * Copyright (C) 2018-2023 Frédéric France * Copyright (C) 2022 Gauthier VERDOL + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -43,7 +44,6 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; - require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; @@ -87,7 +87,6 @@ $action = GETPOST('action', 'aZ09'); $confirm = GETPOST('confirm', 'alpha'); $cancel = GETPOST('cancel', 'alpha'); $backtopage = GETPOST('backtopage', 'alpha'); - $lineid = GETPOST('lineid', 'int'); $userid = GETPOST('userid', 'int'); $search_ref = GETPOST('sf_ref', 'alpha') ? GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha'); @@ -320,9 +319,9 @@ if (empty($reshook)) { } } - // On verifie signe facture + // We check invoice sign if ($object->type == Facture::TYPE_CREDIT_NOTE) { - // Si avoir, le signe doit etre negatif + // If a credit note, the sign must be negative if ($object->total_ht >= 0) { setEventMessages($langs->trans("ErrorInvoiceAvoirMustBeNegative"), null, 'errors'); $action = ''; @@ -743,10 +742,10 @@ if (empty($reshook)) { $resteapayer = $object->total_ttc - $totalpaid; - // We check that invlice lines are transferred into accountancy + // We check that invoice lines are transferred into accountancy $ventilExportCompta = $object->getVentilExportCompta(); - // On verifie si aucun paiement n'a ete effectue + // We check if no payment has been made if ($ventilExportCompta == 0) { if (!empty($conf->global->INVOICE_CAN_BE_EDITED_EVEN_IF_PAYMENT_DONE) || ($resteapayer == $object->total_ttc && empty($object->paye))) { $result = $object->setDraft($user, $idwarehouse); @@ -811,7 +810,7 @@ if (empty($reshook)) { setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Reason")), null, 'errors'); } } elseif ($action == 'confirm_converttoreduc' && $confirm == 'yes' && $usercancreate) { - // Convertir en reduc + // Convert to reduce $object->fetch($id); $object->fetch_thirdparty(); //$object->fetch_lines(); // Already done into fetch @@ -1036,27 +1035,27 @@ if (empty($reshook)) { $result = $object->fetch(GETPOST('fac_replacement', 'int')); $object->fetch_thirdparty(); - $object->date = $dateinvoice; - $object->date_pointoftax = $date_pointoftax; + $object->date = $dateinvoice; + $object->date_pointoftax = $date_pointoftax; $object->note_public = trim(GETPOST('note_public', 'restricthtml')); $object->note_private = trim(GETPOST('note_private', 'restricthtml')); $object->ref_client = GETPOST('ref_client', 'alphanohtml'); $object->ref_customer = GETPOST('ref_client', 'alphanohtml'); - $object->model_pdf = GETPOST('model', 'alphanohtml'); + $object->model_pdf = GETPOST('model', 'alphanohtml'); $object->fk_project = GETPOST('projectid', 'int'); $object->cond_reglement_id = GETPOST('cond_reglement_id', 'int'); $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int'); - $object->fk_account = GETPOST('fk_account', 'int'); + $object->fk_account = GETPOST('fk_account', 'int'); $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU', 2); $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); - $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); - // Proprietes particulieres a facture de remplacement + // Special properties of replacement invoice $object->fk_facture_source = GETPOST('fac_replacement', 'int'); - $object->type = Facture::TYPE_REPLACEMENT; + $object->type = Facture::TYPE_REPLACEMENT; $id = $object->createFromCurrent($user); if ($id <= 0) { @@ -1084,31 +1083,38 @@ if (empty($reshook)) { $action = 'create'; } + if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors'); + $action = 'create'; + } + if (!$error) { if (!empty($originentity)) { $object->entity = $originentity; } - $object->socid = GETPOST('socid', 'int'); - $object->ref = GETPOST('ref'); - $object->date = $dateinvoice; - $object->date_pointoftax = $date_pointoftax; + $object->socid = GETPOST('socid', 'int'); + $object->subtype = GETPOST('subtype'); + $object->ref = GETPOST('ref'); + $object->date = $dateinvoice; + $object->date_pointoftax = $date_pointoftax; $object->note_public = trim(GETPOST('note_public', 'restricthtml')); $object->note_private = trim(GETPOST('note_private', 'restricthtml')); $object->ref_client = GETPOST('ref_client', 'alphanohtml'); $object->ref_customer = GETPOST('ref_client', 'alphanohtml'); - $object->model_pdf = GETPOST('model'); + $object->model_pdf = GETPOST('model'); $object->fk_project = GETPOST('projectid', 'int'); $object->cond_reglement_id = 0; // No payment term for a credit note $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int'); - $object->fk_account = GETPOST('fk_account', 'int'); + $object->fk_account = GETPOST('fk_account', 'int'); $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU'); $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); - $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); - // Proprietes particulieres a facture avoir + // Special properties of replacement invoice $object->fk_facture_source = $sourceinvoice > 0 ? $sourceinvoice : ''; $object->type = Facture::TYPE_CREDIT_NOTE; @@ -1301,25 +1307,33 @@ if (empty($reshook)) { $action = 'create'; } + + if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors'); + $action = 'create'; + } + if (!$error) { - $object->socid = GETPOST('socid', 'int'); - $object->type = GETPOST('type'); - $object->ref = GETPOST('ref'); - $object->date = $dateinvoice; - $object->date_pointoftax = $date_pointoftax; - $object->note_public = trim(GETPOST('note_public', 'restricthtml')); - $object->note_private = trim(GETPOST('note_private', 'restricthtml')); - $object->ref_customer = GETPOST('ref_client'); - $object->ref_client = $object->ref_customer; - $object->model_pdf = GETPOST('model'); - $object->fk_project = GETPOST('projectid', 'int'); + $object->socid = GETPOST('socid', 'int'); + $object->type = GETPOST('type'); + $object->subtype = GETPOST('subtype'); + $object->ref = GETPOST('ref'); + $object->date = $dateinvoice; + $object->date_pointoftax = $date_pointoftax; + $object->note_public = trim(GETPOST('note_public', 'restricthtml')); + $object->note_private = trim(GETPOST('note_private', 'restricthtml')); + $object->ref_customer = GETPOST('ref_client'); + $object->ref_client = $object->ref_customer; + $object->model_pdf = GETPOST('model'); + $object->fk_project = GETPOST('projectid', 'int'); $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id')); $object->mode_reglement_id = GETPOST('mode_reglement_id', 'int'); - $object->fk_account = GETPOST('fk_account', 'int'); - $object->amount = price2num(GETPOST('amount')); + $object->fk_account = GETPOST('fk_account', 'int'); + $object->amount = price2num(GETPOST('amount')); $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU'); $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); - $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); @@ -1380,26 +1394,33 @@ if (empty($reshook)) { } } + + if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) { + $error++; + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors'); + $action = 'create'; + } + if (!$error) { - // Si facture standard - $object->socid = GETPOST('socid', 'int'); + $object->socid = GETPOST('socid', 'int'); $object->type = GETPOST('type'); - $object->ref = GETPOST('ref'); + $object->subtype = GETPOST('subtype'); + $object->ref = GETPOST('ref'); $object->date = $dateinvoice; - $object->date_pointoftax = $date_pointoftax; + $object->date_pointoftax = $date_pointoftax; $object->note_public = trim(GETPOST('note_public', 'restricthtml')); - $object->note_private = trim(GETPOST('note_private', 'restricthtml')); + $object->note_private = trim(GETPOST('note_private', 'restricthtml')); $object->ref_client = GETPOST('ref_client'); $object->ref_customer = GETPOST('ref_client'); - $object->model_pdf = GETPOST('model'); + $object->model_pdf = GETPOST('model'); $object->fk_project = GETPOST('projectid', 'int'); $object->cond_reglement_id = (GETPOST('type') == 3 ? 1 : GETPOST('cond_reglement_id')); $object->mode_reglement_id = GETPOST('mode_reglement_id'); - $object->fk_account = GETPOST('fk_account', 'int'); - $object->amount = price2num(GETPOST('amount')); + $object->fk_account = GETPOST('fk_account', 'int'); + $object->amount = price2num(GETPOST('amount')); $object->remise_absolue = price2num(GETPOST('remise_absolue'), 'MU'); $object->remise_percent = price2num(GETPOST('remise_percent'), '', 2); - $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); $object->multicurrency_code = GETPOST('multicurrency_code', 'alpha'); $object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int'); @@ -1917,7 +1938,7 @@ if (empty($reshook)) { $line->multicurrency_total_tva = $tabprice[17]; $line->multicurrency_total_ttc = $tabprice[18]; - // Si fk_remise_except defini on vérifie si la réduction à déjà été appliquée + // If fk_remise_except defined we check if the reduction has already been applied if ($line->fk_remise_except) { $discount = new DiscountAbsolute($line->db); $result = $discount->fetch($line->fk_remise_except); @@ -1947,7 +1968,7 @@ if (empty($reshook)) { $object->fk_account = GETPOST('fk_account', 'int'); - // Proprietes particulieres a facture de remplacement + // Special properties of replacement invoice $object->situation_counter = $object->situation_counter + 1; $id = $object->createFromCurrent($user); @@ -2154,10 +2175,10 @@ if (empty($reshook)) { $special_code = 0; // if (!GETPOST(qty)) $special_code=3; // Options should not exists on invoices - // Ecrase $pu par celui du produit - // Ecrase $desc par celui du produit - // Ecrase $base_price_type par celui du produit - // Replaces $fk_unit with the product's + // Replaces $pu with that of the product + // Replaces $desc with that of the product + // Replaces $base_price_type with that of the product + // Replaces $fk_unit with that of the product if (!empty($idprod) && $idprod > 0) { $prod = new Product($db); $prod->fetch($idprod); @@ -2405,7 +2426,6 @@ if (empty($reshook)) { } unset($_POST['prod_entry_mode']); - unset($_POST['qty']); unset($_POST['type']); unset($_POST['remise_percent']); @@ -2423,7 +2443,6 @@ if (empty($reshook)) { unset($_POST['dp_desc']); unset($_POST['idprod']); unset($_POST['units']); - unset($_POST['date_starthour']); unset($_POST['date_startmin']); unset($_POST['date_startsec']); @@ -2436,7 +2455,6 @@ if (empty($reshook)) { unset($_POST['date_endday']); unset($_POST['date_endmonth']); unset($_POST['date_endyear']); - unset($_POST['situations']); unset($_POST['progress']); } else { @@ -2700,11 +2718,9 @@ if (empty($reshook)) { unset($_POST['buying_price']); unset($_POST['np_marginRate']); unset($_POST['np_markRate']); - unset($_POST['dp_desc']); unset($_POST['idprod']); unset($_POST['units']); - unset($_POST['date_starthour']); unset($_POST['date_startmin']); unset($_POST['date_startsec']); @@ -2717,7 +2733,6 @@ if (empty($reshook)) { unset($_POST['date_endday']); unset($_POST['date_endmonth']); unset($_POST['date_endyear']); - unset($_POST['situations']); unset($_POST['progress']); } else { @@ -2986,14 +3001,14 @@ if (empty($reshook)) { } } } elseif ($action == 'swapstatut') { - // bascule du statut d'un contact + // toggle the status of a contact if ($object->fetch($id)) { $result = $object->swapContactStatus(GETPOST('ligne', 'int')); } else { dol_print_error($db); } } elseif ($action == 'deletecontact') { - // Efface un contact + // Delete a contact $object->fetch($id); $result = $object->delete_contact($lineid); @@ -3420,12 +3435,12 @@ if ($action == 'create') { jQuery("#typedeposit").change(function() { console.log("We change type of down payment"); jQuery("#radio_deposit").prop("checked", true); - setRadioForTypeOfIncoice(); + setRadioForTypeOfInvoice(); }); jQuery("#radio_standard, #radio_deposit, #radio_replacement, #radio_creditnote, #radio_template").change(function() { - setRadioForTypeOfIncoice(); + setRadioForTypeOfInvoice(); }); - function setRadioForTypeOfIncoice() { + function setRadioForTypeOfInvoice() { console.log("Change radio"); if (jQuery("#radio_deposit").prop("checked") && (jQuery("#typedeposit").val() == \'amount\' || jQuery("#typedeposit").val() == \'variable\')) { jQuery(".checkforselect").prop("disabled", true); @@ -3721,6 +3736,13 @@ if ($action == 'create') { print ''; + // Invoice Subtype + if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) { + print ''.$langs->trans('InvoiceSubtype').''; + print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, ''); + print ''; + } + if ($socid > 0) { // Discounts for third party print ''.$langs->trans('DiscountStillRemaining').''; @@ -4121,7 +4143,7 @@ if ($action == 'create') { $formconfirm = ''; - // Confirmation de la conversion de l'avoir en reduc + // Confirmation of the conversion of the credit into a reduction if ($action == 'converttoreduc') { if ($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_SITUATION) { $type_fac = 'ExcessReceived'; @@ -4305,7 +4327,7 @@ if ($action == 'create') { $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('UnvalidateBill'), $text, 'confirm_modif', $formquestion, "yes", 1); } - // Confirmation du classement paye + // Confirmation of payment classification if ($action == 'paid' && ($resteapayer <= 0 || (!empty($conf->global->INVOICE_CAN_SET_PAID_EVEN_IF_PARTIALLY_PAID) && $resteapayer == $object->total_ttc))) { $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidBill', $object->ref), 'confirm_paid', '', "yes", 1); } @@ -4352,16 +4374,16 @@ if ($action == 'create') { $arrayreasons[$close[$key]['code']] = $close[$key]['reason']; } - // Cree un tableau formulaire + // Create a form table $formquestion = array('text' => $langs->trans("ConfirmClassifyPaidPartiallyQuestion"), array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'morecss' => 'minwidth300')); - // Paiement incomplet. On demande si motif = escompte ou autre + // Incomplete payment. We ask if reason = discount or other $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?facid='.$object->id, $langs->trans('ClassifyPaid'), $langs->trans('ConfirmClassifyPaidPartially', $object->ref), 'confirm_paid_partially', $formquestion, "yes", 1, 380, 600); } - // Confirmation du classement abandonne + // Confirmation of status abandoned if ($action == 'canceled') { - // S'il y a une facture de remplacement pas encore validee (etat brouillon), - // on ne permet pas de classer abandonner la facture. + // If there is a replacement invoice not yet validated (draft state), + // it is not allowed to classify the invoice as abandoned. if ($objectidnext) { $facturereplacement = new Facture($db); $facturereplacement->fetch($objectidnext); @@ -4376,14 +4398,14 @@ if ($action == 'create') { // Help $close[1]['label'] = $langs->trans("ConfirmClassifyPaidPartiallyReasonBadCustomerDesc"); $close[2]['label'] = $langs->trans("ConfirmClassifyAbandonReasonOtherDesc"); - // Texte + // Text $close[1]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyPaidPartiallyReasonBadCustomer", $object->ref), $close[1]['label'], 1); $close[2]['reason'] = $form->textwithpicto($langs->transnoentities("ConfirmClassifyAbandonReasonOther"), $close[2]['label'], 1); // arrayreasons $arrayreasons[$close[1]['code']] = $close[1]['reason']; $arrayreasons[$close[2]['code']] = $close[2]['reason']; - // Cree un tableau formulaire + // Create a form table $formquestion = array('text' => $langs->trans("ConfirmCancelBillQuestion"), array('type' => 'radio', 'name' => 'close_code', 'label' => $langs->trans("Reason"), 'values' => $arrayreasons), array('type' => 'text', 'name' => 'close_note', 'label' => $langs->trans("Comment"), 'value' => '', 'morecss' => 'minwidth300')); $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'].'?facid='.$object->id, $langs->trans('CancelBill'), $langs->trans('ConfirmCancelBill', $object->ref), 'confirm_canceled', $formquestion, "yes", 1, 270); @@ -4493,6 +4515,7 @@ if ($action == 'create') { // Type print ''.$langs->trans('Type').''; print $object->getLibType(2); + print $object->getSubtypeLabel('facture'); if ($object->module_source) { print ' ('.$langs->trans("POS").' '.dol_escape_htmltag(ucfirst($object->module_source)).' - '.$langs->trans("Terminal").' '.dol_escape_htmltag($object->pos_source).')'; } @@ -4914,7 +4937,7 @@ if ($action == 'create') { } - // Add the revenu stamp + // Add the revenue stamp if ($selleruserevenustamp) { print ''; print ''; } +// Invoice Subtype +if (!empty($arrayfields['f.subtype']['checked'])) { + print ''; +} // Date invoice if (!empty($arrayfields['f.datef']['checked'])) { print '"; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Date if (!empty($arrayfields['f.datef']['checked'])) { print ''; + + // Invoice Subtype + if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) { + print ''; + } + if (!empty($societe->id) && $societe->id > 0) { // Discounts for third party print ''; +} + // Invoice Subtype +if (!empty($arrayfields['f.subtype']['checked'])) { + print ''; } // Label if (!empty($arrayfields['f.label']['checked'])) { @@ -1275,6 +1290,9 @@ if (!empty($arrayfields['f.type']['checked'])) { print_liste_field_titre($arrayfields['f.type']['label'], $_SERVER["PHP_SELF"], 'f.type', '', $param, '', $sortfield, $sortorder); $totalarray['nbfield']++; } +if (!empty($arrayfields['f.subtype']['checked'])) { + print_liste_field_titre($arrayfields['f.subtype']['label'], $_SERVER["PHP_SELF"], 'f.subtype', '', $param, '', $sortfield, $sortorder); +} if (!empty($arrayfields['f.label']['checked'])) { print_liste_field_titre($arrayfields['f.label']['label'], $_SERVER['PHP_SELF'], "f.libelle,f.rowid", '', $param, '', $sortfield, $sortorder); $totalarray['nbfield']++; @@ -1457,10 +1475,10 @@ while ($i < $imaxinloop) { $userstatic->user_mobile = $obj->user_mobile; $userstatic->job = $obj->job; $userstatic->gender = $obj->gender; - $facturestatic->id = $obj->facid; $facturestatic->ref = $obj->ref; $facturestatic->type = $obj->type; + $facturestatic->subtype = $obj->subtype; $facturestatic->total_ht = $obj->total_ht; $facturestatic->total_tva = $obj->total_tva; $facturestatic->total_ttc = $obj->total_ttc; @@ -1475,7 +1493,6 @@ while ($i < $imaxinloop) { $facturestatic->multicurrency_total_ht = $obj->multicurrency_total_ht; $facturestatic->multicurrency_total_tva = $obj->multicurrency_total_vat; $facturestatic->multicurrency_total_ttc = $obj->multicurrency_total_ttc; - $thirdparty->id = $obj->socid; $thirdparty->name = $obj->name; $thirdparty->name_alias = $obj->alias; @@ -1612,6 +1629,16 @@ while ($i < $imaxinloop) { } } + // Invoice Subtype + if (!empty($arrayfields['f.subtype']['checked'])) { + print '"; + if (!$i) { + $totalarray['nbfield']++; + } + } + // Label if (!empty($arrayfields['f.label']['checked'])) { print '
'; @@ -5299,7 +5322,7 @@ if ($action == 'create') { dol_print_error($db); } - // Paye partiellement 'escompte' + // Partially paid 'discount' if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'discount_vat') { print '
'; print ''; @@ -5309,7 +5332,7 @@ if ($action == 'create') { $resteapayeraffiche = 0; $cssforamountpaymentcomplete = 'amountpaymentneutral'; } - // Paye partiellement ou Abandon 'badcustomer' + // Partially paid or abandoned 'badcustomer' if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'badcustomer') { print '
'; print ''; @@ -5319,7 +5342,7 @@ if ($action == 'create') { // $resteapayeraffiche=0; $cssforamountpaymentcomplete = 'amountpaymentneutral'; } - // Paye partiellement ou Abandon 'product_returned' + // Partially paid or abandoned 'product_returned' if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'product_returned') { print '
'; print ''; @@ -5329,7 +5352,7 @@ if ($action == 'create') { $resteapayeraffiche = 0; $cssforamountpaymentcomplete = 'amountpaymentneutral'; } - // Paye partiellement ou Abandon 'abandon' + // Partially paid or abandoned 'abandoned' if (($object->statut == Facture::STATUS_CLOSED || $object->statut == Facture::STATUS_ABANDONED) && $object->close_code == 'abandon') { print '
'; $text = $langs->trans("HelpAbandonOther"); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index c4f2ae9ae11..6f6eca7702c 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -19,6 +19,7 @@ * Copyright (C) 2018 Nicolas ZABOURI * Copyright (C) 2022 Sylvain Legrand * Copyright (C) 2023 Gauthier VERDOL + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -300,6 +301,7 @@ class Facture extends CommonInvoice 'ref_client' =>array('type'=>'varchar(255)', 'label'=>'RefCustomer', 'enabled'=>1, 'visible'=>-1, 'position'=>10), 'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>0, 'position'=>12), 'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15), + 'subtype' =>array('type'=>'smallint(6)', 'label'=>'InvoiceSubtype', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15), //'increment' =>array('type'=>'varchar(10)', 'label'=>'Increment', 'enabled'=>1, 'visible'=>-1, 'position'=>45), 'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>50), 'datef' =>array('type'=>'date', 'label'=>'DateInvoice', 'enabled'=>1, 'visible'=>1, 'position'=>20), @@ -648,6 +650,7 @@ class Facture extends CommonInvoice $sql .= ", entity"; $sql .= ", ref_ext"; $sql .= ", type"; + $sql .= ", subtype"; $sql .= ", fk_soc"; $sql .= ", datec"; $sql .= ", remise_absolue"; @@ -674,6 +677,7 @@ class Facture extends CommonInvoice $sql .= ", ".setEntity($this); $sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null"); $sql .= ", '".$this->db->escape($this->type)."'"; + $sql .= ", ".($this->subtype ? "'".$this->db->escape($this->subtype)."'" : "null"); $sql .= ", ".((int) $socid); $sql .= ", '".$this->db->idate($now)."'"; $sql .= ", ".($this->remise_absolue > 0 ? $this->remise_absolue : 'NULL'); @@ -1142,6 +1146,7 @@ class Facture extends CommonInvoice $facture->fk_facture_source = $this->fk_facture_source; $facture->type = $this->type; + $facture->subtype = $this->subtype; $facture->socid = $this->socid; $facture->date = $this->date; $facture->date_pointoftax = $this->date_pointoftax; @@ -2114,7 +2119,7 @@ class Facture extends CommonInvoice return -1; } - $sql = 'SELECT f.rowid, f.entity, f.ref, f.ref_client, f.ref_ext, f.type, f.fk_soc'; + $sql = 'SELECT f.rowid, f.entity, f.ref, f.ref_client, f.ref_ext, f.type, f.subtype, f.fk_soc'; $sql .= ', f.total_tva, f.localtax1, f.localtax2, f.total_ht, f.total_ttc, f.revenuestamp'; $sql .= ', f.remise_percent, f.remise_absolue, f.remise'; $sql .= ', f.datef as df, f.date_pointoftax'; @@ -2165,12 +2170,13 @@ class Facture extends CommonInvoice $this->ref_customer = $obj->ref_client; $this->ref_ext = $obj->ref_ext; $this->type = $obj->type; + $this->subtype = $obj->subtype; $this->date = $this->db->jdate($obj->df); $this->date_pointoftax = $this->db->jdate($obj->date_pointoftax); - $this->date_creation = $this->db->jdate($obj->datec); + $this->date_creation = $this->db->jdate($obj->datec); $this->date_validation = $this->db->jdate($obj->datev); - $this->date_modification = $this->db->jdate($obj->datem); - $this->datem = $this->db->jdate($obj->datem); + $this->date_modification = $this->db->jdate($obj->datem); + $this->datem = $this->db->jdate($obj->datem); $this->remise_percent = $obj->remise_percent; // TODO deprecated $this->remise_absolue = $obj->remise_absolue; $this->total_ht = $obj->total_ht; @@ -2178,8 +2184,8 @@ class Facture extends CommonInvoice $this->total_localtax1 = $obj->localtax1; $this->total_localtax2 = $obj->localtax2; $this->total_ttc = $obj->total_ttc; - $this->revenuestamp = $obj->revenuestamp; - $this->paye = $obj->paye; + $this->revenuestamp = $obj->revenuestamp; + $this->paye = $obj->paye; $this->close_code = $obj->close_code; $this->close_note = $obj->close_note; @@ -2446,6 +2452,9 @@ class Facture extends CommonInvoice if (empty($this->type)) { $this->type = self::TYPE_STANDARD; } + if (isset($this->subtype)) { + $this->subtype = trim($this->subtype); + } if (isset($this->ref)) { $this->ref = trim($this->ref); } @@ -2492,6 +2501,7 @@ class Facture extends CommonInvoice $sql .= " ref=".(isset($this->ref) ? "'".$this->db->escape($this->ref)."'" : "null").","; $sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").","; $sql .= " type=".(isset($this->type) ? $this->db->escape($this->type) : "null").","; + $sql .= " subtype=".(isset($this->subtype) ? $this->db->escape($this->subtype) : "null").","; $sql .= " ref_client=".(isset($this->ref_client) ? "'".$this->db->escape($this->ref_client)."'" : "null").","; $sql .= " increment=".(isset($this->increment) ? "'".$this->db->escape($this->increment)."'" : "null").","; $sql .= " fk_soc=".(isset($this->socid) ? $this->db->escape($this->socid) : "null").","; @@ -4825,7 +4835,7 @@ class Facture extends CommonInvoice $return = array(); - $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiement"; + $sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.subtype, f.paye, pf.fk_paiement"; $sql .= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid = pf.fk_facture"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON (f.rowid = ff.fk_facture_source AND ff.type=".self::TYPE_REPLACEMENT.")"; diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index c16acd833f2..09bd4b3c4b8 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -14,6 +14,7 @@ * Copyright (C) 2017 Josep Lluís Amador * Copyright (C) 2018 Charlene Benke * Copyright (C) 2019-2021 Alexandre Spangaro + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -86,6 +87,7 @@ $userid = GETPOST('userid', 'int'); $search_ref = GETPOST('sf_ref') ?GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha'); $search_refcustomer = GETPOST('search_refcustomer', 'alpha'); $search_type = GETPOST('search_type', 'int'); +$search_subtype = GETPOST('search_subtype', 'int'); $search_project_ref = GETPOST('search_project_ref', 'alpha'); $search_project = GETPOST('search_project', 'alpha'); $search_company = GETPOST('search_company', 'alpha'); @@ -216,6 +218,7 @@ $arrayfields = array( 'f.type'=>array('label'=>"Type", 'checked'=>0, 'position'=>15), 'f.datef'=>array('label'=>"DateInvoice", 'checked'=>1, 'position'=>20), 'f.date_valid'=>array('label'=>"DateValidation", 'checked'=>0, 'position'=>22), + 'f.subtype'=>array('label'=>"InvoiceSubtype", 'checked'=>0, 'position'=>17), 'f.date_lim_reglement'=>array('label'=>"DateDue", 'checked'=>1, 'position'=>25), 'f.date_closing'=>array('label'=>"DateClosing", 'checked'=>0, 'position'=>30), 'p.ref'=>array('label'=>"ProjectRef", 'checked'=>1, 'enabled'=>(!isModEnabled('project') ? 0 : 1), 'position'=>40), @@ -322,6 +325,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter', $search_ref = ''; $search_refcustomer = ''; $search_type = ''; + $search_subtype = ''; $search_project_ref = ''; $search_project = ''; $search_company = ''; @@ -565,7 +569,7 @@ $formcompany = new FormCompany($db); $companystatic = new Societe($db); $companyparent = new Societe($db); $company_url_list = array(); - +$subtypearray = $object->subtype_array(0); $title = $langs->trans('BillsCustomers').' '.($socid > 0 ? ' '.$soc->name : ''); $help_url = 'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes'; @@ -578,7 +582,7 @@ $sql = 'SELECT'; if ($sall || $search_user > 0) { $sql = 'SELECT DISTINCT'; } -$sql .= ' f.rowid as id, f.ref, f.ref_client, f.fk_soc, f.type, f.note_private, f.note_public, f.increment, f.fk_mode_reglement, f.fk_cond_reglement, f.total_ht, f.total_tva, f.total_ttc,'; +$sql .= ' f.rowid as id, f.ref, f.ref_client, f.fk_soc, f.type, f.subtype, f.note_private, f.note_public, f.increment, f.fk_mode_reglement, f.fk_cond_reglement, f.total_ht, f.total_tva, f.total_ttc,'; $sql .= ' f.localtax1 as total_localtax1, f.localtax2 as total_localtax2,'; $sql .= ' f.fk_user_author,'; $sql .= ' f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva as multicurrency_total_vat, f.multicurrency_total_ttc,'; @@ -682,6 +686,9 @@ if ($search_refcustomer) { if ($search_type != '' && $search_type != '-1') { $sql .= " AND f.type IN (".$db->sanitize($db->escape($search_type)).")"; } +if ($search_subtype != '' && $search_subtype != '-1') { + $sql .= " AND f.subtype IN (".$db->sanitize($db->escape($search_subtype)).")"; +} if ($search_project_ref) { $sql .= natural_search('p.ref', $search_project_ref); } @@ -1079,6 +1086,9 @@ if ($search_project) { if ($search_type != '') { $param .= '&search_type='.urlencode($search_type); } +if ($search_subtype != '') { + $param .= '&search_subtype='.urlencode($search_subtype); +} if ($search_company) { $param .= '&search_company='.urlencode($search_company); } @@ -1376,6 +1386,12 @@ if (!empty($arrayfields['f.type']['checked'])) { print $form->selectarray('search_type', $listtype, $search_type, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100'); print ''; + print $form->selectarray('search_subtype', $subtypearray, $search_subtype, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100'); + print ''; @@ -1671,6 +1687,9 @@ if (!empty($arrayfields['f.type']['checked'])) { print_liste_field_titre($arrayfields['f.type']['label'], $_SERVER["PHP_SELF"], 'f.type', '', $param, '', $sortfield, $sortorder); $totalarray['nbfield']++; } +if (!empty($arrayfields['f.subtype']['checked'])) { + print_liste_field_titre($arrayfields['f.subtype']['label'], $_SERVER["PHP_SELF"], 'f.subtype', '', $param, '', $sortfield, $sortorder); +} if (!empty($arrayfields['f.datef']['checked'])) { print_liste_field_titre($arrayfields['f.datef']['label'], $_SERVER['PHP_SELF'], 'f.datef', '', $param, 'align="center"', $sortfield, $sortorder); $totalarray['nbfield']++; @@ -1911,6 +1930,7 @@ if ($num > 0) { $facturestatic->ref = $obj->ref; $facturestatic->ref_client = $obj->ref_client; $facturestatic->type = $obj->type; + $facturestatic->subtype = $obj->subtype; $facturestatic->total_ht = $obj->total_ht; $facturestatic->total_tva = $obj->total_tva; $facturestatic->total_ttc = $obj->total_ttc; @@ -2109,6 +2129,16 @@ if ($num > 0) { } } + // Invoice Subtype + if (!empty($arrayfields['f.subtype']['checked'])) { + print ''; + print $facturestatic->getSubtypeLabel('facture'); + print "'; diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 423849a192f..fd2aaaafe49 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2012 Regis Houssin * Copyright (C) 2012 Cédric Salvador * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -637,6 +638,84 @@ abstract class CommonInvoice extends CommonObject return $out; } + /** + * Return label of invoice subtype + * + * @param string $table table of invoice + * @return string Label of invoice subtype + */ + public function getSubtypeLabel($table = '') + { + if ($table === 'facture' || $table === 'facture_fourn') { + $sql = "SELECT s.label FROM " . MAIN_DB_PREFIX . $table . " AS f"; + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "c_invoice_subtype AS s ON f.subtype = s.rowid"; + $sql .= " WHERE f.ref = '".$this->db->escape($this->ref)."'"; + + $resql = $this->db->query($sql); + + if ($resql) { + $subtypeLabel = ''; + + while ($obj = $this->db->fetch_object($resql)) { + $subtypeLabel = $obj->label; + } + + if (!empty($subtypeLabel)) { + print ' ' . $subtypeLabel; + } + } else { + dol_print_error($this->db); + return -1; + } + } + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Retrieve a list of invoice subtype labels or codes. + * + * @param int $mode 0=Return id+label, 1=Return code+id + * @param string $filter Add a SQL filter to select. Data must not come from user input. + * @return array Array of subtypes + */ + public function subtype_array($mode = 0, $filter = '') + { + // phpcs:enable + global $langs; + + $effs = array(); + + $sql = "SELECT rowid, code, label as label"; + $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype'; + $sql .= " WHERE active = 1"; + if ($filter) { + $sql .= " " . $filter; + } + $sql .= " ORDER by rowid, code"; + dol_syslog(get_class($this) . '::subtype_array', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + + while ($i < $num) { + $objp = $this->db->fetch_object($resql); + if (!$mode) { + $key = $objp->rowid; + $effs[$key] = $objp->label; + } else { + $key = $objp->code; + $effs[$key] = $objp->rowid; + } + + $i++; + } + $this->db->free($resql); + } + + return $effs; + } + /** * Return label of object status * diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 9ef4269a310..6cb3c598509 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -22,6 +22,7 @@ * Copyright (C) 2018 Christophe Battarel * Copyright (C) 2018 Josep Lluis Amador * Copyright (C) 2023 Joachim Kueter + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -79,6 +80,7 @@ class Form public $cache_demand_reason = array(); public $cache_types_fees = array(); public $cache_vatrates = array(); + public $cache_invoice_subtype = array(); /** @@ -10800,4 +10802,97 @@ class Form return $retstring; } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + + /** + * Load into cache list of invoice subtypes + * + * @return int Nb of lines loaded, <0 if KO + */ + public function load_cache_invoice_subtype() + { + // phpcs:enable + global $langs; + + $num = count($this->cache_invoice_subtype); + if ($num > 0) { + return 0; // Cache already loaded + } + + dol_syslog(__METHOD__, LOG_DEBUG); + + $sql = "SELECT rowid, code, label as label"; + $sql .= " FROM " . MAIN_DB_PREFIX . 'c_invoice_subtype'; + $sql .= " WHERE active = 1"; + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) { + $obj = $this->db->fetch_object($resql); + + // If translation exists, we use it, otherwise we take the default wording + $label = ($langs->trans("InvoiceSubtype" . $obj->rowid) != ("InvoiceSubtype" . $obj->rowid)) ? $langs->trans("InvoiceSubtype" . $obj->rowid) : (($obj->label != '-') ? $obj->label : ''); + $this->cache_invoice_subtype[$obj->rowid]['rowid'] = $obj->rowid; + $this->cache_invoice_subtype[$obj->rowid]['code'] = $obj->code; + $this->cache_invoice_subtype[$obj->rowid]['label'] = $label; + $i++; + } + + $this->cache_invoice_subtype = dol_sort_array($this->cache_invoice_subtype, 'code', 'asc', 0, 0, 1); + + return $num; + } else { + dol_print_error($this->db); + return -1; + } + } + + + /** + * Return list of invoice subtypes. + * + * @param int $selected Id of invoice subtype to preselect by default + * @param string $htmlname Select field name + * @param int $addempty Add an empty entry + * @param int $noinfoadmin 0=Add admin info, 1=Disable admin info + * @param string $morecss Add more CSS on select tag + * @return string String for the HTML select component + */ + public function getSelectInvoiceSubtype($selected = 0, $htmlname = 'subtypeid', $addempty = 0, $noinfoadmin = 0, $morecss = '') + { + global $langs, $user; + + $out = ''; + dol_syslog(__METHOD__ . " selected=" . $selected . ", htmlname=" . $htmlname, LOG_DEBUG); + + $this->load_cache_invoice_subtype(); + + $out .= '
'.$langs->trans('InvoiceSubtype').''; + print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, ''); + print '
'.$langs->trans('Discounts').''; @@ -3164,6 +3194,7 @@ if ($action == 'create') { print '
'.$langs->trans('Type').''; print ''; print $object->getLibType(); + print $object->getSubtypeLabel('facture_fourn'); print ''; if ($object->type == FactureFournisseur::TYPE_REPLACEMENT) { $facreplaced = new FactureFournisseur($db); diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php index acd747ae391..a75c54fb491 100644 --- a/htdocs/fourn/facture/list.php +++ b/htdocs/fourn/facture/list.php @@ -13,6 +13,7 @@ * Copyright (C) 2018-2022 Charlene Benke * Copyright (C) 2018-2020 Frédéric France * Copyright (C) 2019-2021 Alexandre Spangaro + * Copyright (C) 2023 Nick Fragoulis * * 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 @@ -65,6 +66,7 @@ $search_amount_all_tax = GETPOST("search_amount_all_tax", "alpha"); $search_ref = GETPOST('sf_ref') ?GETPOST('sf_ref', 'alpha') : GETPOST('search_ref', 'alpha'); $search_refsupplier = GETPOST('search_refsupplier', 'alpha'); $search_type = GETPOST('search_type', 'int'); +$search_subtype = GETPOST('search_subtype', 'int'); $search_project = GETPOST('search_project', 'alpha'); $search_company = GETPOST('search_company', 'alpha'); $search_company_alias = GETPOST('search_company_alias', 'alpha'); @@ -170,6 +172,7 @@ $arrayfields = array( 'f.ref'=>array('label'=>"Ref", 'checked'=>1), 'f.ref_supplier'=>array('label'=>"RefSupplier", 'checked'=>1), 'f.type'=>array('label'=>"Type", 'checked'=>0), + 'f.subtype'=>array('label'=>"InvoiceSubtype", 'checked'=>0,), 'f.label'=>array('label'=>"Label", 'checked'=>0), 'f.datef'=>array('label'=>"DateInvoice", 'checked'=>1), 'f.date_lim_reglement'=>array('label'=>"DateDue", 'checked'=>1), @@ -253,6 +256,7 @@ if (empty($reshook)) { $search_ref = ""; $search_refsupplier = ""; $search_type = ""; + $search_subtype = ''; $search_label = ""; $search_project = ''; $search_company = ""; @@ -276,7 +280,6 @@ if (empty($reshook)) { $search_town = ''; $search_zip = ""; $search_state = ""; - $search_type = ''; $search_country = ''; $search_type_thirdparty = ''; $search_date_start = ''; @@ -396,7 +399,7 @@ $bankaccountstatic = new Account($db); $facturestatic = new FactureFournisseur($db); $formcompany = new FormCompany($db); $thirdparty = new Societe($db); - +$subtypearray = $object->subtype_array(0); $now = dol_now(); $title = $langs->trans("BillsSuppliers").($socid ? ' '.$soc->name : ''); @@ -408,7 +411,7 @@ $sql = "SELECT"; if ($search_all) { $sql = 'SELECT DISTINCT'; } -$sql .= " f.rowid as facid, f.ref, f.ref_supplier, f.type, f.datef, f.date_lim_reglement as datelimite, f.fk_mode_reglement, f.fk_cond_reglement,"; +$sql .= " f.rowid as facid, f.ref, f.ref_supplier, f.type, f.subtype, f.datef, f.date_lim_reglement as datelimite, f.fk_mode_reglement, f.fk_cond_reglement,"; $sql .= " f.total_ht, f.total_ttc, f.total_tva as total_vat, f.paye as paye, f.fk_statut as fk_statut, f.libelle as label, f.datec as date_creation, f.tms as date_update,"; $sql .= " f.localtax1 as total_localtax1, f.localtax2 as total_localtax2,"; $sql .= ' f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva as multicurrency_total_vat, f.multicurrency_total_ttc,'; @@ -504,6 +507,9 @@ if ($search_type != '' && $search_type >= 0) { //if ($search_type == '4') $sql.=" AND f.type = 4"; // proforma //if ($search_type == '5') $sql.=" AND f.type = 5"; // situation } +if ($search_subtype != '' && $search_subtype != '-1') { + $sql .= " AND f.subtype IN (".$db->sanitize($db->escape($search_subtype)).")"; +} if ($search_project) { $sql .= natural_search('p.ref', $search_project); } @@ -673,7 +679,7 @@ $reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters, $objec $sql .= $hookmanager->resPrint; if (!$search_all) { - $sql .= " GROUP BY f.rowid, f.ref, f.ref_supplier, f.type, f.datef, f.date_lim_reglement, f.fk_mode_reglement, f.fk_cond_reglement,"; + $sql .= " GROUP BY f.rowid, f.ref, f.ref_supplier, f.type, f.subtype, f.datef, f.date_lim_reglement, f.fk_mode_reglement, f.fk_cond_reglement,"; $sql .= " f.total_ht, f.total_ttc, f.total_tva, f.paye, f.fk_statut, f.libelle, f.datec, f.tms,"; $sql .= " f.localtax1, f.localtax2,"; $sql .= ' f.fk_multicurrency, f.multicurrency_code, f.multicurrency_tx, f.multicurrency_total_ht, f.multicurrency_total_tva, f.multicurrency_total_ttc,'; @@ -813,6 +819,9 @@ if ($search_refsupplier) { if ($search_type != '') { $param .= '&search_type='.urlencode($search_type); } +if ($search_subtype != '') { + $param .= '&search_subtype='.urlencode($search_subtype); +} if ($search_label) { $param .= '&search_label='.urlencode($search_label); } @@ -1049,6 +1058,12 @@ if (!empty($arrayfields['f.type']['checked'])) { //$listtype[Facture::TYPE_PROFORMA]=$langs->trans("InvoiceProForma"); // A proformat invoice is not an invoice but must be an order. print $form->selectarray('search_type', $listtype, $search_type, 1, 0, 0, '', 0, 0, 0, 'ASC', 'maxwidth100'); print ''; + print $form->selectarray('search_subtype', $subtypearray, $search_subtype, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100'); + print ''; + print $facturestatic->getSubtypeLabel('facture_fourn'); + print "'; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 9a718ad04fb..7d2909f27ae 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1102,6 +1102,7 @@ DictionaryExpenseTaxRange=Expense report - Range by transportation category DictionaryTransportMode=Intracomm report - Transport mode DictionaryBatchStatus=Product lot/serial Quality Control status DictionaryAssetDisposalType=Type of disposal of assets +DictionaryInvoiceSubtype=Invoice Subtypes TypeOfUnit=Type of unit SetupSaved=Setup saved SetupNotSaved=Setup not saved diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 2edd2d738fa..4f0e1fed522 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -641,3 +641,4 @@ MentionCategoryOfOperations=Category of operations MentionCategoryOfOperations0=Delivery of goods MentionCategoryOfOperations1=Provision of services MentionCategoryOfOperations2=Mixed - Delivery of goods & provision of services +InvoiceSubtype=Invoice Subtype diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 5a4b1fd8811..d65026b9cba 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -74,6 +74,7 @@ ErrorNoVATRateDefinedForSellerCountry=Error, no vat rates defined for country '% ErrorNoSocialContributionForSellerCountry=Error, no social/fiscal taxes type defined for country '%s'. ErrorFailedToSaveFile=Error, failed to save file. ErrorCannotAddThisParentWarehouse=You are trying to add a parent warehouse which is already a child of a existing warehouse +ErrorInvalidSubtype=Selected Subtype is not allowed FieldCannotBeNegative=Field "%s" cannot be negative MaxNbOfRecordPerPage=Max. number of records per page NotAuthorized=You are not authorized to do that. @@ -1252,3 +1253,4 @@ ErrorFailedToDeleteLink= Failed to remove link '%s' ErrorFailedToUpdateLink= Failed to update link '%s' URLToLink=URL to link OverwriteIfExists=Overwrite if file exists +InvoiceSubtype=Invoice Subtype