dolibarr/htdocs/comm/propal/card.php
Aymeric Cucherousset a291e0a779
Fix #39412 Add PRG redirect after adding a line to avoid duplicate on refresh (#39528)
Adding a line to a proposal, order, invoice, supplier order or supplier
invoice did not redirect after the POST succeeded, so pressing F5 (or
accepting the browser's "confirm form resubmission" dialog) replayed the
addline POST and duplicated the last line.

Add the same header('Location: ...'); exit(); redirect already used by
the neighboring confirm_addsubtotalline action, on the success path only,
in:
- htdocs/comm/propal/card.php
- htdocs/commande/card.php
- htdocs/compta/facture/card.php
- htdocs/fourn/commande/card.php
- htdocs/fourn/facture/card.php

Validation-error paths are untouched: no DB write happens there, so a
refresh can't duplicate anything, and the form must keep re-displaying
the user's typed values.

Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
2026-08-15 02:45:27 +02:00

3874 lines
166 KiB
PHP

<?php
/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
* Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
* Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
* Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
* Copyright (C) 2010-2023 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2010-2022 Philippe Grand <philippe.grand@atoo-net.com>
* Copyright (C) 2012-2023 Christophe Battarel <christophe.battarel@altairis.fr>
* Copyright (C) 2012 Cedric Salvador <csalvador@gpcsolutions.fr>
* Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro>
* Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2018-2026 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2020 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* Copyright (C) 2023 Lenin Rivas <lenin.rivas777@gmail.com>
* Copyright (C) 2023 William Mead <william.mead@manchenumerique.fr>
* Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Alexandre Spangaro <alexandre@inovea-conseil.com>
* Copyright (C) 2025 Benjamin Falière <benjamin@faliere.com>
* Copyright (C) 2025 Anthony Berton <anthony.berton@bb2a.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/comm/propal/card.php
* \ingroup propale
* \brief Page of commercial proposals card and list
*/
// Load Dolibarr environment
require '../../main.inc.php';
/**
* @var Conf $conf
* @var DoliDB $db
* @var ExtraFields $extrafields
* @var HookManager $hookmanager
* @var Societe $mysoc
* @var Translate $langs
* @var User $user
*/
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formfile.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formpropal.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formmargin.class.php';
require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php';
require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/modules/propale/modules_propale.php';
require_once DOL_DOCUMENT_ROOT . '/core/lib/propal.lib.php';
require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
if (isModEnabled('project')) {
require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
require_once DOL_DOCUMENT_ROOT . '/core/class/html.formprojet.class.php';
}
if (isModEnabled('variants')) {
require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination.class.php';
}
// Load translation files required by the page
$langs->loadLangs(array('companies', 'propal', 'compta', 'bills', 'orders', 'products', 'sendings', 'other'));
if (isModEnabled('incoterm')) {
$langs->load('incoterm');
}
if (isModEnabled('margin')) {
$langs->load('margins');
}
$error = 0;
$outlangs = null;
$array_options = array();
$id = GETPOSTINT('id');
$ref = GETPOST('ref', 'alpha');
$socid = GETPOSTINT('socid');
$action = GETPOST('action', 'aZ09');
$cancel = GETPOST('cancel', 'alpha');
$origin = GETPOST('origin', 'alpha');
$originid = GETPOSTINT('originid');
$renewal = GETPOST('renewal'); // for contract renewal
$confirm = GETPOST('confirm', 'alpha');
$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
$lineid = GETPOSTINT('lineid');
$contactid = GETPOSTINT('contactid');
$projectid = GETPOSTINT('projectid');
$rank = (GETPOSTINT('rank') > 0) ? GETPOSTINT('rank') : -1;
// PDF
$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
$object = new Propal($db);
// fetch optionals attributes and labels
$extrafields->fetch_name_optionals_label($object->table_element);
// Load object
if ($id > 0 || !empty($ref)) {
$ret = $object->fetch($id, $ref);
if ($ret > 0) {
$ret = $object->fetch_thirdparty();
if ($ret > 0 && isset($object->fk_project)) {
$ret = $object->fetchProject();
}
}
if ($ret <= 0) {
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
}
}
// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
$hookmanager->initHooks(array('propalcard', 'globalcard'));
$usercanread = $user->hasRight("propal", "lire");
$usercancreate = $user->hasRight("propal", "creer");
$usercandelete = $user->hasRight("propal", "supprimer");
$usercanclose = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'close')));
$usercanvalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $usercancreate) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'validate')));
$usercansend = (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'send')));
$usermustrespectpricemin = ((getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('produit', 'ignore_price_min_advance')) || !getDolGlobalString('MAIN_USE_ADVANCED_PERMS'));
$usercancreateorder = ($user->hasRight('commande', 'creer') == 1);
$usercancreateinvoice = ($user->hasRight('facture', 'creer') == 1);
$usercancreatecontract = ($user->hasRight('contrat', 'creer') == 1);
$usercancreateintervention = ($user->hasRight('ficheinter', 'creer') == 1);
$usercancreatepurchaseorder = ($user->hasRight('fournisseur', 'commande', 'creer') || $user->hasRight('supplier_order', 'creer'));
$usercanreopen = ((!getDolGlobalBool('MAIN_USE_ADVANCED_PERMS') && $usercanclose) || (getDolGlobalBool('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('propal', 'propal_advance', 'reopen')));
if (getDolGlobalBool('PROPAL_DISALLOW_REOPEN')) {
$usercanreopen = false;
}
$permissiontoadd = $usercancreate;
$permissionnote = $usercancreate; // Used by the include of actions_setnotes.inc.php
$permissiondellink = $usercancreate; // Used by the include of actions_dellink.inc.php
$permissiontoedit = $usercancreate; // Used by the include of actions_lineupdown.inc.php
$permissiontoeditextra = $permissiontoadd;
if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
// For action 'update_extras', is there a specific permission set for the attribute to update
$permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
}
$price_base_type = null;
$shipping_method_id = null;
$warehouse_id = -1;
// Security check
if (!empty($user->socid)) {
$socid = $user->socid;
}
restrictedArea($user, 'propal', $object->id);
/*
* Actions
*/
$parameters = array('socid' => $socid);
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if (empty($reshook)) {
$backurlforlist = dolBuildUrl(DOL_URL_ROOT . '/comm/propal/list.php');
if (empty($backtopage) || ($cancel && empty($id))) {
if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
$backtopage = $backurlforlist;
} else {
$backtopage = dolBuildUrl(DOL_URL_ROOT . '/comm/propal/card.php', ['id' => ((!empty($id) && $id > 0) ? $id : '__ID__')]);
}
}
}
if ($cancel) {
if (!empty($backtopageforcancel)) {
header("Location: " . $backtopageforcancel);
exit;
} elseif (!empty($backtopage)) {
header("Location: " . $backtopage);
exit;
}
$action = '';
}
include DOL_DOCUMENT_ROOT . '/core/actions_setnotes.inc.php'; // Must be include, not includ_once
include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be 'include', not 'include_once'
include DOL_DOCUMENT_ROOT . '/core/actions_lineupdown.inc.php'; // Must be 'include', not 'include_once'
// Action clone object
if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
if (!($socid > 0)) {
setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv('IdThirdParty')), null, 'errors');
} else {
if ($object->id > 0) {
if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY')) {
//Get difference between old and new delivery date and change lines according to difference
$date_delivery = dol_mktime(
12,
0,
0,
GETPOSTINT('date_deliverymonth'),
GETPOSTINT('date_deliveryday'),
GETPOSTINT('date_deliveryyear')
);
$date_delivery_old = $object->delivery_date;
if (!empty($date_delivery_old) && !empty($date_delivery)) {
//Attempt to get the date without possible hour rounding errors
$old_date_delivery = dol_mktime(
12,
0,
0,
(int) dol_print_date($date_delivery_old, '%m'),
(int) dol_print_date($date_delivery_old, '%d'),
(int) dol_print_date($date_delivery_old, '%Y')
);
//Calculate the difference and apply if necessary
$difference = $date_delivery - $old_date_delivery;
if ($difference != 0) {
$object->delivery_date = $date_delivery;
foreach ($object->lines as $line) {
if (isset($line->date_start)) {
$line->date_start += $difference;
}
if (isset($line->date_end)) {
$line->date_end += $difference;
}
}
}
}
}
$result = $object->createFromClone($user, $socid, (GETPOSTISSET('entity') ? GETPOSTINT('entity') : null), (GETPOST('update_prices') == 'on'), (GETPOST('update_desc') == 'on'));
if ($result > 0) {
$warningMsgLineList = array();
// check all product lines are to sell otherwise add a warning message for each product line is not to sell
foreach ($object->lines as $line) {
if (!is_object($line->product)) {
$line->fetch_product();
}
if (is_object($line->product) && $line->product->id > 0) {
if (empty($line->product->status)) {
$warningMsgLineList[$line->id] = $langs->trans('WarningLineProductNotToSell', $line->product->ref);
}
}
}
if (!empty($warningMsgLineList)) {
setEventMessages('', $warningMsgLineList, 'warnings');
}
header("Location: " . $_SERVER['PHP_SELF'] . '?id=' . $result);
exit();
} else {
if (count($object->errors) > 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
$action = '';
}
}
}
} elseif ($action == 'confirm_cancel' && $confirm == 'yes' && $usercanclose) {
// Cancel proposal
$result = $object->setCancel($user);
if ($result > 0) {
header('Location: ' . dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]));
exit();
} else {
$langs->load("errors");
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
// Delete proposal
$result = $object->delete($user);
if ($result > 0) {
header('Location: ' . dolBuildUrl(DOL_URL_ROOT . '/comm/propal/list.php', ['restore_lastsearch_values' => 1]));
exit();
} else {
$langs->load("errors");
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'confirm_deleteline' && $confirm == 'yes' && $usercancreate) {
// Remove line
$result = $object->deleteLine($lineid);
// reorder lines
if ($result > 0) {
$object->line_order(true);
} else {
$langs->load("errors");
setEventMessages($object->error, $object->errors, 'errors');
}
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
if (getDolGlobalInt('MAIN_MULTILANGS')) {
$outputlangs = new Translate("", $conf);
$newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} elseif ($action == 'confirm_delete_subtotalline' && $confirm == 'yes' && $usercancreate) {
// Delete line
$object->fetch($id);
$object->fetch_thirdparty();
$result = $object->deleteSubtotalLine($langs, GETPOSTINT('lineid'), (bool) GETPOST('deletecorrespondingsubtotalline'));
if ($result > 0) {
// reorder lines
$object->line_order(true);
// Define output language
$outputlangs = $langs;
$newlang = '';
if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id')) {
$newlang = GETPOST('lang_id');
}
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
$outputlangs->load('products');
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$ret = $object->fetch($id); // Reload to get new records
$result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
if ($result >= 0) {
header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
exit();
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
$action = '';
}
} elseif ($action == 'confirm_validate' && $confirm == 'yes' && $usercanvalidate) {
// Validation
$idwarehouse = GETPOSTINT('idwarehouse');
$result = $object->valid($user);
if ($result > 0 && getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
$result = $object->closeProposal($user, $object::STATUS_SIGNED);
}
$ret = $object->fetch($id); // Reload to get new records
if ($result >= 0) {
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$outputlangs = $langs;
$newlang = '';
if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
$newlang = GETPOST('lang_id', 'aZ09');
}
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$model = $object->model_pdf;
$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
exit();
} else {
$langs->load("errors");
if (count($object->errors) > 0) {
setEventMessages($object->error, $object->errors, 'errors');
} else {
setEventMessages($langs->trans($object->error), null, 'errors');
}
}
} elseif ($action == 'setdate' && $usercancreate) {
$datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
if (empty($datep)) {
$error++;
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Date")), null, 'errors');
}
if (!$error) {
$result = $object->set_date($user, $datep);
if ($result > 0 && !empty($object->duree_validite) && !empty($object->fin_validite)) {
$datev = $datep + ($object->duree_validite * 24 * 3600);
$result = $object->set_echeance($user, $datev, 1);
}
if ($result < 0) {
dol_print_error($db, $object->error);
} elseif (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$outputlangs = $langs;
$newlang = '';
if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
$newlang = GETPOST('lang_id', 'aZ09');
}
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$model = $object->model_pdf;
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
}
} elseif ($action == 'setecheance' && $usercancreate) {
$result = $object->set_echeance($user, dol_mktime(12, 0, 0, GETPOSTINT('echmonth'), GETPOSTINT('echday'), GETPOSTINT('echyear')));
if ($result >= 0) {
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$outputlangs = $langs;
$newlang = '';
if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
$newlang = GETPOST('lang_id', 'aZ09');
}
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$model = $object->model_pdf;
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'setdate_livraison' && $usercancreate) {
$result = $object->setDeliveryDate($user, dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear')));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'setref_client' && $usercancreate) {
// Positionne ref client
$result = $object->set_ref_client($user, GETPOST('ref_client'));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'set_incoterms' && isModEnabled('incoterm') && $usercancreate) {
// Set incoterm
$result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOST('location_incoterms'));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'settags' && isModEnabled('category') && $usercancreate) { // Set tags
$result = $object->setCategories(GETPOST('categories', 'array'));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'add' && $usercancreate) {
// Create proposal
$object->socid = $socid;
$object->fetch_thirdparty();
$datep = dol_mktime(12, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'));
$date_delivery = dol_mktime(12, 0, 0, GETPOSTINT('date_livraisonmonth'), GETPOSTINT('date_livraisonday'), GETPOSTINT('date_livraisonyear'));
$duration = GETPOSTINT('duree_validite');
if (empty($datep)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("DatePropal")), null, 'errors');
$action = 'create';
$error++;
}
if (empty($duration)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ValidityDuration")), null, 'errors');
$action = 'create';
$error++;
}
if ($socid < 1) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), null, 'errors');
$action = 'create';
$error++;
}
if (!$error) {
$db->begin();
// If we select proposal to clone during creation (when option PROPAL_CLONE_ON_CREATE_PAGE is on)
if (GETPOST('createmode') == 'copy' && GETPOST('copie_propal')) {
if ($object->fetch(GETPOSTINT('copie_propal')) > 0) {
$object->ref = GETPOST('ref');
$object->datep = $datep;
$object->date = $datep;
$object->delivery_date = $date_delivery;
$object->availability_id = GETPOSTINT('availability_id');
$object->demand_reason_id = GETPOSTINT('demand_reason_id');
$object->fk_delivery_address = GETPOSTINT('fk_address');
$object->shipping_method_id = GETPOSTINT('shipping_method_id');
$object->warehouse_id = GETPOSTINT('warehouse_id');
$object->duree_validite = $duration;
$object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
$object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
$object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
$object->fk_account = GETPOSTINT('fk_account');
$object->socid = GETPOSTINT('socid');
$object->contact_id = GETPOSTINT('contactid');
$object->fk_project = GETPOSTINT('projectid');
$object->model_pdf = GETPOST('model', 'alphanohtml');
$object->author = $user; // deprecated
$object->user_author_id = $user->id;
$object->note_private = GETPOST('note_private', 'restricthtml');
$object->note_public = GETPOST('note_public', 'restricthtml');
$object->statut = Propal::STATUS_DRAFT;
$object->status = Propal::STATUS_DRAFT;
$object->fk_incoterms = GETPOSTINT('incoterm_id');
$object->location_incoterms = GETPOST('location_incoterms', 'alpha');
} else {
setEventMessages($langs->trans("ErrorFailedToCopyProposal", GETPOST('copie_propal')), null, 'errors');
}
} else {
$object->ref = GETPOST('ref');
$object->ref_customer = GETPOST('ref_client');
$object->ref_client = $object->ref_customer;
$object->datep = $datep;
$object->date = $datep;
$object->delivery_date = $date_delivery;
$object->availability_id = GETPOSTINT('availability_id');
$object->demand_reason_id = GETPOSTINT('demand_reason_id');
$object->fk_delivery_address = GETPOSTINT('fk_address');
$object->shipping_method_id = GETPOSTINT('shipping_method_id');
$object->warehouse_id = GETPOSTINT('warehouse_id');
$object->duree_validite = price2num(GETPOST('duree_validite', 'alpha'));
$object->cond_reglement_id = GETPOSTINT('cond_reglement_id');
$object->deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
$object->mode_reglement_id = GETPOSTINT('mode_reglement_id');
$object->fk_account = GETPOSTINT('fk_account');
$object->contact_id = GETPOSTINT('contactid');
$object->fk_project = GETPOSTINT('projectid');
$object->model_pdf = GETPOST('model');
$object->author = $user; // deprecated
$object->user_author_id = $user->id;
$object->note_private = GETPOST('note_private', 'restricthtml');
$object->note_public = GETPOST('note_public', 'restricthtml');
$object->fk_incoterms = GETPOSTINT('incoterm_id');
$object->location_incoterms = GETPOST('location_incoterms', 'alpha');
$object->origin = GETPOST('origin');
$object->origin_id = GETPOSTINT('originid');
// Multicurrency
if (isModEnabled("multicurrency")) {
$object->multicurrency_code = GETPOST('multicurrency_code', 'alpha');
}
// Fill array 'array_options' with data from add form
$ret = $extrafields->setOptionalsFromPost(null, $object);
if ($ret < 0) {
$error++;
$action = 'create';
}
}
if (!$error) {
if ($origin && $originid) {
// Parse element/subelement (ex: project_task)
$element = $subelement = $origin;
$regs = array();
if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
$element = $regs[1];
$subelement = $regs[2];
}
// For compatibility
if ($element == 'order') {
$element = $subelement = 'commande';
}
if ($element == 'propal') {
$element = 'comm/propal';
$subelement = 'propal';
}
if ($element == 'contract') {
$element = $subelement = 'contrat';
}
if ($element == 'inter') {
$element = $subelement = 'fichinter';
}
if ($element == 'shipping') {
$element = $subelement = 'expedition';
}
// If this is a renewal proposal for a contract, we might choose to systematically create a new contract,
if (($origin != 'contrat' || $renewal != 'true') && !getDolGlobalInt('CONTRACT_NEW_CONTRACT_ON_RENEWAL')) {
$object->origin = $origin;
$object->origin_id = $originid;
// Possibility to add external linked objects with hooks
$object->linked_objects[$object->origin] = $object->origin_id;
}
if (GETPOSTISARRAY('other_linked_objects')) {
$object->linked_objects = array_merge($object->linked_objects, GETPOST('other_linked_objects', 'array:int'));
}
$id = $object->create($user);
if ($id > 0) {
dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
$classname = ucfirst($subelement);
$srcobject = new $classname($db);
'@phan-var-force Commande|Propal|Contrat|Fichinter|Expedition $srcobject'; // Can be other class, but CommonObject is too generic
/** @var Commande|Propal|Contrat|Fichinter|Expedition $srcobject */
dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines");
$result = $srcobject->fetch($object->origin_id);
if ($result > 0) {
$lines = $srcobject->lines;
if (empty($lines) && method_exists($srcobject, 'fetch_lines')) {
$srcobject->fetch_lines();
$lines = $srcobject->lines;
}
$fk_parent_line = 0;
$num = count($lines);
for ($i = 0; $i < $num; $i++) {
$label = (!empty($lines[$i]->label) ? $lines[$i]->label : '');
$desc = (!empty($lines[$i]->desc) ? $lines[$i]->desc : '');
// Positive line
$product_type = ($lines[$i]->product_type ? (int) $lines[$i]->product_type : 0);
// Date start
$date_start = false;
if ($lines[$i]->date_debut_prevue) {
$date_start = $lines[$i]->date_debut_prevue;
}
if ($lines[$i]->date_debut_reel) {
$date_start = $lines[$i]->date_debut_reel;
}
if ($lines[$i]->date_start) {
$date_start = $lines[$i]->date_start;
}
// Date end
$date_end = false;
if ($lines[$i]->date_fin_prevue) {
$date_end = $lines[$i]->date_fin_prevue;
}
if ($lines[$i]->date_fin_reel) {
$date_end = $lines[$i]->date_fin_reel;
}
if ($lines[$i]->date_end) {
$date_end = $lines[$i]->date_end;
}
// For a contract renewal, we report duration, starting after the end of contract
if ($origin == 'contrat' && $renewal == 'true') {
if ($lines[$i]->date_start && $lines[$i]->date_end) {
$duration = $lines[$i]->date_end - $lines[$i]->date_start;
$date_start = $lines[$i]->date_end + 86400;
$date_end = $date_start + $duration;
}
}
// Reset fk_parent_line for no child products and special product
if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
$fk_parent_line = 0;
}
// Extrafields
if (method_exists($lines[$i], 'fetch_optionals')) {
$lines[$i]->fetch_optionals();
$array_options = $lines[$i]->array_options;
}
$tva_tx = $lines[$i]->tva_tx;
if (!empty($lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) {
$tva_tx .= ' (' . $lines[$i]->vat_src_code . ')';
}
// Preserve the TTC entry mode of the source line: a line entered including tax must
// stay in TTC so its total is computed from the typed value, without rounding drift.
$line_price_base_type = $lines[$i]->getPriceBaseType();
$result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $line_price_base_type, (float) $lines[$i]->subprice_ttc, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $date_start, $date_end, $array_options, $lines[$i]->fk_unit);
if ($result > 0) {
$lineid = $result;
} else {
$lineid = 0;
$error++;
break;
}
// Defined the new fk_parent_line
if ($result > 0 && $lines[$i]->product_type == 9) {
$fk_parent_line = $result;
}
}
// Hooks
$parameters = array('objFrom' => $srcobject);
$reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been
// modified by hook
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
$error++;
}
} else {
setEventMessages($srcobject->error, $srcobject->errors, 'errors');
$error++;
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
} else {
// Standard creation
$id = $object->create($user);
}
if ($id > 0) {
// Insert default contacts if defined
if (GETPOST('contactid') > 0) {
$result = $object->add_contact(GETPOSTINT('contactid'), 'CUSTOMER', 'external');
if ($result < 0) {
$error++;
setEventMessages($langs->trans("ErrorFailedToAddContact"), null, 'errors');
}
}
if (getDolGlobalString('PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT')) {
$result = $object->add_contact($user->id, 'SALESREPFOLL', 'internal');
if ($result < 0) {
$error++;
setEventMessages($langs->trans("ErrorFailedToAddUserAsContact"), null, 'errors');
}
}
if (isModEnabled('category')) {
$categories = GETPOST('categories', 'array');
if (method_exists($object, 'setCategories')) {
$object->setCategories($categories);
}
}
if (!$error) {
$db->commit();
// Define output language
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$outputlangs = $langs;
$newlang = '';
if (getDolGlobalInt('MAIN_MULTILANGS') /* && empty($newlang) */ && GETPOST('lang_id', 'aZ09')) {
$newlang = GETPOST('lang_id', 'aZ09');
}
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$model = $object->model_pdf;
$ret = $object->fetch($id); // Reload to get new records
$result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
if ($result < 0) {
dol_print_error($db, $object->error, $object->errors);
}
}
header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
exit();
} else {
$db->rollback();
$action = 'create';
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
$db->rollback();
$action = 'create';
}
}
}
} elseif ($action == 'classifybilled' && $usercanclose) {
// Classify billed
$db->begin();
$result = $object->classifyBilled($user, 0, '');
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
if (!$error) {
$db->commit();
} else {
$db->rollback();
}
} elseif ($action == 'confirm_closeas' && $usercanclose && !GETPOST('cancel', 'alpha')) {
// Close proposal
if (!(GETPOSTINT('statut') > 0)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("CloseAs")), null, 'errors');
$action = 'closeas';
} elseif (GETPOSTINT('statut') == $object::STATUS_SIGNED || GETPOSTINT('statut') == $object::STATUS_NOTSIGNED) {
$locationTarget = '';
// prevent browser refresh from closing proposal several times
if ($object->status == $object::STATUS_VALIDATED || (getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') && $object->status == $object::STATUS_DRAFT)) {
$db->begin();
$oldstatus = $object->status;
$result = $object->closeProposal($user, GETPOSTINT('statut'), GETPOST('note_private'));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
} else {
// Needed if object linked modified by trigger (because linked objects can't be fetched two times : linkedObjectsFullLoaded)
$locationTarget = DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id;
}
$deposit = null;
$deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
if (
!$error && GETPOSTINT('statut') == $object::STATUS_SIGNED && GETPOST('generate_deposit') == 'on'
&& !empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')
) {
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
$date = dol_mktime(0, 0, 0, GETPOSTINT('datefmonth'), GETPOSTINT('datefday'), GETPOSTINT('datefyear'));
$forceFields = array();
if (GETPOSTISSET('date_pointoftax')) {
$forceFields['date_pointoftax'] = dol_mktime(0, 0, 0, GETPOSTINT('date_pointoftaxmonth'), GETPOSTINT('date_pointoftaxday'), GETPOSTINT('date_pointoftaxyear'));
}
$deposit = Facture::createDepositFromOrigin($object, $date, GETPOSTINT('cond_reglement_id'), $user, 0, GETPOSTINT('validate_generated_deposit') == 'on', $forceFields);
if ($deposit) {
setEventMessage('DepositGenerated');
$locationTarget = DOL_URL_ROOT . '/compta/facture/card.php?id=' . $deposit->id;
} else {
$error++;
setEventMessages("Failed to create down payment - " . $object->error, $object->errors, 'errors');
}
}
if (!$error) {
$db->commit();
if ($deposit && !getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
$ret = $deposit->fetch($deposit->id); // Reload to get new records
$outputlangs = $langs;
if (getDolGlobalInt('MAIN_MULTILANGS')) {
$outputlangs = new Translate('', $conf);
$outputlangs->setDefaultLang($deposit->thirdparty->default_lang);
$outputlangs->load('products');
}
$result = $deposit->generateDocument($deposit->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
if ($result < 0) {
setEventMessages($deposit->error, $deposit->errors, 'errors');
}
}
if ($locationTarget) {
header('Location: ' . $locationTarget);
exit;
}
} else {
$object->status = $oldstatus;
$object->statut = $oldstatus; // deprecated
$db->rollback();
$action = '';
}
}
}
} elseif ($action == 'confirm_reopen' && $usercanreopen && !GETPOST('cancel', 'alpha')) {
// Reopen proposal
// prevent browser refresh from reopening proposal several times
if ($object->status == Propal::STATUS_SIGNED || $object->status == Propal::STATUS_NOTSIGNED || $object->status == Propal::STATUS_BILLED || $object->status == Propal::STATUS_CANCELED) {
$db->begin();
$newstatus = (getDolGlobalInt('PROPAL_SKIP_ACCEPT_REFUSE') ? Propal::STATUS_DRAFT : Propal::STATUS_VALIDATED);
$result = $object->reopen($user, $newstatus);
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
} else {
$object->statut = $newstatus; // deprecated
$object->status = $newstatus;
}
if (!$error) {
$db->commit();
} else {
$db->rollback();
}
}
} elseif ($action == 'import_lines_from_object' && $usercancreate && $object->status == Propal::STATUS_DRAFT) {
// add lines from objectlinked
$fromElement = GETPOST('fromelement');
$fromElementid = GETPOST('fromelementid');
$importLines = GETPOST('line_checkbox');
if (!empty($importLines) && is_array($importLines) && !empty($fromElement) && ctype_alpha($fromElement) && !empty($fromElementid)) {
if ($fromElement == 'commande') {
dol_include_once('/' . $fromElement . '/class/' . $fromElement . '.class.php');
$lineClassName = 'OrderLine';
} elseif ($fromElement == 'propal') {
dol_include_once('/comm/' . $fromElement . '/class/' . $fromElement . '.class.php');
$lineClassName = 'PropaleLigne';
} elseif ($fromElement == 'facture') {
dol_include_once('/compta/' . $fromElement . '/class/' . $fromElement . '.class.php');
$lineClassName = 'FactureLigne';
} else {
$lineClassName = null;
}
$nextRang = count($object->lines) + 1;
$importCount = 0;
$error = 0;
foreach ($importLines as $lineId) {
$lineId = intval($lineId);
$originLine = new $lineClassName($db);
if (intval($fromElementid) > 0 && $originLine->fetch($lineId) > 0) {
$originLine->fetch_optionals();
$desc = $originLine->desc;
$pu_ht = $originLine->subprice;
$qty = $originLine->qty;
$txtva = $originLine->tva_tx;
$txlocaltax1 = $originLine->localtax1_tx;
$txlocaltax2 = $originLine->localtax2_tx;
$fk_product = $originLine->fk_product;
$remise_percent = $originLine->remise_percent;
$date_start = $originLine->date_start;
$date_end = $originLine->date_end;
$fk_code_ventilation = 0;
$info_bits = $originLine->info_bits;
$fk_remise_except = $originLine->fk_remise_except;
$price_base_type = 'HT';
$pu_ttc = 0;
$type = $originLine->product_type;
$rang = $nextRang++;
$special_code = $originLine->special_code;
$origin = $originLine->element;
$origin_id = $originLine->id;
$fk_parent_line = 0;
$fk_fournprice = $originLine->fk_fournprice;
$pa_ht = $originLine->pa_ht;
$label = $originLine->label;
$array_options = $originLine->array_options;
$situation_percent = 100;
$fk_prev_id = '';
$fk_unit = $originLine->fk_unit;
$pu_ht_devise = $originLine->multicurrency_subprice;
$res = $object->addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1, $txlocaltax2, $fk_product, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, $rang, $special_code, $fk_parent_line, $fk_fournprice, $pa_ht, $label, $date_start, $date_end, $array_options, $fk_unit, $origin, $origin_id, $pu_ht_devise, $fk_remise_except);
if ($res > 0) {
$importCount++;
} else {
$error++;
}
} else {
$error++;
}
}
if ($error) {
setEventMessages($langs->trans('ErrorsOnXLines', $error), null, 'errors');
}
}
} elseif ($action == 'addline' && GETPOST('updateallvatlinesblock', 'alpha') && GETPOST('vatforblocklines', 'alpha') !== '' && $usercancreate) {
$tx_tva = GETPOST('vatforblocklines') ? GETPOST('vatforblocklines') : 0;
$result = $object->updateSubtotalLineBlockLines($langs, $object->getRangOfLine($lineid), 'tva', $tx_tva);
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'addline' && GETPOST('updatealldiscountlinesblock', 'alpha') && GETPOST('discountforblocklines', 'alpha') !== '' && $usercancreate) {
$discount = GETPOST('discountforblocklines') ? GETPOST('discountforblocklines') : 0;
$result = $object->updateSubtotalLineBlockLines($langs, $object->getRangOfLine($lineid), 'discount', $discount);
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
}
include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
// Actions to send emails
$actiontypecode = 'AC_EMAIL';
$triggersendname = 'PROPAL_SENTBYMAIL';
$autocopy = 'MAIN_MAIL_AUTOCOPY_PROPOSAL_TO';
$trackid = 'pro' . $object->id;
include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
// Go back to draft
if ($action == 'modif' && $usercancreate) {
$result = $object->setDraft($user);
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
if (getDolGlobalInt('MAIN_MULTILANGS')) {
$outputlangs = new Translate("", $conf);
$newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
$outputlangs->setDefaultLang($newlang);
}
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} elseif ($action == "setabsolutediscount" && $usercancreate) {
if (GETPOSTINT("remise_id")) {
if ($object->id > 0) {
$result = $object->insert_discount(GETPOSTINT("remise_id"));
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
} elseif ($action == 'addline' && GETPOST('submitforalllines', 'aZ09') && (GETPOST('alldate_start', 'alpha') || GETPOST('alldate_end', 'alpha')) && $usercancreate) {
// Define date start and date end for all line
$alldate_start = dol_mktime(GETPOSTINT('alldate_starthour'), GETPOSTINT('alldate_startmin'), 0, GETPOSTINT('alldate_startmonth'), GETPOSTINT('alldate_startday'), GETPOSTINT('alldate_startyear'));
$alldate_end = dol_mktime(GETPOSTINT('alldate_endhour'), GETPOSTINT('alldate_endmin'), 0, GETPOSTINT('alldate_endmonth'), GETPOSTINT('alldate_endday'), GETPOSTINT('alldate_endyear'));
foreach ($object->lines as $key => $line) {
if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
continue;
}
if ($line->product_type == 1) { // only service line
// Preserve the original entry mode of the line so the total is not drifted by rounding.
$line_price_base_type = $line->getPriceBaseType();
$line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
$result = $object->updateline($line->id, $line_pu, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $alldate_start, $alldate_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
$object->lines[$key] = $object->line;
}
}
} elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('vatforalllines', 'alpha') !== '' && $usercancreate) {
// Define a vat_rate for all lines
$vat_rate = (GETPOST('vatforalllines') ? GETPOST('vatforalllines') : 0);
$vat_rate = str_replace('*', '', $vat_rate);
$localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
$localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
foreach ($object->lines as $key => $line) {
if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
continue;
}
// Preserve the original entry mode of the line so the total is not drifted by rounding.
$line_price_base_type = $line->getPriceBaseType();
$line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
$result = $object->updateline($line->id, $line_pu, $line->qty, $line->remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
$object->lines[$key] = $object->line;
}
} elseif ($action == 'addline' && GETPOST('submitforalllines', 'alpha') && GETPOST('remiseforalllines', 'alpha') !== '' && $usercancreate) {
// Define a discount for all lines
$remise_percent = (GETPOST('remiseforalllines') ? GETPOST('remiseforalllines') : 0);
$remise_percent = str_replace('*', '', $remise_percent);
foreach ($object->lines as $key => $line) {
if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
continue;
}
$tvatx = $line->tva_tx;
if (!empty($line->vat_src_code)) {
$tvatx .= ' (' . $line->vat_src_code . ')';
}
// Preserve the original entry mode of the line so the total is not drifted by rounding.
$line_price_base_type = $line->getPriceBaseType();
$line_pu = ($line_price_base_type === 'TTC') ? (float) $line->subprice_ttc : (float) $line->subprice;
$result = $object->updateline($line->id, $line_pu, $line->qty, (float) $remise_percent, $tvatx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, $line_price_base_type, $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $line->multicurrency_subprice);
$object->lines[$key] = $object->line;
}
} elseif ($action == 'addline' && GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines', 'alpha') !== '' && $usercancreate) {
// Define margin
$margin_rate = (GETPOST('marginforalllines', 'alpha') ? GETPOST('marginforalllines', 'alpha') : 0);
foreach ($object->lines as $key => $line) {
if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
continue;
}
$subprice = price2num($line->pa_ht * (1 + $margin_rate / 100), 'MU');
$prod = new Product($db);
$prod->fetch($line->fk_product);
if ($prod->price_min > $subprice) {
$price_subprice = price($subprice, 0, $outlangs, 1, -1, -1, 'auto');
$price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
setEventMessages($prod->ref . ' - ' . $prod->label . ' (' . $price_subprice . ' < ' . $price_price_min . ' ' . strtolower($langs->trans("MinPrice")) . ')' . "\n", null, 'warnings');
}
// Manage $line->subprice and $line->multicurrency_subprice
if ($line->subprice <> 0) {
$multicurrency_subprice = (float) $subprice * $line->multicurrency_subprice / $line->subprice;
} else {
$multicurrency_subprice = 0;
}
// Update DB
$result = $object->updateline($line->id, (float) $subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $multicurrency_subprice);
$object->lines[$key] = $object->line;
// Update $object with new margin info
// $line->price = $subprice;
// $line->marge_tx = $margin_rate;
// $line->marque_tx = $margin_rate * $line->pa_ht / (float) $subprice;
// $line->total_ht = $line->qty * (float) $subprice;
// $line->total_tva = $line->tva_tx * $line->qty * (float) $subprice;
// $line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice;
// // Manage $line->subprice and $line->multicurrency_subprice
// $line->multicurrency_total_ht = $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
// $line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
// $line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice * $line->multicurrency_subprice / $line->subprice;
// // Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
// $line->subprice = (float) $subprice;
// $line->multicurrency_subprice = $multicurrency_subprice;
}
} elseif ($action == 'confirm_addtitleline' && $usercancreate) {
// Handling adding a new title line for subtotals module
$langs->load('subtotals');
$desc = GETPOST('subtotallinedesc', 'alphanohtml');
$depth = GETPOSTINT('subtotallinelevel') ?? 1;
$subtotal_options = array();
foreach (Propal::$TITLE_OPTIONS as $option) {
$value = GETPOST($option, 'alphanohtml');
if ($value) {
$subtotal_options[$option] = $value == 'on' ? 1 : $value;
}
}
// Insert line
$result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
if ($result >= 0) {
if ($result == 0) {
setEventMessages($object->error, $object->errors, 'warnings');
}
$ret = $object->fetch($object->id); // Reload to get new records
$object->fetch_thirdparty();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
exit();
} elseif ($action == 'confirm_addsubtotalline' && $usercancreate) {
// Handling adding a new subtotal line for subtotals module
$langs->load('subtotals');
$choosen_line = GETPOST('subtotaltitleline', 'alphanohtml');
foreach ($object->lines as $line) {
if ($line->desc == $choosen_line && $line->special_code == SUBTOTALS_SPECIAL_CODE) {
$desc = $line->desc;
$depth = -$line->qty;
}
}
$subtotal_options = array();
foreach (Propal::$SUBTOTAL_OPTIONS as $option) {
$value = GETPOST($option, 'alphanohtml');
if ($value) {
$subtotal_options[$option] = $value == 'on' ? 1 : $value;
}
}
// Insert line
if (isset($desc) && isset($depth)) {
$result = $object->addSubtotalLine($langs, $desc, (int) $depth, $subtotal_options);
} else {
$result = -1;
$object->errors[] = $langs->trans("CorrespondingTitleNotFound");
}
if ($result >= 0) {
$ret = $object->fetch($object->id); // Reload to get new records
$object->fetch_thirdparty();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id);
exit();
} elseif ($action == 'addline' && !GETPOST('submitforalllines', 'alpha') && !GETPOST('submitforallmargins', 'alpha') && !GETPOST('markforalllines', 'alpha') && $usercancreate) {
// Add line
// Set if we used free entry or predefined product
$predef = '';
$line_desc = (GETPOSTISSET('dp_desc') ? GETPOST('dp_desc', 'restricthtml') : '');
$price_ht = '';
$price_ht_devise = '';
$price_ttc = '';
$price_ttc_devise = '';
// TODO Implement if (getDolGlobalInt('MAIN_UNIT_PRICE_WITH_TAX_IS_FOR_ALL_TAXES'))
if (GETPOST('price_ht') !== '') {
$price_ht = price2num(GETPOST('price_ht'), 'MU', 2);
}
if (GETPOST('multicurrency_price_ht') !== '') {
$price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2);
}
if (GETPOST('price_ttc') !== '') {
$price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2);
}
if (GETPOST('multicurrency_price_ttc') !== '') {
$price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2);
}
$prod_entry_mode = GETPOST('prod_entry_mode', 'aZ09');
if ($prod_entry_mode == 'free') {
$idprod = 0;
} else {
$idprod = GETPOSTINT('idprod');
if (getDolGlobalString('MAIN_DISABLE_FREE_LINES') && $idprod <= 0) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ProductOrService")), null, 'errors');
$error++;
}
}
$tva_tx = GETPOST('tva_tx', 'alpha');
$qty = price2num(GETPOST('qty' . $predef, 'alpha'), 'MS', 2);
$remise_percent = (GETPOSTISSET('remise_percent' . $predef) ? price2num(GETPOST('remise_percent' . $predef, 'alpha'), '', 2) : 0);
if (empty($remise_percent)) {
$remise_percent = 0;
}
// Extrafields
$extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
$array_options = $extrafields->getOptionalsFromPost($object->table_element_line, $predef);
// Unset extrafield
if (is_array($extralabelsline)) {
// Get extra fields
foreach ($extralabelsline as $key => $value) {
unset($_POST["options_" . $key]);
}
}
$price_to_test_sign = ($price_ht ? $price_ht : $price_ttc);
if ((empty($idprod) || $idprod < 0) && ($price_to_test_sign < 0) && ($qty < 0)) {
$langs->load("errors");
setEventMessages($langs->trans('ErrorBothFieldCantBeNegative', $langs->transnoentitiesnoconv('UnitPriceHT'), $langs->transnoentitiesnoconv('Qty')), null, 'errors');
$error++;
}
if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && GETPOST('type') < 0) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
$error++;
}
if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && $price_ht === '' && $price_ht_devise === '' && $price_ttc === '' && $price_ttc_devise === '') { // Unit price can be 0 but not ''. Also price can be negative for proposal.
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors');
$error++;
}
if ($qty < 0 && !getDolGlobalString('PROPAL_ENABLE_NEGATIVE_QTY')) {
setEventMessages($langs->trans('FieldCannotBeNegative', $langs->transnoentitiesnoconv('Qty')), null, 'errors');
$error++;
}
if ($prod_entry_mode == 'free' && (empty($idprod) || $idprod < 0) && empty($line_desc)) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), null, 'errors');
$error++;
}
if (!$error && isModEnabled('variants') && $prod_entry_mode != 'free') {
if ($combinations = GETPOST('combinations', 'array:alphanohtml')) {
//Check if there is a product with the given combination
$prodcomb = new ProductCombination($db);
if ($res = $prodcomb->fetchByProductCombination2ValuePairs($idprod, $combinations)) {
$idprod = $res->fk_product_child;
} else {
setEventMessages($langs->trans('ErrorProductCombinationNotFound'), null, 'errors');
$error++;
}
}
}
if (!$error && (!empty($line_desc) || (!empty($idprod) && $idprod > 0))) {
$pu_ht = 0;
$pu_ttc = 0;
$pu_ht_devise = 0;
$pu_ttc_devise = 0;
$price_min = 0;
$price_min_ttc = 0;
$tva_npr = 0;
$price_base_type = (GETPOST('price_base_type', 'alpha') ? GETPOST('price_base_type', 'alpha') : 'HT');
$db->begin();
// $tva_tx can be 'x.x (XXX)'
// Ecrase $pu par celui du produit
// Ecrase $desc par celui du produit
// Replaces $fk_unit with the product unit
if (!empty($idprod) && $idprod > 0) {
$prod = new Product($db);
$prod->fetch($idprod);
$label = ((GETPOST('product_label') && GETPOST('product_label') != $prod->label) ? GETPOST('product_label') : '');
// Update if prices fields are defined
/*$tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id);
$tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id);
if (empty($tva_tx)) {
$tva_npr = 0;
}*/
// Price unique per product
$pu_ht = $prod->price;
$pu_ttc = $prod->price_ttc;
$price_min = $prod->price_min;
$price_min_ttc = $prod->price_min_ttc;
$price_base_type = $prod->price_base_type;
if (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
// If price per customer
require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
$prodcustprice = new ProductCustomerPrice($db);
$filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id);
// If a price per customer exist
$pricebycustomerexist = false;
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
foreach ($prodcustprice->lines as $k => $custprice_line) {
if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
$pricebycustomerexist = true;
$pu_ht = price($custprice_line->price);
$pu_ttc = price($custprice_line->price_ttc);
$price_min = price($custprice_line->price_min);
$price_min_ttc = price($custprice_line->price_min_ttc);
$price_base_type = $custprice_line->price_base_type;
/*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx);
if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) {
$tva_tx .= ' ('.$custprice_line->default_vat_code.')';
}
$tva_npr = $custprice_line->recuperableonly;
if (empty($tva_tx)) {
$tva_npr = 0;
}*/
break;
}
}
}
} else {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
if (!$pricebycustomerexist && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
$price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
$price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
$tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
}
if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
$tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
}
}
}
} elseif (getDolGlobalString('PRODUIT_MULTIPRICES') && !empty($object->thirdparty->price_level)) { // If price per segment
$pu_ht = $prod->multiprices[$object->thirdparty->price_level];
$pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level];
$price_min = $prod->multiprices_min[$object->thirdparty->price_level];
$price_min_ttc = $prod->multiprices_min_ttc[$object->thirdparty->price_level];
$price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level];
if (getDolGlobalString('PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL')) { // using this option is a bug. kept for backward compatibility
if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) {
$tva_tx = $prod->multiprices_tva_tx[$object->thirdparty->price_level];
}
if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) {
$tva_npr = $prod->multiprices_recuperableonly[$object->thirdparty->price_level];
}
}
} elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
// If price per customer
require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
$prodcustprice = new ProductCustomerPrice($db);
$filter = array('t.fk_product' => (string) $prod->id, 't.fk_soc' => (string) $object->thirdparty->id);
$result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
if ($result >= 0) {
// If there is some prices specific to the customer
if (count($prodcustprice->lines) > 0) {
$date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
foreach ($prodcustprice->lines as $k => $custprice_line) {
if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
$pu_ht = price($custprice_line->price);
$pu_ttc = price($custprice_line->price_ttc);
$price_min = price($custprice_line->price_min);
$price_min_ttc = price($custprice_line->price_min_ttc);
$price_base_type = $custprice_line->price_base_type;
/*$tva_tx = ($custprice_line->default_vat_code ? $custprice_line->tva_tx.' ('.$custprice_line->default_vat_code.' )' : $custprice_line->tva_tx);
if ($custprice_line->default_vat_code && !preg_match('/\(.*\)/', $tva_tx)) {
$tva_tx .= ' ('.$custprice_line->default_vat_code.')';
}
$tva_npr = $custprice_line->recuperableonly;
if (empty($tva_tx)) {
$tva_npr = 0;
}*/
break;
}
}
}
} else {
setEventMessages($prodcustprice->error, $prodcustprice->errors, 'errors');
}
} elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY')) {
// If price per quantity
if ($prod->prices_by_qty[0]) { // yes, this product has some prices per quantity
// Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
$pqp = GETPOSTINT('pbq');
// Search price into product_price_by_qty from $prod->id
foreach ($prod->prices_by_qty_list[0] as $priceforthequantityarray) {
if ($priceforthequantityarray['rowid'] != $pqp) {
continue;
}
// We found the price
if ($priceforthequantityarray['price_base_type'] == 'HT') {
$pu_ht = $priceforthequantityarray['unitprice'];
} else {
$pu_ttc = $priceforthequantityarray['unitprice'];
}
// Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
break;
}
}
} elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES')) {
// If price per quantity and customer
if ($prod->prices_by_qty[$object->thirdparty->price_level]) { // yes, this product has some prices per quantity
// Search the correct price into loaded array product_price_by_qty using id of array retrieved into POST['pqp'].
$pqp = GETPOSTINT('pbq');
// Search price into product_price_by_qty from $prod->id
foreach ($prod->prices_by_qty_list[$object->thirdparty->price_level] as $priceforthequantityarray) {
if ($priceforthequantityarray['rowid'] != $pqp) {
continue;
}
// We found the price
if ($priceforthequantityarray['price_base_type'] == 'HT') {
$pu_ht = $priceforthequantityarray['unitprice'];
} else {
$pu_ttc = $priceforthequantityarray['unitprice'];
}
// Note: the remise_percent or price by qty is used to set data on form, so we will use value from POST.
break;
}
}
}
$tmpvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
$tmpprodvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', (string) $prod->tva_tx));
// Set unit price to use.
// Force price_base_type to match what the user actually entered, so the total is computed
// from the typed value and not from the converted/rounded value (avoids 0.01 rounding drift).
if (!empty($price_ht) || (string) $price_ht === '0') {
$pu_ht = (float) price2num($price_ht, 'MU');
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
$price_base_type = 'HT';
} elseif (!empty($price_ht_devise) || (string) $price_ht_devise === '0') {
$pu_ht_devise = price2num($price_ht_devise, 'MU');
$pu_ttc_devise = (float) price2num((float) $pu_ht_devise * (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ht = '';
$pu_ttc = '';
$price_base_type = 'HT';
} elseif (!empty($price_ttc) || (string) $price_ttc === '0') {
$pu_ttc = (float) price2num($price_ttc, 'MU');
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
$price_base_type = 'TTC';
} elseif (!empty($price_ttc_devise) || (string) $price_ttc_devise === '0') {
$pu_ttc_devise = (float) price2num($price_ttc_devise, 'MU');
$pu_ht_devise = (float) price2num((float) $pu_ttc_devise / (1 + ((float) $tmpvat / 100)), 'MU');
$pu_ht = '';
$pu_ttc = '';
$price_base_type = 'TTC';
} elseif ($tmpvat != $tmpprodvat) {
// Is this still used ?
if ($price_base_type != 'HT') {
$pu_ht = (float) price2num((float) $pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
} else {
$pu_ttc = (float) price2num((float) $pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
}
}
$desc = '';
// Define output language
if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
$outputlangs = $langs;
$newlang = '';
if (/* empty($newlang) && */GETPOST('lang_id', 'aZ09')) {
$newlang = GETPOST('lang_id', 'aZ09');
}
if (empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$desc = (!empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description;
} else {
$desc = $prod->description;
}
if (getDolGlobalInt('PRODUIT_AUTOFILL_DESC') == 0) {
// 'DoNotAutofillButAutoConcat'
$desc = dol_concatdesc($desc, $line_desc, false, getDolGlobalString('MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION') ? true : false);
} else {
//'AutoFillFormFieldBeforeSubmit' or 'DoNotUseDescriptionOfProdut' => User has already done the modification they want
$desc = $line_desc;
}
// Add custom code and origin country into description
if (!getDolGlobalString('MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE') && (!empty($prod->customcode) || !empty($prod->country_code))) {
$tmptxt = '(';
// Define output language
if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
$outputlangs = $langs;
$newlang = '';
if (/* empty($newlang) && */GETPOST('lang_id', 'alpha')) {
$newlang = GETPOST('lang_id', 'alpha');
}
if (empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
$outputlangs->load('products');
}
if (!empty($prod->customcode)) {
$tmptxt .= $outputlangs->transnoentitiesnoconv("CustomsCode") . ': ' . $prod->customcode;
}
if (!empty($prod->customcode) && !empty($prod->country_code)) {
$tmptxt .= ' - ';
}
if (!empty($prod->country_code)) {
$tmptxt .= $outputlangs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, '', $db, $outputlangs, 0);
}
} else {
if (!empty($prod->customcode)) {
$tmptxt .= $langs->transnoentitiesnoconv("CustomsCode") . ': ' . $prod->customcode;
}
if (!empty($prod->customcode) && !empty($prod->country_code)) {
$tmptxt .= ' - ';
}
if (!empty($prod->country_code)) {
$tmptxt .= $langs->transnoentitiesnoconv("CountryOrigin") . ': ' . getCountry($prod->country_code, '', $db, $langs, 0);
}
}
$tmptxt .= ')';
$desc = dol_concatdesc($desc, $tmptxt);
}
$type = $prod->type;
$fk_unit = $prod->fk_unit;
} else {
$pu_ht = price2num($price_ht, 'MU');
$pu_ttc = price2num($price_ttc, 'MU');
$tva_npr = (preg_match('/\*/', $tva_tx) ? 1 : 0);
$tva_tx = str_replace('*', '', $tva_tx);
if (empty($tva_tx)) {
$tva_npr = 0;
}
$label = (GETPOST('product_label') ? GETPOST('product_label') : '');
$desc = $line_desc;
$type = GETPOST('type');
$fk_unit = GETPOST('units', 'alpha');
$pu_ht_devise = price2num($price_ht_devise, 'MU');
$pu_ttc_devise = price2num($price_ttc_devise, 'MU');
if ($pu_ttc && !$pu_ht) {
$price_base_type = 'TTC';
}
}
$info_bits = 0;
if ($tva_npr) {
$info_bits |= 0x01;
}
// Local Taxes
$localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty, $mysoc, $tva_npr);
$localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty, $mysoc, $tva_npr);
// Margin
$fournprice = (int) (GETPOST('fournprice' . $predef) ? GETPOST('fournprice' . $predef) : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$buyingprice = price2num((GETPOST('buying_price' . $predef) != '' ? GETPOST('buying_price' . $predef) : ''), '', 2); // If buying_price is '0', we must keep this value
$date_start = dol_mktime(GETPOSTINT('date_start' . $predef . 'hour'), GETPOSTINT('date_start' . $predef . 'min'), GETPOSTINT('date_start' . $predef . 'sec'), GETPOSTINT('date_start' . $predef . 'month'), GETPOSTINT('date_start' . $predef . 'day'), GETPOSTINT('date_start' . $predef . 'year'));
$date_end = dol_mktime(GETPOSTINT('date_end' . $predef . 'hour'), GETPOSTINT('date_end' . $predef . 'min'), GETPOSTINT('date_end' . $predef . 'sec'), GETPOSTINT('date_end' . $predef . 'month'), GETPOSTINT('date_end' . $predef . 'day'), GETPOSTINT('date_end' . $predef . 'year'));
// Prepare a price equivalent for minimum price check
$pu_equivalent = $pu_ht;
$pu_equivalent_ttc = $pu_ttc;
$currency_tx = $object->multicurrency_tx;
// Check if we have a foreign currency
// If so, we update the pu_equiv as the equivalent price in base currency
if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
$pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
}
if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
$pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
}
// TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
/*
if ($pu_equivalent) {
$tmp = calcul_price_total(1, $pu_equivalent, 0, $tva_tx, -1, -1, 0, 'HT', $info_bits, $type);
$pu_equivalent_ttc = ...
} else {
$tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $tva_tx, -1, -1, 0, 'TTC', $info_bits, $type);
$pu_equivalent_ht = ...
}
*/
//var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
//var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
//$desc = dol_htmlcleanlastbr($desc);
// Check price is not lower than minimum
if ($usermustrespectpricemin) {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
$mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
$mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
}
}
if (!$error) {
// Insert line
$result = $object->addline($desc, $pu_ht, (float) $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, min($rank, count($object->lines) + 1), 0, GETPOSTINT('fk_parent_line'), (int) $fournprice, $buyingprice, $label, $date_start, $date_end, $array_options, $fk_unit, '', 0, (float) $pu_ht_devise);
if ($result > 0) {
$db->commit();
$ret = $object->fetch($object->id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
unset($_POST['prod_entry_mode']);
unset($_POST['qty']);
unset($_POST['type']);
unset($_POST['remise_percent']);
unset($_POST['price_ht']);
unset($_POST['multicurrency_price_ht']);
unset($_POST['price_ttc']);
unset($_POST['tva_tx']);
unset($_POST['product_ref']);
unset($_POST['product_label']);
unset($_POST['product_desc']);
unset($_POST['fournprice']);
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']);
unset($_POST['date_startday']);
unset($_POST['date_startmonth']);
unset($_POST['date_startyear']);
unset($_POST['date_endhour']);
unset($_POST['date_endmin']);
unset($_POST['date_endsec']);
unset($_POST['date_endday']);
unset($_POST['date_endmonth']);
unset($_POST['date_endyear']);
header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);
exit();
} else {
$db->rollback();
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
} elseif ($action == 'addline' && $usercancreate && (
(GETPOST('submitforallmargins', 'alpha') && GETPOST('marginforalllines', 'alpha') !== '') ||
(GETPOST('submitforallmark', 'alpha') && GETPOST('markforalllines', 'alpha') !== '')
)) {
$outlangs = $langs;
// Define margin
$margin_rate = GETPOSTISSET('marginforalllines') ? GETPOST('marginforalllines', 'int') : '';
$mark_rate = GETPOSTISSET('markforalllines') ? GETPOST('markforalllines', 'int') : '';
foreach ($object->lines as &$line) {
if ($line->subprice > 0) {
if ($line->special_code == SUBTOTALS_SPECIAL_CODE) {
continue;
}
$subprice_multicurrency = $line->subprice;
if (is_numeric($margin_rate) && $margin_rate > 0) {
$line->subprice = (float) price2num((float) $line->pa_ht * (1 + (float) $margin_rate / 100), 'MU');
} elseif (is_numeric($mark_rate) && $mark_rate > 0) {
$line->subprice = (float) ($line->pa_ht / (1 - ((float) $mark_rate / 100)));
} else {
$line->subprice = (float) $line->pa_ht;
}
if ($line->fk_product > 0) {
$prod = new Product($db);
$res = $prod->fetch($line->fk_product);
if ($res > 0) {
if ($prod->price_min > $line->subprice) {
$price_subprice = price($line->subprice, 0, $outlangs, 1, -1, -1, 'auto');
$price_price_min = price($prod->price_min, 0, $outlangs, 1, -1, -1, 'auto');
setEventMessages($prod->ref . ' - ' . $prod->label . ' (' . $price_subprice . ' < ' . $price_price_min . ' ' . strtolower($langs->trans("MinPrice")) . ')' . "\n", null, 'warnings');
} else {
setEventMessages($prod->error, $prod->errors, 'errors');
}
} else {
setEventMessages($prod->error, $prod->errors, 'errors');
}
}
// Manage $line->subprice and $line->multicurrency_subprice
$multicurrency_subprice = (float) $line->subprice * $line->multicurrency_subprice / $subprice_multicurrency;
// Update DB
$result = $object->updateline($line->id, $line->subprice, $line->qty, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, $line->desc, 'HT', $line->info_bits, $line->special_code, $line->fk_parent_line, 0, $line->fk_fournprice, $line->pa_ht, $line->label, $line->product_type, $line->date_start, $line->date_end, $line->array_options, $line->fk_unit, $multicurrency_subprice);
// Update $object with new margin info
if ($result > 0) {
if (is_numeric($margin_rate) && empty($mark_rate)) {
$line->marge_tx = $margin_rate;
} elseif (is_numeric($mark_rate) && empty($margin_rate)) {
$line->marque_tx = $mark_rate;
}
$line->total_ht = $line->qty * (float) $line->subprice;
$line->total_tva = $line->tva_tx * $line->qty * (float) $line->subprice;
$line->total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $line->subprice;
// Manage $line->subprice and $line->multicurrency_subprice
$line->multicurrency_total_ht = $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
$line->multicurrency_total_tva = $line->tva_tx * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
$line->multicurrency_total_ttc = (1 + $line->tva_tx) * $line->qty * (float) $subprice_multicurrency * $line->multicurrency_subprice / $line->subprice;
// Used previous $line->subprice and $line->multicurrency_subprice above, now they can be set to their new values
$line->multicurrency_subprice = $multicurrency_subprice;
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
}
}
} elseif ($action == 'updatetitleline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
// Handling updating a title line for subtotals module
$langs->load('subtotals');
$desc = GETPOST('line_desc', 'alphanohtml') ?? $langs->trans("Title");
$depth = GETPOSTINT('line_depth') ?? 1;
$subtotal_options = array();
foreach (Propal::$TITLE_OPTIONS as $option) {
$value = GETPOST($option, 'alphanohtml');
if ($value) {
$subtotal_options[$option] = $value == 'on' ? 1 : $value;
}
}
// Update line
$result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
if ($result >= 0) {
if ($result == 0) {
setEventMessages($object->error, $object->errors, 'warnings');
}
$ret = $object->fetch($object->id); // Reload to get new records
$object->fetch_thirdparty();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'updatesubtotalline' && GETPOSTISSET("save") && $usercancreate && !GETPOST('cancel', 'alpha')) {
// Handling updating a subtotal line for subtotals module
$langs->load('subtotals');
$desc = GETPOST('line_desc', 'alphanohtml');
$depth = GETPOSTINT('line_depth');
$subtotal_options = array();
foreach (Propal::$SUBTOTAL_OPTIONS as $option) {
$value = GETPOST($option, 'alphanohtml');
if ($value) {
$subtotal_options[$option] = $value == 'on' ? 1 : $value;
}
}
// Update line
$result = $object->updateSubtotalLine($langs, GETPOSTINT('lineid'), $desc, $depth, $subtotal_options);
if ($result > 0) {
$ret = $object->fetch($object->id); // Reload to get new records
$object->fetch_thirdparty();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
$newlang = GETPOST('lang_id', 'alpha');
if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
$newlang = $object->thirdparty->default_lang;
}
if (!empty($newlang)) {
$outputlangs = new Translate("", $conf);
$outputlangs->setDefaultLang($newlang);
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
} elseif ($action == 'updateline' && $usercancreate && GETPOST('save')) {
// Update a line
// Clean parameters
$description = dol_htmlcleanlastbr(GETPOST('product_desc', 'restricthtml'));
// Define info_bits
$info_bits = 0;
if (preg_match('/\*/', GETPOST('tva_tx'))) {
$info_bits |= 0x01;
}
// Define vat_rate
$vat_rate = (GETPOST('tva_tx') ? GETPOST('tva_tx', 'alpha') : 0);
$vat_rate = str_replace('*', '', $vat_rate);
$localtax1_rate = get_localtax($vat_rate, 1, $object->thirdparty, $mysoc);
$localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty, $mysoc);
$pu_ht = price2num(GETPOST('price_ht'), '', 2);
$pu_ttc = price2num(GETPOST('price_ttc'), '', 2);
// Add buying price
$fournprice = (int) (GETPOST('fournprice') ? GETPOST('fournprice') : ''); // This can be id of supplier price, or 'pmpprice' or 'costprice', or 'inputprice', we force to keep ID only
$buyingprice = price2num((GETPOST('buying_price') != '' ? GETPOST('buying_price') : ''), '', 2); // If buying_price is '0', we must keep this value
$pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), '', 2);
$pu_ttc_devise = price2num(GETPOST('multicurrency_subprice_ttc'), '', 2);
$date_start = dol_mktime(GETPOSTINT('date_starthour'), GETPOSTINT('date_startmin'), GETPOSTINT('date_startsec'), GETPOSTINT('date_startmonth'), GETPOSTINT('date_startday'), GETPOSTINT('date_startyear'));
$date_end = dol_mktime(GETPOSTINT('date_endhour'), GETPOSTINT('date_endmin'), GETPOSTINT('date_endsec'), GETPOSTINT('date_endmonth'), GETPOSTINT('date_endday'), GETPOSTINT('date_endyear'));
$remise_percent = price2num(GETPOST('remise_percent'), '', 2);
if (empty($remise_percent)) {
$remise_percent = 0;
}
// Prepare a price equivalent for minimum price check
$pu_equivalent = $pu_ht;
$pu_equivalent_ttc = $pu_ttc;
$currency_tx = $object->multicurrency_tx;
// Check if we have a foreign currency
// If so, we update the pu_equiv as the equivalent price in base currency
if ($pu_ht == '' && $pu_ht_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
$pu_equivalent = (float) $pu_ht_devise / (float) $currency_tx;
}
if ($pu_ttc == '' && $pu_ttc_devise != '' && $currency_tx != '' && !empty((float) $currency_tx)) {
$pu_equivalent_ttc = (float) $pu_ttc_devise / (float) $currency_tx;
}
// TODO $pu_equivalent or $pu_equivalent_ttc must be calculated from the one not null taking into account all taxes
/*
if ($pu_equivalent) {
$tmp = calcul_price_total(1, $pu_equivalent, 0, $vat_rate, -1, -1, 0, 'HT', $info_bits, $type);
$pu_equivalent_ttc = ...
} else {
$tmp = calcul_price_total(1, $pu_equivalent_ttc, 0, $vat_rate, -1, -1, 0, 'TTC', $info_bits, $type);
$pu_equivalent_ht = ...
}
*/
// Extrafields
$extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line);
$array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
// Unset extrafield
if (is_array($extralabelsline)) {
// Get extra fields
foreach ($extralabelsline as $key => $value) {
unset($_POST["options_" . $key]);
}
}
// Define special_code for special lines
$special_code = GETPOSTINT('special_code');
if (!GETPOST('qty')) {
$special_code = 3;
}
// The form JS clears the other field when the user edits one of them: only the modified field is filled.
// When both fields are submitted, the user did not change the price - we must preserve the original
// storage mode of the line, otherwise a no-op save would shift the total by rounding.
$pu = $pu_ht;
$price_base_type = 'HT';
if (empty($pu_ht) && !empty($pu_ttc)) {
$pu = $pu_ttc;
$price_base_type = 'TTC';
} elseif (!empty($pu_ht) && !empty($pu_ttc)) {
foreach ($object->lines as $line_obj) {
if ($line_obj->id == GETPOSTINT('lineid')) {
if ($line_obj->wasEnteredIncludingTax()) {
$pu = $pu_ttc;
$price_base_type = 'TTC';
}
break;
}
}
}
// Check minimum price
$productid = GETPOSTINT('productid');
if (!empty($productid)) {
$product = new Product($db);
$res = $product->fetch($productid);
$type = $product->type;
$label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label') : '');
$price_min = $product->price_min;
if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
$price_min = $product->multiprices_min[$object->thirdparty->price_level];
}
$price_min_ttc = $product->price_min_ttc;
if ((getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) && !empty($object->thirdparty->price_level)) {
$price_min_ttc = $product->multiprices_min_ttc[$object->thirdparty->price_level];
}
//var_dump(price2num($price_min)); var_dump(price2num($pu_ht)); var_dump($remise_percent);
//var_dump(price2num($price_min_ttc)); var_dump(price2num($pu_ttc)); var_dump($remise_percent);exit;
// Check price is not lower than minimum
if ($usermustrespectpricemin) {
if ($pu_equivalent && $price_min && (((float) price2num($pu_equivalent) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min)) && $price_base_type == 'HT') {
$mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
$action = 'editline';
} elseif ($pu_equivalent_ttc && $price_min_ttc && (((float) price2num($pu_equivalent_ttc) * (1 - (float) $remise_percent / 100)) < (float) price2num($price_min_ttc)) && $price_base_type == 'TTC') {
$mesg = $langs->trans("CantBeLessThanMinPriceInclTax", price(price2num($price_min_ttc, 'MU'), 0, $langs, 0, 0, -1, $conf->currency));
setEventMessages($mesg, null, 'errors');
$error++;
$action = 'editline';
}
}
} else {
$type = GETPOST('type');
$label = (GETPOST('product_label') ? GETPOST('product_label') : '');
// Check parameters
if (GETPOST('type') < 0) {
setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), null, 'errors');
$error++;
}
}
if (!$error) {
$db->begin();
if (!$user->hasRight('margins', 'creer')) {
foreach ($object->lines as &$line) {
if ($line->id == GETPOSTINT('lineid')) {
$fournprice = $line->fk_fournprice;
$buyingprice = (string) $line->pa_ht; // do not convert to float here, it breaks the functioning of $pa_ht_isemptystring
break;
}
}
}
$qty = price2num(GETPOST('qty', 'alpha'), 'MS');
$result = $object->updateline(GETPOSTINT('lineid'), (float) $pu, (float) $qty, (float) $remise_percent, $vat_rate, $localtax1_rate, $localtax2_rate, $description, $price_base_type, $info_bits, $special_code, GETPOSTINT('fk_parent_line'), 0, (int) $fournprice, $buyingprice, $label, $type, $date_start, $date_end, $array_options, GETPOSTINT("units"), (float) $pu_ht_devise);
if ($result >= 0) {
$db->commit();
if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
// Define output language
$outputlangs = $langs;
if (getDolGlobalInt('MAIN_MULTILANGS')) {
$outputlangs = new Translate("", $conf);
$newlang = (GETPOST('lang_id', 'aZ09') ? GETPOST('lang_id', 'aZ09') : $object->thirdparty->default_lang);
$outputlangs->setDefaultLang($newlang);
}
$ret = $object->fetch($id); // Reload to get new records
if ($ret > 0) {
$object->fetch_thirdparty();
}
$object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
}
unset($_POST['qty']);
unset($_POST['type']);
unset($_POST['productid']);
unset($_POST['remise_percent']);
unset($_POST['price_ht']);
unset($_POST['multicurrency_price_ht']);
unset($_POST['price_ttc']);
unset($_POST['tva_tx']);
unset($_POST['product_ref']);
unset($_POST['product_label']);
unset($_POST['product_desc']);
unset($_POST['fournprice']);
unset($_POST['buying_price']);
unset($_POST['date_starthour']);
unset($_POST['date_startmin']);
unset($_POST['date_startsec']);
unset($_POST['date_startday']);
unset($_POST['date_startmonth']);
unset($_POST['date_startyear']);
unset($_POST['date_endhour']);
unset($_POST['date_endmin']);
unset($_POST['date_endsec']);
unset($_POST['date_endday']);
unset($_POST['date_endmonth']);
unset($_POST['date_endyear']);
} else {
$db->rollback();
setEventMessages($object->error, $object->errors, 'errors');
}
}
} elseif ($action == 'updateline' && $usercancreate && GETPOST('cancel', 'alpha')) {
header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To re-display card in edit mode
exit();
} elseif ($action == 'classin' && $usercancreate) {
// Set project
$object->setProject(GETPOSTINT('projectid'));
} elseif ($action == 'setavailability' && $usercancreate) {
// Delivery time
$result = $object->set_availability($user, GETPOSTINT('availability_id'));
} elseif ($action == 'setdemandreason' && $usercancreate) {
// Origin of the commercial proposal
$result = $object->set_demand_reason($user, GETPOSTINT('demand_reason_id'));
} elseif ($action == 'setconditions' && $usercancreate) {
// Terms of payment
$result = $object->setPaymentTerms(GETPOSTINT('cond_reglement_id'), GETPOSTFLOAT('cond_reglement_id_deposit_percent'));
} elseif ($action == 'setmode' && $usercancreate) {
// Payment choice
$result = $object->setPaymentMethods(GETPOSTINT('mode_reglement_id'));
} elseif ($action == 'setmulticurrencycode' && $usercancreate) {
// Multicurrency Code
$result = $object->setMulticurrencyCode(GETPOST('multicurrency_code', 'alpha'));
} elseif ($action == 'setmulticurrencyrate' && $usercancreate) {
// Multicurrency rate
$result = $object->setMulticurrencyRate(GETPOSTFLOAT('multicurrency_tx'), GETPOSTINT('calculation_mode'));
} elseif ($action == 'setbankaccount' && $usercancreate) {
// bank account
$result = $object->setBankAccount(GETPOSTINT('fk_account'));
} elseif ($action == 'setshippingmethod' && $usercancreate) {
// shipping method
$result = $object->setShippingMethod(GETPOSTINT('shipping_method_id'));
} elseif ($action == 'setwarehouse' && $usercancreate) {
// warehouse
$result = $object->setWarehouse(GETPOSTINT('warehouse_id'));
} elseif ($action == 'update_extras' && $permissiontoeditextra) {
$object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
$attribute_name = GETPOST('attribute', 'aZ09');
// Fill array 'array_options' with data from update form
$result = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
if ($result < 0) {
$error++;
}
if (!$error) {
$result = $object->updateExtraField($attribute_name, 'PROPAL_MODIFY');
if ($result < 0) {
setEventMessages($object->error, $object->errors, 'errors');
$error++;
}
}
if ($error) {
$action = 'edit_extras';
}
}
if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
if ($action == 'addcontact' && $usercancreate) {
$result = 0;
if ($object->id > 0) {
$contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid'));
$typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type'));
$result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09'));
}
if ($result >= 0) {
header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
exit();
} else {
if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') {
$langs->load("errors");
setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors');
} else {
setEventMessages($object->error, $object->errors, 'errors');
}
}
} elseif ($action == 'swapstatut' && $usercancreate) {
// Toggle the status of a contact
if ($object->fetch($id) > 0) {
$result = $object->swapContactStatus(GETPOSTINT('ligne'));
} else {
dol_print_error($db);
}
} elseif ($action == 'deletecontact' && $usercancreate) {
// Delete a contact
$object->fetch($id);
$result = $object->delete_contact($lineid);
if ($result >= 0) {
header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
exit();
} else {
dol_print_error($db);
}
}
}
// Actions to build doc
$upload_dir = !empty($conf->propal->multidir_output[$object->entity ?? $conf->entity]) ? $conf->propal->multidir_output[$object->entity ?? $conf->entity] : $conf->propal->dir_output;
$permissiontoadd = $usercancreate;
include DOL_DOCUMENT_ROOT . '/core/actions_builddoc.inc.php';
}
/*
* View
*/
$form = new Form($db);
$formfile = new FormFile($db);
$formpropal = new FormPropal($db);
$formmargin = new FormMargin($db);
$formproject = null;
if (isModEnabled('project')) {
$formproject = new FormProjets($db);
}
$title = $object->ref . " - " . $langs->trans('Card');
if ($action == 'create') {
$title = $langs->trans("NewPropal");
}
$help_url = 'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos|DE:Modul_Angebote';
llxHeader('', $title, $help_url);
$now = dol_now();
// Add new proposal
if ($action == 'create') {
$currency_code = getDolCurrency();
print load_fiche_titre($langs->trans("NewProp"), '', 'propal');
$soc = new Societe($db);
if ($socid > 0) {
$res = $soc->fetch($socid);
}
$cond_reglement_id = GETPOSTINT('cond_reglement_id');
$deposit_percent = GETPOSTFLOAT('cond_reglement_id_deposit_percent');
$mode_reglement_id = GETPOSTINT('mode_reglement_id');
$fk_account = GETPOSTINT('fk_account');
$datepropal = (getDolGlobalString('MAIN_DO_NOT_AUTOFILL_DATE_PROPOSAL') ? -1 : ''); // By default '' so we will autofill date. -1 means keep empty.
// Load objectsrc
$objectsrc = null;
if (!empty($origin) && !empty($originid)) {
// Parse element/subelement (ex: project_task)
$element = $subelement = $origin;
$regs = array();
if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) {
$element = $regs[1];
$subelement = $regs[2];
}
if ($element == 'project') {
$projectid = $originid;
// Fetch project and thirdparty
$project = new Project($db);
$project->fetch($projectid);
if ($project->socid > 0) {
$soc = new Societe($db);
$soc->fetch($project->socid);
}
} else {
// For compatibility
if ($element == 'order' || $element == 'commande') {
$element = $subelement = 'commande';
}
if ($element == 'propal') {
$element = 'comm/propal';
$subelement = 'propal';
}
if ($element == 'contract') {
$element = $subelement = 'contrat';
}
if ($element == 'shipping') {
$element = $subelement = 'expedition';
}
dol_include_once('/' . $element . '/class/' . $subelement . '.class.php');
$classname = ucfirst($subelement);
$objectsrc = new $classname($db);
'@phan-var-force Commande|Propal|Contrat|Expedition $objectsrc'; // Can be other class, but CommonObject is too generic
/** @var Commande|Propal|Contrat|Expedition $objectsrc */
$objectsrc->fetch($originid);
if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) {
$objectsrc->fetch_lines();
}
$objectsrc->fetch_thirdparty();
$projectid = (int) $objectsrc->fk_project;
$ref_client = (!empty($objectsrc->ref_client) ? $objectsrc->ref_client : '');
$soc = $objectsrc->thirdparty;
$cond_reglement_id = (!empty($objectsrc->cond_reglement_id) ? $objectsrc->cond_reglement_id : (!empty($soc->cond_reglement_id) ? $soc->cond_reglement_id : 0));
$mode_reglement_id = (!empty($objectsrc->mode_reglement_id) ? $objectsrc->mode_reglement_id : (!empty($soc->mode_reglement_id) ? $soc->mode_reglement_id : 0));
$warehouse_id = (!empty($objectsrc->warehouse_id) ? $objectsrc->warehouse_id : (!empty($soc->warehouse_id) ? $soc->warehouse_id : -1));
// Replicate extrafields
$objectsrc->fetch_optionals();
$object->array_options = $objectsrc->array_options;
if (isModEnabled("multicurrency")) {
if (!empty($objectsrc->multicurrency_code)) {
$currency_code = $objectsrc->multicurrency_code;
}
if (getDolGlobalString('MULTICURRENCY_USE_ORIGIN_TX') && !empty($objectsrc->multicurrency_tx)) {
$currency_tx = $objectsrc->multicurrency_tx;
}
}
}
}
// Load default values from thirdparty
if (!empty($soc)) {
$cond_reglement_id = empty($soc->cond_reglement_id) ? $cond_reglement_id : $soc->cond_reglement_id;
$deposit_percent = empty($soc->deposit_percent) ? $deposit_percent : $soc->deposit_percent;
$mode_reglement_id = empty($soc->mode_reglement_id) ? $mode_reglement_id : $soc->mode_reglement_id;
$fk_account = empty($soc->fk_account) ? $fk_account : $soc->fk_account;
$shipping_method_id = $soc->shipping_method_id;
$warehouse_id = !empty($soc->fk_warehouse) ? $soc->fk_warehouse : $warehouse_id;
$remise_percent = $soc->remise_percent;
if (isModEnabled("multicurrency") && !empty($soc->multicurrency_code)) {
$currency_code = $soc->multicurrency_code;
}
}
// If form was posted (but error returned), we must reuse the value posted in priority (standard Dolibarr behaviour)
if (!GETPOST('changecompany')) {
if (GETPOSTISSET('cond_reglement_id')) {
$cond_reglement_id = GETPOSTINT('cond_reglement_id');
}
if (GETPOSTISSET('deposit_percent')) {
$deposit_percent = price2num(GETPOST('deposit_percent', 'alpha'));
}
if (GETPOSTISSET('mode_reglement_id')) {
$mode_reglement_id = GETPOSTINT('mode_reglement_id');
}
if (GETPOSTISSET('fk_account')) {
$fk_account = GETPOSTINT('fk_account');
}
if (GETPOSTISSET('shipping_method_id')) {
$shipping_method_id = GETPOSTINT('shipping_method_id');
}
}
// Warehouse default if null
if ($soc->fk_warehouse > 0) {
$warehouse_id = $soc->fk_warehouse;
}
if (isModEnabled('stock') && $warehouse_id < 0 && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE')) {
$warehouse_id = getDolGlobalString('MAIN_DEFAULT_WAREHOUSE');
}
if (empty($object->warehouse_id) && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && !empty($user->fk_warehouse)) {
$warehouse_id = $user->fk_warehouse;
}
}
print '<form name="addprop" action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
print '<input type="hidden" name="token" value="' . newToken() . '">';
print '<input type="hidden" name="action" value="add">';
print '<input type="hidden" name="changecompany" value="0">'; // will be set to 1 by javascript so we know post is done after a company change
print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
if ($origin != 'project' && $originid) {
print '<input type="hidden" name="origin" value="' . $origin . '">';
print '<input type="hidden" name="originid" value="' . $originid . '">';
if ($origin == 'contrat' && !empty($renewal)) {
print '<input type="hidden" name="renewal" value="' . $renewal . '">';
}
} elseif ($origin == 'project' && !empty($projectid)) {
print '<input type="hidden" name="projectid" value="' . $projectid . '">';
}
print dol_get_fiche_head();
// Call Hook tabContentCreateProposal
$parameters = array();
// Note that $action and $object may be modified by hook
$reshook = $hookmanager->executeHooks('tabContentCreateProposal', $parameters, $object, $action);
if (empty($reshook)) {
print '<table class="border centpercent">';
// Reference
//print '<tr class="field_ref"><td class="titlefieldcreate fieldrequired">' . $langs->trans('Ref') . '</td><td class="valuefieldcreate">' . $langs->trans("Draft") . '</td></tr>';
// Third party
print '<tr class="field_socid">';
print '<td class="titlefieldcreate fieldrequired">' . $langs->trans('Customer') . '</td>';
$shipping_method_id = 0;
$warehouse_id = 0;
if ($socid > 0) {
print '<td class="valuefieldcreate">';
print $soc->getNomUrl(1, 'customer');
print '<input type="hidden" name="socid" value="' . $soc->id . '">';
print '</td>';
if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
$shipping_method_id = $soc->shipping_method_id;
}
} else {
print '<td class="valuefieldcreate">';
$filter = '((s.client:IN:1,2,3) AND (s.status:=:1))';
print img_picto('', 'company', 'class="pictofixedwidth"');
print $form->select_company('', 'socid', $filter, 'SelectThirdParty', 1, 0, array(), 0, 'minwidth300 maxwidth500 widthcentpercentminusxx');
// reload page to retrieve customer information
if (!getDolGlobalString('RELOAD_PAGE_ON_CUSTOMER_CHANGE_DISABLED')) {
print '<script>
$(document).ready(function() {
$("#socid").change(function() {
console.log("We have changed the company - Reload page");
var socid = $(this).val();
// reload page
$("input[name=action]").val("create");
$("input[name=changecompany]").val("1");
$("form[name=addprop]").submit();
});
});
</script>';
}
print ' <a href="' . DOL_URL_ROOT . '/societe/card.php?action=create&prospect=3&fournisseur=0&backtopage=' . urlencode($_SERVER["PHP_SELF"] . '?action=create') . '"><span class="fa fa-plus-circle valignmiddle paddingleft" title="' . $langs->trans("AddThirdParty") . '"></span></a>';
print '</td>';
}
print '</tr>' . "\n";
// Reference of proposal on customer side
if (getDolGlobalString('MAIN_ASK_CUSTOMER_REF_OF_PROPOSAL_AT_CREATION')) {
print '<tr class="field_ref_client"><td class="titlefieldcreate">';
print $form->textwithpicto($langs->trans('RefCustomer'), $langs->trans('RefOfOnCustomerSide', $langs->transnoentitiesnoconv("Proposal")));
print '</td><td class="valuefieldcreate">';
print '<input type="text" name="ref_client" value="' . (!empty($ref_client) ? $ref_client : GETPOST('ref_client')) . '"></td>';
print '</tr>';
}
if ($socid > 0) {
// Contacts (ask contact only if thirdparty already defined).
print '<tr class="field_contactid"><td class="titlefieldcreate">' . $langs->trans("DefaultContact") . '</td><td class="valuefieldcreate">';
print img_picto('', 'contact', 'class="pictofixedwidth"');
//print $form->selectcontacts($soc->id, $contactid, 'contactid', 1, '', '', 0, 'minwidth300 widthcentpercentminusx');
print $form->select_contact($soc->id, $contactid, 'contactid', 1, '', '', 1, 'maxwidth300 widthcentpercentminusx', true);
print '</td></tr>';
// Third party discounts info line
print '<tr class="field_discount_info"><td class="titlefieldcreate">' . $langs->trans('Discounts') . '</td><td class="valuefieldcreate">';
$absolute_discount = $soc->getAvailableDiscounts();
$thirdparty = $soc;
$discount_type = 0;
$backtopage = $_SERVER["PHP_SELF"] . '?socid=' . $thirdparty->id . '&action=' . $action . '&origin=' . urlencode((string) (GETPOST('origin'))) . '&originid=' . urlencode((string) (GETPOSTINT('originid')));
include DOL_DOCUMENT_ROOT . '/core/tpl/object_discounts.tpl.php';
print '</td></tr>';
}
$newdatepropal = dol_mktime(0, 0, 0, GETPOSTINT('remonth'), GETPOSTINT('reday'), GETPOSTINT('reyear'), 'tzserver');
// Date
print '<tr class="field_addprop"><td class="titlefieldcreate fieldrequired">' . $langs->trans('Date') . '</td><td class="valuefieldcreate">';
print img_picto('', 'action', 'class="pictofixedwidth"');
print $form->selectDate($newdatepropal ? $newdatepropal : $datepropal, '', 0, 0, 0, "addprop", 1, 1);
print '</td></tr>';
// Validaty duration
print '<tr class="field_duree_validitee"><td class="titlefieldcreate fieldrequired">' . $langs->trans("ValidityDuration") . '</td><td class="valuefieldcreate">' . img_picto('', 'clock', 'class="pictofixedwidth"') . '<input name="duree_validite" class="width50" value="' . (GETPOSTISSET('duree_validite') ? GETPOST('duree_validite', 'alphanohtml') : getDolGlobalString('PROPALE_VALIDITY_DURATION')) . '"> ' . $langs->trans("days") . '</td></tr>';
// Terms of payment
print '<tr class="field_cond_reglement_id"><td class="nowrap">' . $langs->trans('PaymentConditionsShort') . '</td><td>';
print img_picto('', 'payment', 'class="pictofixedwidth"');
// at last resort we take the payment term id which may be filled by default values set (if not getpostisset)
print $form->getSelectConditionsPaiements((int) $cond_reglement_id, 'cond_reglement_id', 1, 1, 0, '', $deposit_percent);
print '</td></tr>';
// Mode of payment
print '<tr class="field_mode_reglement_id"><td class="titlefieldcreate">' . $langs->trans('PaymentMode') . '</td><td class="valuefieldcreate">';
print img_picto('', 'bank', 'class="pictofixedwidth"');
print $form->select_types_paiements((string) $mode_reglement_id, 'mode_reglement_id', 'CRDT', 0, 1, 0, 0, 1, 'maxwidth200 widthcentpercentminusx', 1);
print '</td></tr>';
// Bank Account
if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
print '<tr class="field_fk_account"><td class="titlefieldcreate">' . $langs->trans('BankAccount') . '</td><td class="valuefieldcreate">';
print img_picto('', 'bank_account', 'class="pictofixedwidth"') . $form->select_comptes((int) $fk_account, 'fk_account', 0, '', 1, '', 0, 'maxwidth200 widthcentpercentminusx', 1);
print '</td></tr>';
}
// Source / Channel - What trigger creation
print '<tr class="field_demand_reason_id"><td class="titlefieldcreate">' . $langs->trans('Source') . '</td><td class="valuefieldcreate">';
print img_picto('', 'question', 'class="pictofixedwidth"');
$form->selectInputReason((GETPOSTISSET('demand_reason_id') ? GETPOSTINT('demand_reason_id') : ''), 'demand_reason_id', "SRC_PROP", 1, 'maxwidth200 widthcentpercentminusx');
print '</td></tr>';
// Shipping Method
if (isModEnabled("shipping")) {
if (getDolGlobalString('SOCIETE_ASK_FOR_SHIPPING_METHOD') && !empty($soc->shipping_method_id)) {
$shipping_method_id = $soc->shipping_method_id;
}
print '<tr class="field_shipping_method_id"><td class="titlefieldcreate">' . $langs->trans('SendingMethod') . '</td><td class="valuefieldcreate">';
print img_picto('', 'dolly', 'class="pictofixedwidth"');
$form->selectShippingMethod((string) $shipping_method_id, 'shipping_method_id', '', 1, '', 0, 'maxwidth200 widthcentpercentminusx');
print '</td></tr>';
}
$formproduct = null;
// Warehouse
if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
$formproduct = new FormProduct($db);
print '<tr class="field_warehouse_id"><td class="titlefieldcreate">' . $langs->trans('Warehouse') . '</td><td class="valuefieldcreate">';
print img_picto('', 'stock', 'class="pictofixedwidth"') . $formproduct->selectWarehouses((int) $warehouse_id, 'warehouse_id', '', 1, 0, 0, '', 0, 0, array(), 'maxwidth500 widthcentpercentminusxx');
print '</td></tr>';
}
// Delivery delay
print '<tr class="field_availability_id"><td class="titlefieldcreate">' . $langs->trans('AvailabilityPeriod');
if (isModEnabled('order')) {
print ' (' . $langs->trans('AfterOrder') . ')';
}
print '</td><td class="valuefieldcreate">';
print img_picto('', 'clock', 'class="pictofixedwidth"');
print $form->selectAvailabilityDelay((GETPOSTISSET('availability_id') ? GETPOSTINT('availability_id') : ''), 'availability_id', '', 1, 'maxwidth200 widthcentpercentminusx', 1);
print '</td></tr>';
// Delivery date (or manufacturing)
print '<tr class="field_date_livraison"><td class="titlefieldcreate">' . $langs->trans("DeliveryDate") . '</td>';
print '<td class="valuefieldcreate">';
print img_picto('', 'action', 'class="pictofixedwidth"');
if (is_numeric(getDolGlobalString('DATE_LIVRAISON_WEEK_DELAY'))) { // If value set to 0 or a num, not empty
$tmpdte = time() + (7 * getDolGlobalInt('DATE_LIVRAISON_WEEK_DELAY') * 24 * 60 * 60);
$syear = date("Y", $tmpdte);
$smonth = date("m", $tmpdte);
$sday = date("d", $tmpdte);
print $form->selectDate($syear . "-" . $smonth . "-" . $sday, 'date_livraison', 0, 0, 0, "addprop");
} else {
$tmp_date_delivery = GETPOST('date_delivery') ?: -1;
print $form->selectDate($tmp_date_delivery, 'date_livraison', 0, 0, 0, "addprop", 1, 1);
}
print '</td></tr>';
// Project
if (isModEnabled('project') && is_object($formproject)) {
$langs->load("projects");
print '<tr class="field_projectid">';
print '<td class="titlefieldcreate">'.$langs->trans("Project").'</td><td class="valuefieldcreate">';
print img_picto('', 'project', 'class="pictofixedwidth"').$formproject->select_projects((($soc->id > 0 && !getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_CUSTOMERS')) ? $soc->id : -1), (string) $projectid, 'projectid', 0, 0, 1, 1, 0, 0, 0, '', 1, 0, 'maxwidth500 widthcentpercentminusxx');
print ' <a href="'.DOL_URL_ROOT.'/projet/card.php?socid='.$soc->id.'&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'"><span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddProject").'"></span></a>';
print '</td>';
print '</tr>';
}
// Incoterms
if (isModEnabled('incoterm')) {
print '<tr class="field_incoterm_id">';
print '<td class="titlefieldcreate"><label for="incoterm_id">' . $form->textwithpicto($langs->trans("IncotermLabel"), $soc->label_incoterms, 1) . '</label></td>';
print '<td class="valuefieldcreate maxwidthonsmartphone">';
print img_picto('', 'incoterm', 'class="pictofixedwidth"');
print $form->select_incoterms((!empty($soc->fk_incoterms) ? $soc->fk_incoterms : ''), (!empty($soc->location_incoterms) ? $soc->location_incoterms : ''));
print '</td></tr>';
}
if (isModEnabled('category')) {
// Categories
print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
print $form->selectCategories(Categorie::TYPE_PROPOSAL, 'categories', $object);
print "</td></tr>";
}
// Template to use by default
include_once DOL_DOCUMENT_ROOT . '/core/modules/propale/modules_propale.php';
$list = ModelePDFPropales::liste_modeles($db);
if (is_array($list) && count($list) > 0) {
print '<tr class="field_model">';
print '<td class="titlefieldcreate">' . $langs->trans("DefaultModel") . '</td>';
print '<td class="valuefieldcreate">';
print img_picto('', 'pdf', 'class="pictofixedwidth"');
$preselected = getDolGlobalString('PROPALE_ADDON_PDF_ODT_DEFAULT', getDolGlobalString("PROPALE_ADDON_PDF"));
print $form->selectarray('model', $list, $preselected, 0, 0, 0, '', 0, 0, 0, '', 'maxwidth200 widthcentpercentminusx', 1);
print "</td></tr>";
}
// Multicurrency
if (isModEnabled("multicurrency")) {
print '<tr class="field_currency">';
print '<td class="titlefieldcreate">' . $form->editfieldkey('Currency', 'multicurrency_code', '', $object, 0) . '</td>';
print '<td class="valuefieldcreate maxwidthonsmartphone">';
print img_picto('', 'currency', 'class="pictofixedwidth"') . $form->selectMultiCurrency(((GETPOSTISSET('multicurrency_code') && !GETPOST('changecompany')) ? GETPOST('multicurrency_code') : $currency_code), 'multicurrency_code', 0, '', false, 'maxwidth200 widthcentpercentminusx');
print '</td></tr>';
}
// Public note
print '<tr class="field_note_public">';
print '<td class="titlefieldcreate tdtop">' . $langs->trans('NotePublic') . '</td>';
print '<td class="valuefieldcreate">';
$note_public = GETPOST('note_public', 'restricthtml');
if (!GETPOSTISSET('note_public') && empty($note_public) && !empty($objectsrc)) {
$note_public = $objectsrc->note_public;
}
$doleditor = new DolEditor('note_public', (string) $note_public, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
print $doleditor->Create(1);
// Private note
if (empty($user->socid)) {
print '<tr class="field_note_private">';
print '<td class="titlefieldcreate tdtop">' . $langs->trans('NotePrivate') . '</td>';
print '<td class="valuefieldcreate">';
$note_private = GETPOST('note_private', 'restricthtml');
if (!GETPOSTISSET('note_private') && empty($note_private) && !empty($objectsrc)) {
$note_private = $objectsrc->note_private;
}
$doleditor = new DolEditor('note_private', (string) $note_private, '', 80, 'dolibarr_notes', 'In', false, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
print $doleditor->Create(1);
// print '<textarea name="note_private" wrap="soft" cols="70" rows="'.ROWS_3.'">'.$note_private.'.</textarea>
print '</td></tr>';
}
// Other attributes
if (getDolGlobalInt('THIRDPARTY_PROPAGATE_EXTRAFIELDS_TO_PROPAL') && $socid > 0) {
$thirdpartytopropagateextrafieldsfrom = $soc;
}
include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_add.tpl.php';
// Lines from source
if (!empty($origin) && !empty($originid) && is_object($objectsrc) && !empty($classname)) {
// TODO for compatibility
if ($origin == 'contrat') {
// Calcul contrat->price (HT), contrat->total (TTC), contrat->tva
$objectsrc->update_price(1, 'auto', 1);
}
print "\n<!-- " . $classname . " info -->";
print "\n";
print '<input type="hidden" name="amount" value="' . $objectsrc->total_ht . '">' . "\n";
print '<input type="hidden" name="total" value="' . $objectsrc->total_ttc . '">' . "\n";
print '<input type="hidden" name="tva" value="' . $objectsrc->total_tva . '">' . "\n";
print '<input type="hidden" name="origin" value="' . $objectsrc->element . '">';
print '<input type="hidden" name="originid" value="' . $objectsrc->id . '">';
$newclassname = $classname;
if ($newclassname == 'Propal') {
$newclassname = 'CommercialProposal';
} elseif ($newclassname == 'Commande') {
$newclassname = 'Order';
} elseif ($newclassname == 'Expedition') {
$newclassname = 'Sending';
} elseif ($newclassname == 'Fichinter') {
$newclassname = 'Intervention';
}
print '<tr><td>' . $langs->trans($newclassname) . '</td><td>' . $objectsrc->getNomUrl(1) . '</td></tr>';
print '<tr><td>' . $langs->trans('AmountHT') . '</td><td>' . price($objectsrc->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td></tr>';
print '<tr><td>' . $langs->trans('AmountVAT') . '</td><td>' . price($objectsrc->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) { // Localtax1
print '<tr><td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td><td>' . price($objectsrc->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
}
if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) { // Localtax2
print '<tr><td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td><td>' . price($objectsrc->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
}
print '<tr><td>' . $langs->trans('AmountTTC') . '</td><td>' . price($objectsrc->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . "</td></tr>";
if (isModEnabled("multicurrency")) {
print '<tr><td>' . $langs->trans('MulticurrencyAmountHT') . '</td><td>' . price($objectsrc->multicurrency_total_ht) . '</td></tr>';
print '<tr><td>' . $langs->trans('MulticurrencyAmountVAT') . '</td><td>' . price($objectsrc->multicurrency_total_tva) . "</td></tr>";
print '<tr><td>' . $langs->trans('MulticurrencyAmountTTC') . '</td><td>' . price($objectsrc->multicurrency_total_ttc) . "</td></tr>";
}
}
print "</table>\n";
/*
* Combobox for copy function
*/
if (!getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
print '<input type="hidden" name="createmode" value="empty">';
}
if (getDolGlobalString('PROPAL_CLONE_ON_CREATE_PAGE')) {
print '<br><table>';
// For backward compatibility
print '<tr>';
print '<td><input type="radio" name="createmode" value="copy"></td>';
print '<td>' . $langs->trans("CopyPropalFrom") . ' </td>';
print '<td>';
$liste_propal = array();
$liste_propal[0] = '';
$sql = "SELECT p.rowid as id, p.ref, s.nom";
$sql .= " FROM " . MAIN_DB_PREFIX . "propal p";
$sql .= ", " . MAIN_DB_PREFIX . "societe s";
$sql .= " WHERE s.rowid = p.fk_soc";
$sql .= " AND p.entity IN (" . getEntity('propal') . ")";
$sql .= " AND p.fk_statut <> 0";
$sql .= " ORDER BY Id";
$resql = $db->query($sql);
if ($resql) {
$num = $db->num_rows($resql);
$i = 0;
while ($i < $num) {
$row = $db->fetch_row($resql);
$propalRefAndSocName = $row[1] . " - " . $row[2];
$liste_propal[$row[0]] = $propalRefAndSocName;
$i++;
}
print $form->selectarray("copie_propal", $liste_propal, 0);
} else {
dol_print_error($db);
}
print '</td></tr>';
print '<tr><td class="tdtop"><input type="radio" name="createmode" value="empty" checked></td>';
print '<td valign="top" colspan="2">' . $langs->trans("CreateEmptyPropal") . '</td></tr>';
print '</table>';
}
}
print dol_get_fiche_end();
$langs->load("bills");
print $form->buttonsSaveCancel("CreateDraft");
print "</form>";
// Show origin lines
if (!empty($origin) && !empty($originid) && is_object($objectsrc)) {
print '<br>';
$title = $langs->trans('ProductsAndServices');
print load_fiche_titre($title);
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent">';
$objectsrc->printOriginLinesList();
print '</table>';
print '</div>';
}
} elseif ($object->id > 0) {
/*
* Show object in view mode
*/
$object->fetch_thirdparty();
if ($object->thirdparty) {
$soc = $object->thirdparty;
} else {
$soc = new Societe($db);
}
$head = propal_prepare_head($object);
print dol_get_fiche_head($head, 'comm', $langs->trans('Proposal'), -1, $object->picto, 0, '', '', 0, '', 1);
$formconfirm = '';
// Clone confirmation
if ($action == 'clone') {
// Create an array for form
$filter = '(s.client:IN:1,2,3)';
$formquestion = array(
// 'text' => $langs->trans("ConfirmClone"),
// array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOSTINT('socid'), 'socid', $filter, '', 0, 0, array(), 0, 'maxwidth300')),
array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans('PuttingPricesUpToDate'), 'value' => 0),
array('type' => 'checkbox', 'name' => 'update_desc', 'label' => $langs->trans('PuttingDescUpToDate'), 'value' => 0),
);
if (getDolGlobalString('PROPAL_CLONE_DATE_DELIVERY') && !empty($object->delivery_date)) {
$formquestion[] = array('type' => 'date', 'name' => 'date_delivery', 'label' => $langs->trans("DeliveryDate"), 'value' => $object->delivery_date);
}
// Incomplete payment. We ask if reason = discount or other
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ToClone'), $langs->trans('ConfirmClonePropal', $object->ref), 'confirm_clone', $formquestion, 'yes', 1, 0, 600);
}
// Subtotal line form
if ($action == 'add_title_line') {
$langs->load('subtotals');
$type = 'title';
$depth_array = $object->getPossibleLevels($langs);
require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
} elseif ($action == 'add_subtotal_line') {
$langs->load('subtotals');
$type = 'subtotal';
$titles = $object->getPossibleTitles();
require dol_buildpath('/core/tpl/subtotal_create.tpl.php');
}
if ($action == 'closeas') {
//Form to close proposal (signed or not)
$formquestion = array();
if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
$formquestion[] = array('type' => 'select', 'name' => 'statut', 'label' => '<span class="fieldrequired">' . $langs->trans("CloseAs") . '</span>', 'values' => array($object::STATUS_SIGNED => $object->LibStatut($object::STATUS_SIGNED), $object::STATUS_NOTSIGNED => $object->LibStatut($object::STATUS_NOTSIGNED)));
}
$formquestion[] = array('type' => 'text', 'name' => 'note_private', 'label' => $langs->trans("Note"), 'value' => ''); // Field to complete private note (not replace)
if (getDolGlobalInt('PROPOSAL_SUGGEST_DOWN_PAYMENT_INVOICE_CREATION')) {
// This is a hidden option:
// Suggestion to create invoice during proposal signature is not enabled by default.
// Such choice should be managed by the workflow module and trigger. This option generates conflicts with some setup.
// It may also break step of creating an order when invoicing must be done from orders and not from proposal
$deposit_percent_from_payment_terms = getDictionaryValue('c_payment_term', 'deposit_percent', $object->cond_reglement_id);
if (!empty($deposit_percent_from_payment_terms) && isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
$object->fetchObjectLinked();
$eligibleForDepositGeneration = true;
if (array_key_exists('facture', $object->linkedObjects)) {
foreach ($object->linkedObjects['facture'] as $invoice) {
'@phan-var-force Facture $invoice';
/** @var Facture $invoice */
if ($invoice->type == Facture::TYPE_DEPOSIT) {
$eligibleForDepositGeneration = false;
break;
}
}
}
if ($eligibleForDepositGeneration && array_key_exists('commande', $object->linkedObjects)) {
foreach ($object->linkedObjects['commande'] as $order) {
$order->fetchObjectLinked();
if (array_key_exists('facture', $order->linkedObjects)) {
foreach ($order->linkedObjects['facture'] as $invoice) {
'@phan-var-force Facture $invoice';
/** @var Facture $invoice */
if ($invoice->type == Facture::TYPE_DEPOSIT) {
$eligibleForDepositGeneration = false;
break 2;
}
}
}
}
}
if ($eligibleForDepositGeneration) {
$formquestion[] = array(
'type' => 'checkbox',
'tdclass' => 'showonlyifsigned',
'name' => 'generate_deposit',
'morecss' => 'margintoponly marginbottomonly',
'label' => $form->textwithpicto($langs->trans('GenerateDeposit', $object->deposit_percent), $langs->trans('DepositGenerationPermittedByThePaymentTermsSelected'))
);
$formquestion[] = array(
'type' => 'date',
'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
'name' => 'datef',
'label' => $langs->trans('DateInvoice'),
'value' => dol_now(),
'datenow' => true
);
if (getDolGlobalString('INVOICE_POINTOFTAX_DATE')) {
$formquestion[] = array(
'type' => 'date',
'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
'name' => 'date_pointoftax',
'label' => $langs->trans('DatePointOfTax'),
'value' => dol_now(),
'datenow' => true
);
}
$paymentTermsSelect = $form->getSelectConditionsPaiements(0, 'cond_reglement_id', -1, 0, 1, 'minwidth200');
$formquestion[] = array(
'type' => 'other',
'tdclass' => 'fieldrequired showonlyifgeneratedeposit',
'name' => 'cond_reglement_id',
'label' => $langs->trans('PaymentTerm'),
'value' => $paymentTermsSelect
);
$formquestion[] = array(
'type' => 'checkbox',
'tdclass' => 'showonlyifgeneratedeposit',
'name' => 'validate_generated_deposit',
'morecss' => 'margintoponly marginbottomonly',
'label' => $langs->trans('ValidateGeneratedDeposit')
);
$formquestion[] = array(
'type' => 'onecolumn',
'value' => '
<script>
let signedValue = ' . $object::STATUS_SIGNED . ';
$(document).ready(function() {
$("[name=generate_deposit]").change(function () {
let $self = $(this);
let $target = $(".showonlyifgeneratedeposit").parent(".tagtr");
if (! $self.parents(".tagtr").is(":hidden") && $self.is(":checked")) {
$target.show();
} else {
$target.hide();
}
return true;
});
$("#statut").change(function() {
let $target = $(".showonlyifsigned").parent(".tagtr");
if ($(this).val() == signedValue) {
$target.show();
} else {
$target.hide();
}
$("[name=generate_deposit]").trigger("change");
return true;
});
$("#statut").trigger("change");
});
</script>
'
);
}
}
}
if (isModEnabled('notification')) {
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$formquestion = array_merge($formquestion, array(
array('type' => 'onecolumn', 'value' => $notify->confirmMessage('PROPAL_CLOSE_SIGNED', $object->socid, $object)),
));
}
if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('SetAcceptedRefused'), '', 'confirm_closeas', $formquestion, '', 1, 250);
} else {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?statut=3&id=' . $object->id, $langs->trans('Close'), '', 'confirm_closeas', $formquestion, '', 1, 250);
}
} elseif ($action == 'cancel') {
// Confirm cancel
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans("CancelPropal"), $langs->trans('ConfirmCancelPropal', $object->ref), 'confirm_cancel', '', 0, 1);
} elseif ($action == 'delete') {
// Confirm delete
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp', $object->ref), 'confirm_delete', '', 0, 1);
} elseif ($action == 'reopen') {
// Confirm reopen
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp', $object->ref), 'confirm_reopen', '', 0, 1);
} elseif ($action == 'ask_deleteline') {
// Confirmation delete product/service line
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
} elseif ($action == 'ask_subtotal_deleteline') {
// Confirmation of removal of a subtotal line
$langs->load("subtotals");
$title = "DeleteSubtotalLine";
$question = "ConfirmDeleteSubtotalLine";
if (GETPOST('type') == 'title') {
$formconfirm = array(array('type' => 'checkbox', 'name' => 'deletecorrespondingsubtotalline', 'label' => $langs->trans("DeleteCorrespondingSubtotalLine"), 'value' => 0));
$title = "DeleteTitleLine";
$question = "ConfirmDeleteTitleLine";
}
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id . '&lineid=' . $lineid, $langs->trans($title), $langs->trans($question), 'confirm_delete_subtotalline', $formconfirm, 'no', 1);
} elseif ($action == 'validate') {
// Confirm validate proposal
$error = 0;
// We verify whether the object is provisionally numbering
$ref = substr($object->ref, 1, 4);
if ($ref == 'PROV' || $ref == '') {
$numref = $object->getNextNumRef($soc);
if (empty($numref)) {
$error++;
setEventMessages($object->error, $object->errors, 'errors');
}
} else {
$numref = (string) $object->ref;
}
$text = $langs->trans('ConfirmValidateProp', $numref);
if (isModEnabled('notification')) {
require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
$notify = new Notify($db);
$text .= '<br>';
$text .= $notify->confirmMessage('PROPAL_VALIDATE', $object->socid, $object);
}
// mandatoryPeriod
$nbMandated = 0;
foreach ($object->lines as $line) {
$res = $line->fetch_product();
if ($res > 0) {
if ($line->product->isService() && $line->product->isMandatoryPeriod() && (empty($line->date_start) || empty($line->date_end))) {
$nbMandated++;
break;
}
}
}
if ($nbMandated > 0) {
if (getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
setEventMessages($langs->trans("mandatoryPeriodNeedTobeSetMsgValidate"), null, 'errors');
$error++;
} else {
$text .= '<div><span class="clearboth nowraponall warning">' . img_warning() . $langs->trans("mandatoryPeriodNeedTobeSetMsgValidate") . '</span></div>';
}
}
if (!$error) {
$formconfirm = $form->formconfirm(dolBuildUrl($_SERVER["PHP_SELF"], ['id' => $object->id]), $langs->trans('ValidateProp'), $text, 'confirm_validate', '', 0, 1, 240);
}
}
// Call Hook formConfirm
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$formconfirm .= $hookmanager->resPrint;
} elseif ($reshook > 0) {
$formconfirm = $hookmanager->resPrint;
}
// Print form confirm
print $formconfirm;
// Proposal card
$linkback = '<a href="' . DOL_URL_ROOT . '/comm/propal/list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
$morehtmlref = '<div class="refidno">';
// Ref customer
$morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
$morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string' . (isset($conf->global->THIRDPARTY_REF_INPUT_SIZE) ? ':' . getDolGlobalString('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
// Thirdparty
$morehtmlref .= '<br>' . $soc->getNomUrl(1, 'customer');
if (!getDolGlobalString('MAIN_DISABLE_OTHER_LINK') && $soc->id > 0) {
$morehtmlref .= ' (<a href="' . DOL_URL_ROOT . '/comm/propal/list.php?socid=' . ((int) $soc->id) . '">' . $langs->trans("OtherProposals") . '</a>)';
}
// Project
if (isModEnabled('project')) {
$langs->load("projects");
$morehtmlref .= '<br>';
if ($usercancreate) {
$morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
if ($action != 'classify') {
$morehtmlref .= '<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> ';
}
$morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, (string) $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
} else {
if (!empty($object->fk_project)) {
$proj = new Project($db);
$proj->fetch($object->fk_project);
$morehtmlref .= $proj->getNomUrl(1);
if ($proj->title) {
$morehtmlref .= '<span class="opacitymedium"> - ' . dol_escape_htmltag($proj->title) . '</span>';
}
}
}
}
$morehtmlref .= '</div>';
dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
// Call Hook tabContentViewProposal
$parameters = array();
// Note that $action and $object may be modified by hook
$reshook = $hookmanager->executeHooks('tabContentViewProposal', $parameters, $object, $action);
if (empty($reshook)) {
print '<div class="fichecenter">';
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield centpercent">';
// Link for thirdparty discounts
if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
$filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
$filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be subtracted to payments only and not to total of final invoice
} else {
$filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
$filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
}
print '<tr><td class="titlefieldmax45">' . $langs->trans('Discounts') . '</td><td>';
$absolute_discount = $soc->getAvailableDiscounts(null, $filterabsolutediscount);
$absolute_creditnote = $soc->getAvailableDiscounts(null, $filtercreditnote);
$absolute_discount = price2num($absolute_discount, 'MT');
$absolute_creditnote = price2num($absolute_creditnote, 'MT');
$caneditfield = ($object->status != Propal::STATUS_SIGNED && $object->status != Propal::STATUS_BILLED);
$thirdparty = $soc;
$discount_type = 0;
$backtopage = $_SERVER["PHP_SELF"] . '?id=' . $object->id;
include DOL_DOCUMENT_ROOT . '/core/tpl/object_discounts.tpl.php';
print '</td></tr>';
// Date of proposal
print '<tr>';
print '<td>';
// print '<table class="nobordernopadding" width="100%"><tr><td>';
// print $langs->trans('DatePropal');
// print '</td>';
// if ($action != 'editdate' && $usercancreate && $caneditfield) {
// print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editdate&token='.newToken().'&id='.$object->id.'">'.img_edit($langs->trans('SetDate'), 1).'</a></td>';
// }
// print '</tr></table>';
$editenable = $usercancreate && $caneditfield && $object->status == Propal::STATUS_DRAFT;
print $form->editfieldkey("DatePropal", 'date', '', $object, (int) $editenable);
print '</td><td class="valuefield">';
if ($action == 'editdate' && $usercancreate && $caneditfield) {
print '<form name="editdate" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
print '<input type="hidden" name="token" value="' . newToken() . '">';
print '<input type="hidden" name="action" value="setdate">';
print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
print $form->selectDate($object->date, 're', 0, 0, 0, "editdate");
print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
print '</form>';
} else {
if ($object->date) {
print dol_print_date($object->date, 'day');
} else {
print '&nbsp;';
}
}
print '</td>';
// Date end proposal
print '<tr>';
print '<td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('DateEndPropal');
print '</td>';
if ($action != 'editecheance' && $usercancreate && $caneditfield) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editecheance&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetConditions'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editecheance' && $usercancreate && $caneditfield) {
print '<form name="editecheance" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
print '<input type="hidden" name="token" value="' . newToken() . '">';
print '<input type="hidden" name="action" value="setecheance">';
print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
print $form->selectDate($object->fin_validite, 'ech', 0, 0, 0, "editecheance");
print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
print '</form>';
} else {
if (!empty($object->fin_validite)) {
print dol_print_date($object->fin_validite, 'day');
if ($object->status == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - getWarningDelay('propal', 'cloture'))) {
print img_warning($langs->trans("Late"));
}
} else {
print '&nbsp;';
}
}
print '</td>';
print '</tr>';
// Payment term
print '<tr><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('PaymentConditionsShort');
print '</td>';
if ($action != 'editconditions' && $usercancreate && $caneditfield) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editconditions&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetConditions'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editconditions' && $usercancreate && $caneditfield) {
$form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->cond_reglement_id, 'cond_reglement_id', 0, '', 1, $object->deposit_percent);
} else {
$form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->cond_reglement_id, 'none', 0, '', 1, $object->deposit_percent);
}
print '</td>';
print '</tr>';
// Payment mode
print '<tr class="field_mode_reglement_id">';
print '<td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('PaymentMode');
print '</td>';
if ($action != 'editmode' && $usercancreate && $caneditfield) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editmode&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetMode'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefieldcreate">';
if ($action == 'editmode' && $usercancreate && $caneditfield) {
$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->mode_reglement_id, 'mode_reglement_id', 'CRDT', 1, 1);
} else {
$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->mode_reglement_id, 'none');
}
print '</td></tr>';
// Delivery delay
print '<tr class="fielddeliverydelay"><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
if (isModEnabled('order')) {
print $form->textwithpicto($langs->trans('AvailabilityPeriod'), $langs->trans('AvailabilityPeriod') . ' (' . $langs->trans('AfterOrder') . ')');
} else {
print $langs->trans('AvailabilityPeriod');
}
print '</td>';
if ($action != 'editavailability' && $usercancreate && $caneditfield) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editavailability&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetAvailability'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editavailability' && $usercancreate && $caneditfield) {
$form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->availability_id, 'availability_id', $langs->trans("Delay"));
} else {
$form->form_availability($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->availability_id, 'none', 1);
}
print '</td>';
print '</tr>';
// Delivery date
print '<tr><td>';
print $form->editfieldkey($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, (int) ($usercancreate && $caneditfield), 'datepicker');
print '</td><td class="valuefieldedit">';
print $form->editfieldval($langs->trans('DeliveryDate'), 'date_livraison', $object->delivery_date, $object, $usercancreate && $caneditfield, 'datepicker');
print '</td>';
print '</tr>';
// Shipping Method
if (isModEnabled("shipping")) {
print '<tr><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('SendingMethod');
print '</td>';
if ($action != 'editshippingmethod' && $usercancreate && $caneditfield) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editshippingmethod&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetShippingMode'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editshippingmethod' && $usercancreate && $caneditfield) {
$form->formSelectShippingMethod($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->shipping_method_id, 'shipping_method_id', 1);
} else {
$form->formSelectShippingMethod($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->shipping_method_id, 'none');
}
print '</td>';
print '</tr>';
}
// Warehouse
if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
$langs->load('stocks');
require_once DOL_DOCUMENT_ROOT . '/product/class/html.formproduct.class.php';
$formproduct = new FormProduct($db);
print '<tr class="field_warehouse_id"><td>';
$editenable = $usercancreate;
print $form->editfieldkey("Warehouse", 'warehouse', '', $object, $editenable);
print '</td><td class="valuefieldcreate">';
if ($action == 'editwarehouse') {
$formproduct->formSelectWarehouses($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->warehouse_id, 'warehouse_id', 1);
} else {
$formproduct->formSelectWarehouses($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->warehouse_id, 'none');
}
print '</td>';
print '</tr>';
}
// Origin of demand
print '<tr><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans('Source');
print '</td>';
if ($action != 'editdemandreason' && $usercancreate) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editdemandreason&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetDemandReason'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editdemandreason' && $usercancreate) {
$form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->demand_reason_id, 'demand_reason_id', 1);
} else {
$form->formInputReason($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->demand_reason_id, 'none');
}
print '</td>';
print '</tr>';
if ($soc->outstanding_limit) {
// Outstanding Bill
print '<tr><td>';
print $langs->trans('OutstandingBill');
print '</td><td class="valuefield">';
$arrayoutstandingbills = $soc->getOutstandingBills();
print($arrayoutstandingbills['opened'] > $soc->outstanding_limit ? img_warning() : '');
print price($arrayoutstandingbills['opened']) . ' / ';
print price($soc->outstanding_limit, 0, $langs, 1, -1, -1, $conf->currency);
print '</td>';
print '</tr>';
}
if (getDolGlobalString('BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL') && isModEnabled("bank")) {
// Bank Account
print '<tr><td>';
print '<table width="100%" class="nobordernopadding"><tr><td>';
print $langs->trans('BankAccount');
print '</td>';
if ($action != 'editbankaccount' && $usercancreate) {
print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editbankaccount&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetBankAccount'), 1) . '</a></td>';
}
print '</tr></table>';
print '</td><td class="valuefield">';
if ($action == 'editbankaccount') {
$form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_account, 'fk_account', 1);
} else {
$form->formSelectAccount($_SERVER['PHP_SELF'] . '?id=' . $object->id, (string) $object->fk_account, 'none');
}
print '</td>';
print '</tr>';
}
if (!getDolGlobalString('PROPOSAL_HIDE_CALCULATED_WEIGHT_VOLUME')) {
$tmparray = $object->getTotalWeightVolume();
$totalWeight = isset($tmparray['weight']) ? $tmparray['weight'] : 0;
$totalVolume = isset($tmparray['volume']) ? $tmparray['volume'] : 0;
if ($totalWeight) {
print '<tr><td>' . $langs->trans("CalculatedWeight") . '</td>';
print '<td class="valuefield">';
print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, getDolGlobalInt('MAIN_WEIGHT_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 'no'), 1);
print '</td></tr>';
}
if ($totalVolume) {
print '<tr><td>' . $langs->trans("CalculatedVolume") . '</td>';
print '<td class="valuefield">';
print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, getDolGlobalInt('MAIN_VOLUME_DEFAULT_ROUND', -1), getDolGlobalString('MAIN_VOLUME_DEFAULT_UNIT', 'no'), 1);
print '</td></tr>';
}
}
// Incoterms
if (isModEnabled('incoterm')) {
print '<tr><td>';
print '<table width="100%" class="nobordernopadding"><tr><td>';
print $langs->trans('IncotermLabel');
print '<td><td class="right">';
if ($action != 'editincoterm' && $usercancreate && $caneditfield) {
print '<a class="editfielda" href="' . DOL_URL_ROOT . '/comm/propal/card.php?id=' . $object->id . '&action=editincoterm&token=' . newToken() . '">' . img_edit() . '</a>';
} else {
print '&nbsp;';
}
print '</td></tr></table>';
print '</td>';
print '<td class="valuefield">';
if ($action == 'editincoterm' && $usercancreate && $caneditfield) {
print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'] . '?id=' . $object->id);
} else {
print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
}
print '</td></tr>';
}
// Categories
if (isModEnabled('category')) {
print '<tr><td>';
print '<table class="nobordernopadding centpercent"><tr><td>';
print $langs->trans("Categories");
print '<td><td class="right">';
if ($usercancreate) {
print '<a class="editfielda" href="'.DOL_URL_ROOT.'/comm/propal/card.php?id='.$object->id.'&action=edittags&token='.newToken().'">'.img_edit().'</a>';
} else {
print '&nbsp;';
}
print '</td></tr></table>';
print '</td>';
print '<td>';
if ($action == 'edittags') {
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
print '<input type="hidden" name="action" value="settags">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print $form->selectCategories(Categorie::TYPE_PROPOSAL, 'categories', $object);
print '<input type="submit" class="button valignmiddle smallpaddingimp" value="'.$langs->trans("Modify").'">';
print '</form>';
} else {
print $form->showCategories($object->id, Categorie::TYPE_PROPOSAL, 1);
}
print "</td></tr>";
}
// Other attributes
include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
print '</table>';
print '</div>';
print '<div class="fichehalfright">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border tableforfield centpercent">';
include DOL_DOCUMENT_ROOT . '/core/tpl/object_currency_amount.tpl.php';
print '<tr>';
print '<td class="titlefieldmiddle">' . $langs->trans('AmountHT') . '</td>';
print '<td class="nowrap amountcard right">' . price($object->total_ht, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ht, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
}
print '</tr>';
print '<tr>';
print '<td>' . $langs->trans('AmountVAT') . '</td>';
print '<td class="nowrap amountcard right">' . price($object->total_tva, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_tva, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
}
print '</tr>';
if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) {
print '<tr>';
print '<td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
print '<td class="nowrap amountcard right">' . price($object->total_localtax1, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
$object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
}
print '</tr>';
}
if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
print '<tr>';
print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
print '<td class="nowrap amountcard right">' . price($object->total_localtax2, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
$object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
}
print '</tr>';
}
print '<tr>';
print '<td>' . $langs->trans('AmountTTC') . '</td>';
print '<td class="nowrap amountcard right">' . price($object->total_ttc, 0, $langs, 1, -1, -1, $conf->currency) . '</td>';
if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_ttc, 0, $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
}
print '</tr>';
print '</table>';
// Margin Infos
if (isModEnabled('margin')) {
$formmargin->displayMarginInfos($object);
}
print '</div>';
print '</div>';
print '<div class="clearboth"></div><br>';
if (getDolGlobalString('MAIN_DISABLE_CONTACTS_TAB')) {
$blocname = 'contacts';
$title = $langs->trans('ContactsAddresses');
include DOL_DOCUMENT_ROOT . '/core/tpl/bloc_showhide.tpl.php';
}
if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
$blocname = 'notes';
$title = $langs->trans('Notes');
include DOL_DOCUMENT_ROOT . '/core/tpl/bloc_showhide.tpl.php';
}
/*
* Lines
*/
// Get object lines
$result = $object->getLinesArray();
// Add products/services form
//$forceall = 1;
global $inputalsopricewithtax;
$inputalsopricewithtax = 1;
print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="POST">
<input type="hidden" name="token" value="' . newToken() . '">
<input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateline') . '">
<input type="hidden" name="mode" value="">
<input type="hidden" name="page_y" value="">
<input type="hidden" name="backtopage" value="' . $backtopage . '">
<input type="hidden" name="id" value="' . $object->id . '">
';
if (!empty($conf->use_javascript_ajax) && $object->status == Propal::STATUS_DRAFT) {
if (isModEnabled('subtotals')) {
include DOL_DOCUMENT_ROOT . '/core/tpl/subtotal_ajaxrow.tpl.php';
} else {
include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
}
}
print '<div class="div-table-responsive-no-min">';
if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
print '<table id="tablelines" class="noborder noshadow centpercent">';
}
if (!empty($object->lines)) {
$object->printObjectLines($action, $mysoc, $object->thirdparty, $lineid, 1);
}
// Form to add new line
if ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines') {
if ($action != 'editline') {
$parameters = array();
$reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
if (empty($reshook)) {
$object->formAddObjectLine(1, $mysoc, $soc);
}
} else {
$parameters = array();
$reshook = $hookmanager->executeHooks('formEditObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
}
}
if (!empty($object->lines) || ($object->status == Propal::STATUS_DRAFT && $usercancreate && $action != 'selectlines' && $action != 'editline')) {
print '</table>';
}
print '</div>';
print "</form>\n";
}
print dol_get_fiche_end();
/*
* Button Actions
*/
if ($action != 'presend') {
$numlines = count($object->lines);
print '<div class="tabsAction">';
$parameters = array();
$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been
// modified by hook
if (empty($reshook)) {
if ($action != 'editline') {
// Subtotal
if ($object->status == Propal::STATUS_DRAFT && isModEnabled('subtotals')
&& (getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element)) || getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element)))) {
$langs->load('subtotals');
$url_button = array();
$url_button[] = array(
'lang' => 'subtotals',
'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_TITLE_'.strtoupper($object->element))),
'perm' => (bool) $usercancreate,
'label' => $langs->trans('AddTitleLine'),
'url' => '/comm/propal/card.php?id=' . $object->id . '&action=add_title_line&token=' . newToken()
);
$url_button[] = array(
'lang' => 'subtotals',
'enabled' => (isModEnabled('propal') && $object->status == Propal::STATUS_DRAFT && getDolGlobalInt('SUBTOTAL_'.strtoupper($object->element))),
'perm' => (bool) $usercancreate,
'label' => $langs->trans('AddSubtotalLine'),
'url' => '/comm/propal/card.php?id=' . $object->id . '&action=add_subtotal_line&token=' . newToken()
);
print dolGetButtonAction('', $langs->trans('Subtotal'), 'default', $url_button, '', true);
}
// Validate
if (($object->status == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0)
|| ($object->status == Propal::STATUS_DRAFT && getDolGlobalString('PROPAL_ENABLE_NEGATIVE') && count($object->lines) > 0)
) {
if ($usercanvalidate) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=validate&token=' . newToken() . '">' . (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE') ? $langs->trans('Validate') : $langs->trans('ValidateAndSign')) . '</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#">' . $langs->trans('Validate') . '</a>';
}
}
// Create event
/*if (isModEnabled('agenda') && !empty($conf->global->MAIN_ADD_EVENT_ON_ELEMENT_CARD)) // Add hidden condition because this is not a "workflow" action so should appears somewhere else on page.
{
print '<a class="butAction" href="' . DOL_URL_ROOT . '/comm/action/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans("AddAction") . '</a></div>';
}*/
// Edit
if ($object->status == Propal::STATUS_VALIDATED && $usercancreate) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=modif&token=' . newToken() . '">' . $langs->trans('Modify') . '</a>';
}
// ReOpen
if (((getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && $object->status == Propal::STATUS_NOTSIGNED) || (!getDolGlobalString('PROPAL_REOPEN_UNSIGNED_ONLY') && ($object->status == Propal::STATUS_SIGNED || $object->status == Propal::STATUS_NOTSIGNED || $object->status == Propal::STATUS_BILLED || $object->status == Propal::STATUS_CANCELED)))) {
if ($usercanreopen) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=reopen&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#reopen') . '"';
print '>' . $langs->trans('ReOpen') . '</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '">' . $langs->trans("ReOpen") . '</a>';
}
}
// Send
if (empty($user->socid)) {
if ($object->status == Propal::STATUS_VALIDATED || $object->status == Propal::STATUS_SIGNED || getDolGlobalString('PROPOSAL_SENDBYEMAIL_FOR_ALL_STATUS')) {
print dolGetButtonAction('', $langs->trans('SendMail'), 'email', $_SERVER["PHP_SELF"] . '?action=presend&token=' . newToken() . '&id=' . $object->id . '&mode=init#formmailbeforetitle', '', $usercansend);
}
}
$arrayforbutaction = array();
// Create a sale order
$arrayforbutaction[] = array(
'lang' => 'orders',
'enabled' => (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED),
'perm' => $usercancreateorder,
'label' => 'AddOrder',
'url' => '/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
);
/*if (isModEnabled('order') && $object->status == Propal::STATUS_SIGNED) {
if ($usercancreateorder) {
print '<a class="butAction" href="'.DOL_URL_ROOT.'/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddOrder").'</a>';
}
}*/
// Create a purchase order
if (getDolGlobalString('WORKFLOW_CAN_CREATE_PURCHASE_ORDER_FROM_PROPOSAL')) {
$arrayforbutaction[] = array(
'lang' => 'orders',
'enabled' => ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")),
'perm' => $usercancreatepurchaseorder,
'label' => 'AddPurchaseOrder',
'url' => '/fourn/commande/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
);
/*if ($object->status == Propal::STATUS_SIGNED && isModEnabled("supplier_order")) {
if ($usercancreatepurchaseorder) {
print '<a class="butAction" href="'.DOL_URL_ROOT.'/fourn/commande/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddPurchaseOrder").'</a>';
}
}*/
}
// Create an intervention
$arrayforbutaction[] = array(
'lang' => 'interventions',
'enabled' => (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED),
'perm' => $usercancreateintervention,
'label' => 'AddIntervention',
'url' => '/fichinter/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
);
/*if (isModEnabled("service") && isModEnabled('intervention') && $object->status == Propal::STATUS_SIGNED) {
if ($usercancreateintervention) {
$langs->load("interventions");
print '<a class="butAction" href="'.DOL_URL_ROOT.'/fichinter/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("AddIntervention").'</a>';
}
}*/
// Create contract
$arrayforbutaction[] = array(
'lang' => 'contracts',
'enabled' => (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED),
'perm' => $usercancreatecontract,
'label' => 'AddContract',
'url' => '/contrat/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid)
);
/*if (isModEnabled('contract') && $object->status == Propal::STATUS_SIGNED) {
$langs->load("contracts");
if ($usercancreatecontract) {
print '<a class="butAction" href="'.DOL_URL_ROOT.'/contrat/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans('AddContract').'</a>';
}
}*/
// Create an invoice and classify billed
if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
$arrayforbutaction[] = [
'lang' => 'invoice',
'enabled' => isModEnabled('invoice'),
'perm' => $usercancreateinvoice,
'label' => 'CreateBill',
'url' => '/compta/facture/card.php?action=create&origin=' . urlencode($object->element) . '&originid=' . ((int) $object->id) . '&socid=' . ((int) $object->socid),
];
/*if (isModEnabled('invoice') && $usercancreateinvoice) {
print '<a class="butAction" href="'.DOL_URL_ROOT.'/compta/facture/card.php?action=create&origin='.$object->element.'&originid='.$object->id.'&socid='.$object->socid.'">'.$langs->trans("CreateBill").'</a>';
}*/
}
$actionButtonsParameters = [
"areDropdownButtons" => !getDolGlobalInt("MAIN_REMOVE_DROPDOWN_CREATE_BUTTONS_ON_ORDER"),
"backtopage" => $_SERVER["PHP_SELF"] . "?id=" . ((int) $id)
];
if ($numlines > 0) {
print dolGetButtonAction('', $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 1, $actionButtonsParameters);
} else {
print dolGetButtonAction($langs->trans("ErrorObjectMustHaveLinesToBeValidated", $object->ref), $langs->trans("Create"), 'default', $arrayforbutaction, (string) $object->id, 0, $actionButtonsParameters);
}
if ($object->status == Propal::STATUS_SIGNED && !getDolGlobalString('PROPOSAL_ARE_NOT_BILLABLE')) {
$arrayofinvoiceforpropal = $object->getInvoiceArrayList();
if ((is_array($arrayofinvoiceforpropal) && count($arrayofinvoiceforpropal) > 0) || !getDolGlobalString('WORKFLOW_PROPAL_NEED_INVOICE_TO_BE_CLASSIFIED_BILLED')) {
if ($usercanclose) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=classifybilled&token=' . newToken() . '&socid=' . $object->socid . '">' . $langs->trans("ClassifyBilled") . '</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '">' . $langs->trans("ClassifyBilled") . '</a>';
}
}
}
if (!getDolGlobalString('PROPAL_SKIP_ACCEPT_REFUSE')) {
// Close as accepted/refused
if ($object->status == Propal::STATUS_VALIDATED) {
if ($usercanclose) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=closeas&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
print '>' . $langs->trans('SetAcceptedRefused') . '</a>';
} else {
print '<a class="butActionRefused classfortooltip" href="#" title="' . $langs->trans("NotEnoughPermissions") . '"';
print '>' . $langs->trans('SetAcceptedRefused') . '</a>';
}
}
} else {
// Set not signed (close)
if ($object->status == Propal::STATUS_DRAFT && $usercanclose) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&token=' . newToken() . '&action=closeas&token=' . newToken() . (!getDolGlobalString('MAIN_JUMP_TAG') ? '' : '#close') . '"';
print '>' . $langs->trans('SetRefusedAndClose') . '</a>';
}
}
// Cancel propal
if ($object->status > Propal::STATUS_DRAFT && $usercanclose) {
print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=cancel&token=' . newToken() . '">' . $langs->trans("CancelPropal") . '</a>';
}
// Clone
if ($usercancreate) {
print '<a class="butAction butActionClone" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&socid=' . $object->socid . '&action=clone&token=' . newToken() . '&object=' . $object->element . '">' . $langs->trans("ToClone") . '</a>';
}
// Delete
print dolGetButtonAction($langs->trans("Delete"), '', 'delete', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete&token=' . newToken(), 'delete', $usercandelete);
}
}
print '</div>';
}
//Select mail models is same action as presend
if (GETPOST('modelselected')) {
$action = 'presend';
}
if ($action != 'presend') {
print '<div class="fichecenter"><div class="fichehalfleft">';
print '<a name="builddoc"></a>'; // ancre
/*
* Generated documents
*/
$objref = dol_sanitizeFileName($object->ref);
$filedir = $conf->propal->multidir_output[$object->entity ?? $conf->entity] . "/" . dol_sanitizeFileName($object->ref);
$urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
$genallowed = $usercanread;
$delallowed = $usercancreate;
$tooltipAfterComboOfModels = '';
if (getDolGlobalString('MAIN_PDF_ADD_TERMSOFSALE_PROPAL')) {
$tooltipAfterComboOfModels = $langs->trans("AccordingToYourSetupTheFileWillBeConcatenated", getDolGlobalString('MAIN_INFO_PROPAL_TERMSOFSALE'));
}
print $formfile->showdocuments('propal', $objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '0', '', $soc->default_lang, '', $object, 0, 'remove_file', $tooltipAfterComboOfModels);
// Show links to link elements
$tmparray = $form->showLinkToObjectBlock($object, array(), array('propal'), 1);
$linktoelem = $tmparray['linktoelem'];
$htmltoenteralink = $tmparray['htmltoenteralink'];
print $htmltoenteralink;
$compatibleImportElementsList = false;
if ($user->hasRight('propal', 'creer') && $object->status == Propal::STATUS_DRAFT) {
$compatibleImportElementsList = array('commande', 'propal', 'facture', 'subscription'); // import from linked elements
}
$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem, $compatibleImportElementsList);
// Show online signature link
$useonlinesignature = getDolGlobalInt('PROPOSAL_ALLOW_ONLINESIGN');
if ($object->status != Propal::STATUS_DRAFT && $useonlinesignature) {
print '<br><!-- Link to sign -->';
require_once DOL_DOCUMENT_ROOT . '/core/lib/signature.lib.php';
print showOnlineSignatureUrl('proposal', $object->ref, $object) . '<br>';
}
print '</div><div class="fichehalfright">';
$MAXEVENT = 10;
$morehtmlcenter = dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT . '/comm/propal/messaging.php?id=' . $object->id);
$morehtmlcenter .= dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT . '/comm/propal/agenda.php?id=' . $object->id);
// List of actions on element
include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
$formactions = new FormActions($db);
$somethingshown = $formactions->showactions($object, 'propal', $socid, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for thirdparty
print '</div></div>';
}
// Presend form
$modelmail = 'propal_send';
$defaulttopic = 'SendPropalRef';
$diroutput = $conf->propal->multidir_output[$object->entity ?? $conf->entity];
$trackid = 'pro' . $object->id;
include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
}
// End of page
llxFooter();
$db->close();