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
This commit is contained in:
sonikf 2023-10-18 03:33:14 +03:00 committed by GitHub
parent 5b28ed0f4f
commit 732fb2fa04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 455 additions and 148 deletions

View File

@ -16,6 +16,7 @@
* Copyright (C) 2015-2016 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* 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 '</td></tr>';
// Invoice Subtype
if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
print '<tr><td class="fieldrequired">'.$langs->trans('InvoiceSubtype').'</td><td colspan="2">';
print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, '');
print '</td></tr>';
}
if ($socid > 0) {
// Discounts for third party
print '<tr><td>'.$langs->trans('DiscountStillRemaining').'</td><td colspan="2">';
@ -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 '<tr><td class="titlefield fieldname_type">'.$langs->trans('Type').'</td><td class="valuefield fieldname_type">';
print $object->getLibType(2);
print $object->getSubtypeLabel('facture');
if ($object->module_source) {
print ' <span class="opacitymediumbycolor paddingleft">('.$langs->trans("POS").' '.dol_escape_htmltag(ucfirst($object->module_source)).' - '.$langs->trans("Terminal").' '.dol_escape_htmltag($object->pos_source).')</span>';
}
@ -4914,7 +4937,7 @@ if ($action == 'create') {
}
// Add the revenu stamp
// Add the revenue stamp
if ($selleruserevenustamp) {
print '<tr><td class="titlefieldmiddle">';
print '<table class="nobordernopadding centpercent"><tr><td>';
@ -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 '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
print '<span class="opacitymedium">';
@ -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 '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
print '<span class="opacitymedium">';
@ -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 '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
print '<span class="opacitymedium">';
@ -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 '<tr><td colspan="'.$nbcols.'" class="nowrap right">';
$text = $langs->trans("HelpAbandonOther");

View File

@ -19,6 +19,7 @@
* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2022 Sylvain Legrand <contact@infras.fr>
* Copyright (C) 2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* 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.")";

View File

@ -14,6 +14,7 @@
* Copyright (C) 2017 Josep Lluís Amador <joseplluis@lliuretic.cat>
* Copyright (C) 2018 Charlene Benke <charlie@patas-monkey.com>
* Copyright (C) 2019-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* 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 '</td>';
}
// Invoice Subtype
if (!empty($arrayfields['f.subtype']['checked'])) {
print '<td class="liste_titre maxwidthonsmartphone" align="center">';
print $form->selectarray('search_subtype', $subtypearray, $search_subtype, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100');
print '</td>';
}
// Date invoice
if (!empty($arrayfields['f.datef']['checked'])) {
print '<td class="liste_titre center">';
@ -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 '<td class="nowraponall tdoverflowmax300" title="'.$facturestatic->getSubtypeLabel().'">';
print $facturestatic->getSubtypeLabel('facture');
print "</td>";
if (!$i) {
$totalarray['nbfield']++;
}
}
// Date
if (!empty($arrayfields['f.datef']['checked'])) {
print '<td align="center" class="nowraponall">';

View File

@ -2,6 +2,7 @@
/* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2012 Cédric Salvador <csalvador@gpcsolutions.fr>
* Copyright (C) 2012-2014 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
* 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
*

View File

@ -22,6 +22,7 @@
* Copyright (C) 2018 Christophe Battarel <christophe@altairis.fr>
* Copyright (C) 2018 Josep Lluis Amador <joseplluis@lliuretic.cat>
* Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
* 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 .= '<select id="' . $htmlname . '" class="flat selectsubtype' . ($morecss ? ' ' . $morecss : '') . '" name="' . $htmlname . '">';
if ($addempty) {
$out .= '<option value="0">&nbsp;</option>';
}
foreach ($this->cache_invoice_subtype as $rowid => $subtype) {
$label = $subtype['label'];
$out .= '<option value="' . $subtype['rowid'] . '"';
if ($selected == $subtype['rowid']) {
$out .= ' selected="selected"';
}
$out .= '>';
$out .= $label;
$out .= '</option>';
}
$out .= '</select>';
if ($user->admin && empty($noinfoadmin)) {
$out .= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
}
$out .= ajax_combobox($htmlname);
return $out;
}
}

View File

@ -14,6 +14,7 @@
* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* 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
@ -255,6 +256,7 @@ class FactureFournisseur extends CommonInvoice
'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>25, 'index'=>1),
'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'RefExt', 'enabled'=>1, 'visible'=>0, 'position'=>30),
'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
'subtype' =>array('type'=>'smallint(6)', 'label'=>'InvoiceSubtype', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>36),
'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>'isModEnabled("societe")', 'visible'=>-1, 'notnull'=>1, 'position'=>40),
'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
'datef' =>array('type'=>'date', 'label'=>'Date', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
@ -527,6 +529,7 @@ class FactureFournisseur extends CommonInvoice
$sql .= ", ref_ext";
$sql .= ", entity";
$sql .= ", type";
$sql .= ", subtype";
$sql .= ", libelle";
$sql .= ", fk_soc";
$sql .= ", datec";
@ -553,6 +556,7 @@ class FactureFournisseur extends CommonInvoice
$sql .= ", '".$this->db->escape($this->ref_ext)."'";
$sql .= ", ".((int) $conf->entity);
$sql .= ", '".$this->db->escape($this->type)."'";
$sql .= ", ".($this->subtype ? "'".$this->db->escape($this->subtype)."'" : "null");
$sql .= ", '".$this->db->escape(isset($this->label) ? $this->label : (isset($this->libelle) ? $this->libelle : ''))."'";
$sql .= ", ".((int) $this->socid);
$sql .= ", '".$this->db->idate($now)."'";
@ -853,6 +857,7 @@ class FactureFournisseur extends CommonInvoice
$sql .= " t.ref_ext,";
$sql .= " t.entity,";
$sql .= " t.type,";
$sql .= " t.subtype,";
$sql .= " t.fk_soc,";
$sql .= " t.datec,";
$sql .= " t.datef,";
@ -916,16 +921,17 @@ class FactureFournisseur extends CommonInvoice
$this->id = $obj->rowid;
$this->ref = $obj->ref ? $obj->ref : $obj->rowid; // We take rowid if ref is empty for backward compatibility
$this->ref_supplier = $obj->ref_supplier;
$this->ref_ext = $obj->ref_ext;
$this->ref_supplier = $obj->ref_supplier;
$this->ref_ext = $obj->ref_ext;
$this->entity = $obj->entity;
$this->type = empty($obj->type) ? self::TYPE_STANDARD : $obj->type;
$this->subtype = $obj->subtype;
$this->socid = $obj->fk_soc;
$this->datec = $this->db->jdate($obj->datec);
$this->date = $this->db->jdate($obj->datef);
$this->datep = $this->db->jdate($obj->datef);
$this->tms = $this->db->jdate($obj->tms);
$this->libelle = $obj->label; // deprecated
$this->tms = $this->db->jdate($obj->tms);
$this->libelle = $obj->label; // deprecated
$this->label = $obj->label;
$this->paye = $obj->paye;
$this->paid = $obj->paye;
@ -939,28 +945,28 @@ class FactureFournisseur extends CommonInvoice
$this->status = $obj->status;
$this->statut = $obj->status; // For backward compatibility
$this->fk_statut = $obj->status; // For backward compatibility
$this->fk_user_author = $obj->fk_user_author;
$this->fk_user_author = $obj->fk_user_author;
$this->author = $obj->fk_user_author;
$this->fk_user_valid = $obj->fk_user_valid;
$this->fk_user_valid = $obj->fk_user_valid;
$this->fk_facture_source = $obj->fk_facture_source;
$this->vat_reverse_charge = empty($obj->vat_reverse_charge) ? '0' : '1';
$this->fk_fac_rec_source = $obj->fk_fac_rec_source;
$this->fk_project = $obj->fk_project;
$this->fk_project = $obj->fk_project;
$this->cond_reglement_id = $obj->fk_cond_reglement;
$this->cond_reglement_code = $obj->cond_reglement_code;
$this->cond_reglement = $obj->cond_reglement_label; // deprecated
$this->cond_reglement_code = $obj->cond_reglement_code;
$this->cond_reglement = $obj->cond_reglement_label; // deprecated
$this->cond_reglement_label = $obj->cond_reglement_label;
$this->cond_reglement_doc = $obj->cond_reglement_doc;
$this->fk_account = $obj->fk_account;
$this->mode_reglement_id = $obj->fk_mode_reglement;
$this->mode_reglement_code = $obj->mode_reglement_code;
$this->mode_reglement = $obj->mode_reglement_label;
$this->cond_reglement_doc = $obj->cond_reglement_doc;
$this->fk_account = $obj->fk_account;
$this->mode_reglement_id = $obj->fk_mode_reglement;
$this->mode_reglement_code = $obj->mode_reglement_code;
$this->mode_reglement = $obj->mode_reglement_label;
$this->date_echeance = $this->db->jdate($obj->date_lim_reglement);
$this->note = $obj->note_private; // deprecated
$this->note = $obj->note_private; // deprecated
$this->note_private = $obj->note_private;
$this->note_public = $obj->note_public;
$this->model_pdf = $obj->model_pdf;
$this->import_key = $obj->import_key;
$this->note_public = $obj->note_public;
$this->model_pdf = $obj->model_pdf;
$this->import_key = $obj->import_key;
//Incoterms
$this->fk_incoterms = $obj->fk_incoterms;
@ -1038,45 +1044,43 @@ class FactureFournisseur extends CommonInvoice
$line = new SupplierInvoiceLine($this->db);
$line->id = $obj->rowid;
$line->rowid = $obj->rowid;
$line->description = $obj->description;
$line->date_start = $obj->date_start;
$line->date_end = $obj->date_end;
$line->product_ref = $obj->product_ref;
$line->ref = $obj->product_ref;
$line->id = $obj->rowid;
$line->rowid = $obj->rowid;
$line->description = $obj->description;
$line->date_start = $obj->date_start;
$line->date_end = $obj->date_end;
$line->product_ref = $obj->product_ref;
$line->ref = $obj->product_ref;
$line->ref_supplier = $obj->ref_supplier;
$line->libelle = $obj->label;
$line->label = $obj->label;
$line->product_desc = $obj->product_desc;
$line->subprice = $obj->pu_ht;
$line->pu_ht = $obj->pu_ht;
$line->subprice = $obj->pu_ht;
$line->pu_ht = $obj->pu_ht;
$line->pu_ttc = $obj->pu_ttc;
$line->vat_src_code = $obj->vat_src_code;
$line->vat_src_code = $obj->vat_src_code;
$line->tva_tx = $obj->tva_tx;
$line->localtax1_tx = $obj->localtax1_tx;
$line->localtax2_tx = $obj->localtax2_tx;
$line->localtax1_type = $obj->localtax1_type;
$line->localtax2_type = $obj->localtax2_type;
$line->qty = $obj->qty;
$line->remise_percent = $obj->remise_percent;
$line->remise_percent = $obj->remise_percent;
$line->fk_remise_except = $obj->fk_remise_except;
//$line->tva = $obj->total_tva; // deprecated
//$line->tva = $obj->total_tva; // deprecated
$line->total_ht = $obj->total_ht;
$line->total_ttc = $obj->total_ttc;
$line->total_tva = $obj->total_tva;
$line->total_localtax1 = $obj->total_localtax1;
$line->total_localtax2 = $obj->total_localtax2;
$line->fk_facture_fourn = $obj->fk_facture_fourn;
$line->fk_product = $obj->fk_product;
$line->fk_product = $obj->fk_product;
$line->product_type = $obj->product_type;
$line->product_label = $obj->label;
$line->info_bits = $obj->info_bits;
$line->info_bits = $obj->info_bits;
$line->fk_parent_line = $obj->fk_parent_line;
$line->special_code = $obj->special_code;
$line->rang = $obj->rang;
$line->rang = $obj->rang;
$line->fk_unit = $obj->fk_unit;
// Accountancy
@ -1139,6 +1143,9 @@ class FactureFournisseur extends CommonInvoice
if (isset($this->type)) {
$this->type = trim($this->type);
}
if (isset($this->subtype)) {
$this->subtype = trim($this->subtype);
}
if (isset($this->socid)) {
$this->socid = trim($this->socid);
}
@ -1220,6 +1227,7 @@ class FactureFournisseur extends CommonInvoice
$sql .= " ref_ext=".(isset($this->ref_ext) ? "'".$this->db->escape($this->ref_ext)."'" : "null").",";
$sql .= " entity=".(isset($this->entity) ? ((int) $this->entity) : "null").",";
$sql .= " type=".(isset($this->type) ? ((int) $this->type) : "null").",";
$sql .= " subtype=".(isset($this->subtype) ? $this->db->escape($this->subtype) : "null").",";
$sql .= " fk_soc=".(isset($this->socid) ? ((int) $this->socid) : "null").",";
$sql .= " datec=".(dol_strlen($this->datec) != 0 ? "'".$this->db->idate($this->datec)."'" : 'null').",";
$sql .= " datef=".(dol_strlen($this->date) != 0 ? "'".$this->db->idate($this->date)."'" : 'null').",";
@ -2621,7 +2629,7 @@ class FactureFournisseur extends CommonInvoice
$return = array();
$sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.paye, pf.fk_paiementfourn";
$sql = "SELECT f.rowid as rowid, f.ref, f.fk_statut, f.type, f.subtype, f.paye, pf.fk_paiementfourn";
$sql .= " FROM ".MAIN_DB_PREFIX."facture_fourn as f";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf ON f.rowid = pf.fk_facturefourn";
$sql .= " WHERE f.entity = ".$conf->entity;

View File

@ -12,6 +12,7 @@
* Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2019 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* 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
@ -848,28 +849,35 @@ if (empty($reshook)) {
$error++;
}
if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors');
$action = 'create';
}
if (!$error) {
$tmpproject = GETPOST('projectid', 'int');
// Creation facture
$object->ref = GETPOST('ref', 'alphanohtml');
$object->ref_supplier = GETPOST('ref_supplier', 'alphanohtml');
$object->ref = GETPOST('ref', 'alphanohtml');
$object->ref_supplier = GETPOST('ref_supplier', 'alphanohtml');
$object->subtype = GETPOST('subtype', 'alphanohtml');
$object->socid = GETPOST('socid', 'int');
$object->libelle = GETPOST('label', 'alphanohtml');
$object->libelle = GETPOST('label', 'alphanohtml');
$object->label = GETPOST('label', 'alphanohtml');
$object->date = $dateinvoice;
$object->date_echeance = $datedue;
$object->note_public = GETPOST('note_public', 'restricthtml');
$object->note_private = GETPOST('note_private', 'restricthtml');
$object->date = $dateinvoice;
$object->date_echeance = $datedue;
$object->note_public = GETPOST('note_public', 'restricthtml');
$object->note_private = GETPOST('note_private', 'restricthtml');
$object->cond_reglement_id = GETPOST('cond_reglement_id');
$object->mode_reglement_id = GETPOST('mode_reglement_id');
$object->fk_account = GETPOST('fk_account', 'int');
$object->vat_reverse_charge = GETPOST('vat_reverse_charge') == 'on' ? 1 : 0;
$object->fk_project = ($tmpproject > 0) ? $tmpproject : null;
$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');
$object->multicurrency_tx = GETPOST('originmulticurrency_tx', 'int');
$object->transport_mode_id = GETPOST('transport_mode_id', 'int');
// Proprietes particulieres a facture avoir
@ -946,23 +954,30 @@ 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', 'alphanohtml');
$object->ref = GETPOST('ref', 'alphanohtml');
$object->date = $dateinvoice;
$object->note_public = trim(GETPOST('note_public', 'restricthtml'));
$object->note_private = trim(GETPOST('note_private', 'restricthtml'));
$object->ref_supplier = GETPOST('ref_supplier', 'alphanohtml');
$object->model_pdf = GETPOST('model', 'alphanohtml');
$object->fk_project = GETPOST('projectid', 'int');
$object->socid = GETPOST('socid', 'int');
$object->type = GETPOST('type', 'alphanohtml');
$object->subtype = GETPOST('subtype', 'alphanohtml');
$object->ref = GETPOST('ref', 'alphanohtml');
$object->date = $dateinvoice;
$object->note_public = trim(GETPOST('note_public', 'restricthtml'));
$object->note_private = trim(GETPOST('note_private', 'restricthtml'));
$object->ref_supplier = GETPOST('ref_supplier', 'alphanohtml');
$object->model_pdf = GETPOST('model', 'alphanohtml');
$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');
@ -1002,12 +1017,19 @@ if (empty($reshook)) {
$error++;
}
if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED') && empty(GETPOST("subtype"))) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("InvoiceSubtype")), null, 'errors');
$action = 'create';
}
if (!$error) {
$tmpproject = GETPOST('projectid', 'int');
// Creation invoice
$object->socid = GETPOST('socid', 'int');
$object->type = GETPOST('type', 'alphanohtml');
$object->subtype = GETPOST('subtype', 'alphanohtml');
$object->ref = GETPOST('ref', 'alphanohtml');
$object->ref_supplier = GETPOST('ref_supplier', 'alphanohtml');
$object->socid = GETPOST('socid', 'int');
@ -2558,6 +2580,14 @@ if ($action == 'create') {
print '</td></tr>';
// Invoice Subtype
if (getDolGlobalInt('INVOICE_SUBTYPE_ENABLED')) {
print '<tr><td class="fieldrequired">'.$langs->trans('InvoiceSubtype').'</td><td colspan="2">';
print $form->getSelectInvoiceSubtype(GETPOST('subtype'), 'subtype', 1, 0, '');
print '</td></tr>';
}
if (!empty($societe->id) && $societe->id > 0) {
// Discounts for third party
print '<tr><td>'.$langs->trans('Discounts').'</td><td>';
@ -3164,6 +3194,7 @@ if ($action == 'create') {
print '<tr><td class="titlefield">'.$langs->trans('Type').'</td><td>';
print '<span class="badgeneutral">';
print $object->getLibType();
print $object->getSubtypeLabel('facture_fourn');
print '</span>';
if ($object->type == FactureFournisseur::TYPE_REPLACEMENT) {
$facreplaced = new FactureFournisseur($db);

View File

@ -13,6 +13,7 @@
* Copyright (C) 2018-2022 Charlene Benke <charlene@patas-monkey.com>
* Copyright (C) 2018-2020 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2019-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
* 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 '</td>';
}
// Invoice Subtype
if (!empty($arrayfields['f.subtype']['checked'])) {
print '<td class="liste_titre maxwidthonsmartphone" align="center">';
print $form->selectarray('search_subtype', $subtypearray, $search_subtype, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100');
print '</td>';
}
// 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 '<td class="nowraponall tdoverflowmax300" title="'.$facturestatic->getSubtypeLabel().'">';
print $facturestatic->getSubtypeLabel('facture_fourn');
print "</td>";
if (!$i) {
$totalarray['nbfield']++;
}
}
// Label
if (!empty($arrayfields['f.label']['checked'])) {
print '<td class="nowrap">';

View File

@ -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

View File

@ -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

View File

@ -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 '<b>%s</b>'
ErrorFailedToUpdateLink= Failed to update link '<b>%s</b>'
URLToLink=URL to link
OverwriteIfExists=Overwrite if file exists
InvoiceSubtype=Invoice Subtype