Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2021-09-30 14:46:39 +02:00
commit 9460ad152e
15 changed files with 509 additions and 260 deletions

View File

@ -195,7 +195,7 @@ if (empty($reshook)) {
} elseif ($action == 'enable' && $permissiontoadd) {
if ($accounting->fetch($id)) {
$mode = GETPOST('mode', 'int');
$result = $accounting->account_activate($id, $mode);
$result = $accounting->accountActivate($id, $mode);
}
$action = 'update';
if ($result < 0) {

View File

@ -26,6 +26,9 @@
* \brief File of class to manage accounting accounts
*/
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
/**
* Class to manage accounting accounts
*/
@ -140,6 +143,11 @@ class AccountingAccount extends CommonObject
*/
public $reconcilable;
/**
* @var array cache array
*/
private $accountingaccount_codetotid_cache = array();
/**
* Constructor
*
@ -225,8 +233,8 @@ class AccountingAccount extends CommonObject
/**
* Insert new accounting account in chart of accounts
*
* @param User $user User making action
* @param int $notrigger Disable triggers
* @param User $user User making action
* @param int $notrigger Disable triggers
* @return int <0 if KO, >0 if OK
*/
public function create($user, $notrigger = 0)
@ -259,7 +267,7 @@ class AccountingAccount extends CommonObject
// Put here code to add control on parameters values
// Insert request
$sql = "INSERT INTO ".MAIN_DB_PREFIX."accounting_account(";
$sql = "INSERT INTO " . MAIN_DB_PREFIX . "accounting_account(";
$sql .= "datec";
$sql .= ", entity";
$sql .= ", fk_pcg_version";
@ -293,11 +301,11 @@ class AccountingAccount extends CommonObject
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
$this->errors[] = "Error " . $this->db->lasterror();
}
if (!$error) {
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."accounting_account");
$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "accounting_account");
// Uncomment this and change MYOBJECT to your own tag if you
// want this action to call a trigger.
@ -313,8 +321,8 @@ class AccountingAccount extends CommonObject
// Commit or rollback
if ($error) {
foreach ($this->errors as $errmsg) {
dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR);
$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
dol_syslog(get_class($this) . "::create " . $errmsg, LOG_ERR);
$this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
}
$this->db->rollback();
return -1 * $error;
@ -327,7 +335,7 @@ class AccountingAccount extends CommonObject
/**
* Update record
*
* @param User $user Use making update
* @param User $user Use making update
* @return int <0 if KO, >0 if OK
*/
public function update($user)
@ -339,18 +347,18 @@ class AccountingAccount extends CommonObject
$this->db->begin();
$sql = "UPDATE ".MAIN_DB_PREFIX."accounting_account ";
$sql .= " SET fk_pcg_version = ".($this->fk_pcg_version ? "'".$this->db->escape($this->fk_pcg_version)."'" : "null");
$sql .= " , pcg_type = ".($this->pcg_type ? "'".$this->db->escape($this->pcg_type)."'" : "null");
$sql .= " , account_number = '".$this->db->escape($this->account_number)."'";
$sql .= " , account_parent = ".(int) $this->account_parent;
$sql .= " , label = ".($this->label ? "'".$this->db->escape($this->label)."'" : "''");
$sql .= " , labelshort = ".($this->labelshort ? "'".$this->db->escape($this->labelshort)."'" : "''");
$sql .= " , fk_accounting_category = ".(empty($this->account_category) ? 0 : (int) $this->account_category);
$sql .= " , fk_user_modif = ".((int) $user->id);
$sql .= " , active = ".(int) $this->active;
$sql .= " , reconcilable = ".(int) $this->reconcilable;
$sql .= " WHERE rowid = ".((int) $this->id);
$sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_account ";
$sql .= " SET fk_pcg_version = " . ($this->fk_pcg_version ? "'" . $this->db->escape($this->fk_pcg_version) . "'" : "null");
$sql .= " , pcg_type = " . ($this->pcg_type ? "'" . $this->db->escape($this->pcg_type) . "'" : "null");
$sql .= " , account_number = '" . $this->db->escape($this->account_number) . "'";
$sql .= " , account_parent = " . (int) $this->account_parent;
$sql .= " , label = " . ($this->label ? "'" . $this->db->escape($this->label) . "'" : "''");
$sql .= " , labelshort = " . ($this->labelshort ? "'" . $this->db->escape($this->labelshort) . "'" : "''");
$sql .= " , fk_accounting_category = " . (empty($this->account_category) ? 0 : (int) $this->account_category);
$sql .= " , fk_user_modif = " . ((int) $user->id);
$sql .= " , active = " . (int) $this->active;
$sql .= " , reconcilable = " . (int) $this->reconcilable;
$sql .= " WHERE rowid = " . ((int) $this->id);
dol_syslog(get_class($this)."::update", LOG_DEBUG);
$result = $this->db->query($sql);
@ -413,22 +421,22 @@ class AccountingAccount extends CommonObject
$this->db->begin();
if (!$error) {
$sql = "DELETE FROM ".MAIN_DB_PREFIX."accounting_account";
$sql .= " WHERE rowid=".((int) $this->id);
$sql = "DELETE FROM " . MAIN_DB_PREFIX . "accounting_account";
$sql .= " WHERE rowid=" . ((int) $this->id);
dol_syslog(get_class($this)."::delete sql=".$sql);
dol_syslog(get_class($this) . "::delete sql=" . $sql);
$resql = $this->db->query($sql);
if (!$resql) {
$error++;
$this->errors[] = "Error ".$this->db->lasterror();
$this->errors[] = "Error " . $this->db->lasterror();
}
}
// Commit or rollback
if ($error) {
foreach ($this->errors as $errmsg) {
dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
$this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
}
$this->db->rollback();
return -1 * $error;
@ -444,20 +452,20 @@ class AccountingAccount extends CommonObject
/**
* Return clicable name (with picto eventually)
*
* @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
* @param int $withlabel 0=No label, 1=Include label of account
* @param int $nourl 1=Disable url
* @param string $moretitle Add more text to title tooltip
* @param int $notooltip 1=Disable tooltip
* @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
* @param int $withcompletelabel 0=Short label (field short label), 1=Complete label (field label)
* @param string $option 'ledger', 'journals', 'accountcard'
* @return string String with URL
* @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto
* @param int $withlabel 0=No label, 1=Include label of account
* @param int $nourl 1=Disable url
* @param string $moretitle Add more text to title tooltip
* @param int $notooltip 1=Disable tooltip
* @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
* @param int $withcompletelabel 0=Short label (field short label), 1=Complete label (field label)
* @param string $option 'ledger', 'journals', 'accountcard'
* @return string String with URL
*/
public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $withcompletelabel = 0, $option = '')
{
global $langs, $conf;
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
if (!empty($conf->dol_no_mouse_hover)) {
$notooltip = 1; // Force disable tooltips
@ -465,15 +473,16 @@ class AccountingAccount extends CommonObject
$result = '';
$url = ''; $labelurl = '';
$url = '';
$labelurl = '';
if (empty($option) || $option == 'ledger') {
$url = DOL_URL_ROOT.'/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start='.urlencode($this->account_number).'&search_accountancy_code_end='.urlencode($this->account_number);
$url = DOL_URL_ROOT . '/accountancy/bookkeeping/listbyaccount.php?search_accountancy_code_start=' . urlencode($this->account_number) . '&search_accountancy_code_end=' . urlencode($this->account_number);
$labelurl = $langs->trans("ShowAccountingAccountInLedger");
} elseif ($option == 'journals') {
$url = DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?search_accountancy_code_start='.urlencode($this->account_number).'&search_accountancy_code_end='.urlencode($this->account_number);
$url = DOL_URL_ROOT . '/accountancy/bookkeeping/list.php?search_accountancy_code_start=' . urlencode($this->account_number) . '&search_accountancy_code_end=' . urlencode($this->account_number);
$labelurl = $langs->trans("ShowAccountingAccountInJournals");
} elseif ($option == 'accountcard') {
$url = DOL_URL_ROOT.'/accountancy/admin/card.php?id='.urlencode($this->id);
$url = DOL_URL_ROOT . '/accountancy/admin/card.php?id=' . urlencode($this->id);
$labelurl = $langs->trans("ShowAccountingAccount");
}
@ -495,29 +504,29 @@ class AccountingAccount extends CommonObject
$labeltoshow = $this->labelshort;
}
$label = '<u>'.$labelurl.'</u>';
$label = '<u>' . $labelurl . '</u>';
if (!empty($this->account_number)) {
$label .= '<br><b>'.$langs->trans('AccountAccounting').':</b> '.length_accountg($this->account_number);
$label .= '<br><b>' . $langs->trans('AccountAccounting') . ':</b> ' . length_accountg($this->account_number);
}
if (!empty($labeltoshow)) {
$label .= '<br><b>'.$langs->trans('Label').':</b> '.$labeltoshow;
$label .= '<br><b>' . $langs->trans('Label') . ':</b> ' . $labeltoshow;
}
if ($moretitle) {
$label .= ' - '.$moretitle;
$label .= ' - ' . $moretitle;
}
$linkclose = '';
if (empty($notooltip)) {
if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
$label = $labelurl;
$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
$linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
}
$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
$linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
$linkclose .= ' class="classfortooltip"';
}
$linkstart = '<a href="'.$url.'"';
$linkstart .= $linkclose.'>';
$linkstart = '<a href="' . $url . '"';
$linkstart .= $linkclose . '>';
$linkend = '</a>';
if ($nourl) {
@ -528,17 +537,17 @@ class AccountingAccount extends CommonObject
$label_link = length_accountg($this->account_number);
if ($withlabel) {
$label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$labeltoshow.($nourl ? '</span>' : '');
$label_link .= ' - ' . ($nourl ? '<span class="opacitymedium">' : '') . $labeltoshow . ($nourl ? '</span>' : '');
}
if ($withpicto) {
$result .= ($linkstart.img_object(($notooltip ? '' : $label), $picto, ($notooltip ? '' : 'class="classfortooltip"'), 0, 0, $notooltip ? 0 : 1).$linkend);
$result .= ($linkstart . img_object(($notooltip ? '' : $label), $picto, ($notooltip ? '' : 'class="classfortooltip"'), 0, 0, $notooltip ? 0 : 1) . $linkend);
}
if ($withpicto && $withpicto != 2) {
$result .= ' ';
}
if ($withpicto != 2) {
$result .= $linkstart.$label_link.$linkend;
$result .= $linkstart . $label_link . $linkend;
}
return $result;
}
@ -552,10 +561,10 @@ class AccountingAccount extends CommonObject
public function info($id)
{
$sql = 'SELECT a.rowid, a.datec, a.fk_user_author, a.fk_user_modif, a.tms';
$sql .= ' FROM '.MAIN_DB_PREFIX.'accounting_account as a';
$sql .= ' WHERE a.rowid = '.((int) $id);
$sql .= ' FROM ' . MAIN_DB_PREFIX . 'accounting_account as a';
$sql .= ' WHERE a.rowid = ' . ((int) $id);
dol_syslog(get_class($this).'::info sql='.$sql);
dol_syslog(get_class($this) . '::info sql=' . $sql);
$result = $this->db->query($sql);
if ($result) {
@ -584,8 +593,8 @@ class AccountingAccount extends CommonObject
/**
* Deactivate an account (for status active or status reconcilable)
*
* @param int $id Id
* @param int $mode 0=field active, 1=field reconcilable
* @param int $id Id
* @param int $mode 0=field active, 1=field reconcilable
* @return int <0 if KO, >0 if OK
*/
public function accountDeactivate($id, $mode = 0)
@ -620,15 +629,15 @@ class AccountingAccount extends CommonObject
}
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Account activated
*
* @param int $id Id
* @param int $mode 0=field active, 1=field reconcilable
* @param int $id Id
* @param int $mode 0=field active, 1=field reconcilable
* @return int <0 if KO, >0 if OK
*/
public function account_activate($id, $mode = 0)
public function accountActivate($id, $mode = 0)
{
// phpcs:enable
$this->db->begin();
@ -654,12 +663,11 @@ class AccountingAccount extends CommonObject
}
}
/**
* Retourne le libelle du statut d'un user (actif, inactif)
*
* @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
* @return string Label of status
* @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
* @return string Label of status
*/
public function getLibStatut($mode = 0)
{
@ -670,9 +678,9 @@ class AccountingAccount extends CommonObject
/**
* Renvoi le libelle d'un statut donne
*
* @param int $status Id status
* @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
* @return string Label of status
* @param int $status Id status
* @param int $mode 0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
* @return string Label of status
*/
public function LibStatut($status, $mode = 0)
{
@ -694,9 +702,9 @@ class AccountingAccount extends CommonObject
}
} elseif ($mode == 2) {
if ($status == 1) {
return img_picto($langs->trans('Enabled'), 'statut4').' '.$langs->trans('Enabled');
return img_picto($langs->trans('Enabled'), 'statut4') . ' ' . $langs->trans('Enabled');
} elseif ($status == 0) {
return img_picto($langs->trans('Disabled'), 'statut5').' '.$langs->trans('Disabled');
return img_picto($langs->trans('Disabled'), 'statut5') . ' ' . $langs->trans('Disabled');
}
} elseif ($mode == 3) {
if ($status == 1) {
@ -706,15 +714,173 @@ class AccountingAccount extends CommonObject
}
} elseif ($mode == 4) {
if ($status == 1) {
return img_picto($langs->trans('Enabled'), 'statut4').' '.$langs->trans('Enabled');
return img_picto($langs->trans('Enabled'), 'statut4') . ' ' . $langs->trans('Enabled');
} elseif ($status == 0) {
return img_picto($langs->trans('Disabled'), 'statut5').' '.$langs->trans('Disabled');
return img_picto($langs->trans('Disabled'), 'statut5') . ' ' . $langs->trans('Disabled');
}
} elseif ($mode == 5) {
if ($status == 1) {
return $langs->trans('Enabled').' '.img_picto($langs->trans('Enabled'), 'statut4');
return $langs->trans('Enabled') . ' ' . img_picto($langs->trans('Enabled'), 'statut4');
} elseif ($status == 0) {
return $langs->trans('Disabled').' '.img_picto($langs->trans('Disabled'), 'statut5');
return $langs->trans('Disabled') . ' ' . img_picto($langs->trans('Disabled'), 'statut5');
}
}
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return Suggest accounting accounts to bind
*
* @param Societe $buyer Societe Object Buyers
* @param $seller Company Object seller
* @param Product $product Product object sell or buy
* @param Facture $facture Facture
* @param FactureLigne $factureDet Facture Det
* @param array $accountingAccount array of Account account
*
* @return array Accounting accounts suggested
*/
public function getAccountingCodeToBind(Societe $buyer, $seller, Product $product, Facture $facture, FactureLigne $factureDet, $accountingAccount = array())
{
global $conf;
global $hookmanager;
// Instantiate hooks for external modules
$hookmanager->initHooks(array('accoutancyBindingCalculation'));
// Execute hook accoutancyBindingCalculation
$parameters = array('buyer' => $buyer, 'seller' => $seller, 'product' => $product, 'facture' => $facture, 'factureDet' => $factureDet ,'accountingAccount'=>$accountingAccount);
$reshook = $hookmanager->executeHooks('accoutancyBindingCalculation', $parameters); // Note that $action and $object may have been modified by some hooks
if (empty($reshook)) {
require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
$isBuyerInEEC = isInEEC($buyer);
$isSellerInEEC = isInEEC($seller);
$code_sell_l = '';
$code_sell_p = '';
$code_sell_t = '';
$suggestedid = '';
// Level 1: Search suggested default account for product/service
$suggestedaccountingaccountbydefaultfor = '';
if ($factureDet->product_type == 1) {
if ($buyer->country_code == $seller->country_code || empty($buyer->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = '';
} else {
if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0) { // European intravat sale, but with a VAT
$code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra)) { // European intravat sale, without VAT intra community number
$code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eec';
} else { // Foreign sale
$code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'export';
}
}
} elseif ($factureDet->product_type == 0) {
if ($buyer->country_code == $seller->country_code || empty($buyer->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = '';
} else {
if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0) { // European intravat sale, but with a VAT
$code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra)) { // European intravat sale, without VAT intra community number
$code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eec';
} else {
$code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'export';
}
}
}
if ($code_sell_l == -1) {
$code_sell_l = '';
}
// Level 2: Search suggested account for product/service (similar code exists in page index.php to make automatic binding)
$suggestedaccountingaccountfor = '';
if ((($buyer->country_code == $seller->country_code) || empty($buyer->country_code)) && !empty($product->accountancy_code_sell)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$code_sell_p = $product->accountancy_code_sell;
$suggestedid = $accountingAccount['dom'];
$suggestedaccountingaccountfor = 'prodserv';
} else {
if ($isSellerInEEC && $isBuyerInEEC && $factureDet->tva_tx != 0 && !empty($product->accountancy_code_sell)) { // European intravat sale, but with VAT
$code_sell_p = $product->accountancy_code_sell;
$suggestedid = $accountingAccount['dom'];
$suggestedaccountingaccountfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($buyer->tva_intra) && !empty($product->accountancy_code_sell)) { // European intravat sale, without VAT intra community number
$code_sell_p = $product->accountancy_code_sell;
$suggestedid = $accountingAccount['dom']; // There is a doubt for this case. Is it an error on vat or we just forgot to fill vat number ?
$suggestedaccountingaccountfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC && !empty($product->accountancy_code_sell_intra)) { // European intravat sale
$code_sell_p = $product->accountancy_code_sell_intra;
$suggestedid = $accountingAccount['intra'];
$suggestedaccountingaccountfor = 'eec';
} elseif (!empty($product->accountancy_code_sell_export)) { // Foreign sale
$code_sell_p = $product->accountancy_code_sell_export;
$suggestedid = $accountingAccount['export'];
$suggestedaccountingaccountfor = 'export';
}
}
// Level 3: Search suggested account for this thirdparty (similar code exists in page index.php to make automatic binding)
if (!empty($conf->global->ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY)) {
if (!empty($buyer->code_compta)) {
$code_sell_t = $buyer->code_compta;
$suggestedid = $accountingAccount['thirdparty'];
$suggestedaccountingaccountfor = 'thridparty';
}
}
// Manage Deposit
if ($factureDet->desc == "(DEPOSIT)") {
$accountdeposittoventilated = new self($this->db);
$result = $accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT, 1);
if ($result < 0) {
return -1;
}
$code_sell_l = $accountdeposittoventilated->ref;
$suggestedid = $accountdeposittoventilated->rowid;
$suggestedaccountingaccountfor = 'deposit';
}
if (empty($suggestedid) && empty($code_sell_p) && !empty($code_sell_l) && empty($conf->global->ACCOUNTANCY_DO_NOT_AUTOFILL_ACCOUNT_WITH_GENERIC)) {
if (empty($this->accountingaccount_codetotid_cache[$code_sell_l])) {
$tmpaccount = new self($this->db);
$result = $tmpaccount->fetch(0, $code_sell_l, 1);
if ($result < 0) {
return -1;
}
if ($tmpaccount->id > 0) {
$suggestedid = $tmpaccount->id;
}
$this->accountingaccount_codetotid_cache[$code_sell_l] = $tmpaccount->id;
} else {
$suggestedid = $this->accountingaccount_codetotid_cache[$code_sell_l];
}
}
return array(
'suggestedaccountingaccountbydefaultfor' => $suggestedaccountingaccountbydefaultfor,
'suggestedaccountingaccountfor' => $suggestedaccountingaccountfor,
'suggestedid' => $suggestedid,
'code_sell_l' => $code_sell_l,
'code_sell_p' => $code_sell_p,
'code_sell_t' => $code_sell_t,
);
} else {
if (is_array($hookmanager->resArray) && !empty($hookmanager->resArray)) {
return $hookmanager->resArray;
}
}
}

View File

@ -31,6 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
// Load translation files required by the page
$langs->loadLangs(array("compta", "bills", "other", "accountancy"));
@ -46,6 +47,7 @@ if (!$user->rights->accounting->bind->write) {
accessforbidden();
}
$accountingAccount = new AccountingAccount($db);
$month_start = ($conf->global->SOCIETE_FISCAL_MONTH_START ? ($conf->global->SOCIETE_FISCAL_MONTH_START) : 1);
if (GETPOST("year", 'int')) {
@ -172,35 +174,75 @@ if ($action == 'validatehistory') {
$isSellerInEEC = isInEEC($mysoc);
$thirdpartystatic = new Societe($db);
$facture_static = new Facture($db);
$facture_static_det = new FactureLigne($db);
$product_static = new Product($db);
$i = 0;
while ($i < min($num_lines, 10000)) { // No more than 10000 at once
$objp = $db->fetch_object($result);
$isBuyerInEEC = isInEEC($objp); // This make a database request but there is a cache into $conf->cache['country_code_in_EEC']
$thirdpartystatic->id = $objp->socid;
$thirdpartystatic->name = $objp->name;
$thirdpartystatic->client = $objp->client;
$thirdpartystatic->fournisseur = $objp->fournisseur;
$thirdpartystatic->code_client = $objp->code_client;
$thirdpartystatic->code_compta_client = $objp->code_compta_client;
$thirdpartystatic->code_fournisseur = $objp->code_fournisseur;
$thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
$thirdpartystatic->email = $objp->email;
$thirdpartystatic->country_code = $objp->country_code;
$thirdpartystatic->tva_intra = $objp->tva_intra;
$thirdpartystatic->code_compta = $objp->company_code_sell;
// Level 2: Search suggested account for product/service (similar code exists in page list.php to make manual binding)
$suggestedaccountingaccountfor = '';
if (($objp->country_code == $mysoc->country_code) || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = $objp->aarowid;
$suggestedaccountingaccountfor = '';
$product_static->ref = $objp->product_ref;
$product_static->id = $objp->product_id;
$product_static->type = $objp->type;
$product_static->label = $objp->product_label;
$product_static->status = $objp->status;
$product_static->status_buy = $objp->status_buy;
$product_static->accountancy_code_sell = $objp->code_sell;
$product_static->accountancy_code_sell_intra = $objp->code_sell_intra;
$product_static->accountancy_code_sell_export = $objp->code_sell_export;
$product_static->accountancy_code_buy = $objp->code_buy;
$product_static->accountancy_code_buy_intra = $objp->code_buy_intra;
$product_static->accountancy_code_buy_export = $objp->code_buy_export;
$product_static->tva_tx = $objp->tva_tx_prod;
$product_static->tva_tx = $objp->tva_tx_prod;
$facture_static->ref = $objp->ref;
$facture_static->id = $objp->facid;
$facture_static->type = $objp->ftype;
$facture_static->datef = $objp->datef;
$facture_static_det->id = $objp->rowid;
$facture_static_det->total_ht = $objp->total_ht;
$facture_static_det->tva_tx = $objp->tva_tx_line;
$facture_static_det->vat_src_code = $objp->vat_src_code;
$facture_static_det->product_type = $objp->type_l;
$facture_static_det->desc = $objp->description;
$accoutinAccountArray = array(
'dom'=>$objp->aarowid,
'intra'=>$objp->aarowid_intra,
'export'=>$objp->aarowid_export,
'thirdparty' =>$objp->aarowid_thirdparty);
$code_sell_p_notset = '';
$code_sell_t_notset = '';
$return=$accountingAccount->getAccountingCodeToBind($thirdpartystatic, $mysoc, $product_static, $facture_static, $facture_static_det, $accoutinAccountArray);
if (!is_array($return) && $return<0) {
setEventMessage($accountingAccount->error, 'errors');
} else {
if ($isSellerInEEC && $isBuyerInEEC && $objp->tva_tx_line != 0) { // European intravat sale, but with VAT
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = $objp->aarowid;
$suggestedaccountingaccountfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($objp->tva_intra)) { // European intravat sale, without VAT intra community number
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = 0; // There is a doubt, no automatic binding
$suggestedaccountingaccountfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$objp->code_sell_p = $objp->code_sell_intra;
$objp->aarowid_suggest = $objp->aarowid_intra;
$suggestedaccountingaccountfor = 'eec';
} else { // Foreign sale
$objp->code_sell_p = $objp->code_sell_export;
$objp->aarowid_suggest = $objp->aarowid_export;
$suggestedaccountingaccountfor = 'export';
$suggestedid=$return['suggestedid'];
$suggestedaccountingaccountfor=$return['suggestedaccountingaccountfor'];
if (!empty($suggestedid) && $suggestedaccountingaccountfor<>'') {
$suggestedid=$return['suggestedid'];
} else {
$suggestedid=0;
}
}
@ -215,8 +257,8 @@ if ($action == 'validatehistory') {
if ($objp->aarowid_suggest > 0) {
$sqlupdate = "UPDATE ".MAIN_DB_PREFIX."facturedet";
$sqlupdate .= " SET fk_code_ventilation = ".((int) $objp->aarowid_suggest);
$sqlupdate .= " WHERE fk_code_ventilation <= 0 AND product_type <= 2 AND rowid = ".((int) $objp->rowid);
$sqlupdate .= " SET fk_code_ventilation = ".((int) $suggestedid);
$sqlupdate .= " WHERE fk_code_ventilation <= 0 AND product_type <= 2 AND rowid = ".((int) $facture_static_det->id);
$resqlupdate = $db->query($sqlupdate);
if (!$resqlupdate) {

View File

@ -45,6 +45,7 @@ $massaction = GETPOST('massaction', 'alpha');
$show_files = GETPOST('show_files', 'int');
$confirm = GETPOST('confirm', 'alpha');
$toselect = GETPOST('toselect', 'array');
$optioncss = GETPOST('optioncss', 'alpha');
// Select Box
$mesCasesCochees = GETPOST('toselect', 'array');
@ -96,6 +97,7 @@ if (!$sortorder) {
$hookmanager->initHooks(array('accountancycustomerlist'));
$formaccounting = new FormAccounting($db);
$accountingAccount = new AccountingAccount($db);
$chartaccountcode = dol_getIdFromCode($db, $conf->global->CHARTOFACCOUNTS, 'accounting_system', 'rowid', 'pcg_version');
@ -510,17 +512,17 @@ if ($result) {
$thirdpartystatic = new Societe($db);
$facture_static = new Facture($db);
$facture_static_det = new FactureLigne($db);
$product_static = new Product($db);
$isSellerInEEC = isInEEC($mysoc);
$accountingaccount_codetotid_cache = array();
while ($i < min($num_lines, $limit)) {
$objp = $db->fetch_object($result);
$objp->code_sell_l = '';
$objp->code_sell_p = '';
$code_sell_l = '';
$code_sell_p = '';
$thirdpartystatic->id = $objp->socid;
$thirdpartystatic->name = $objp->name;
@ -532,6 +534,8 @@ if ($result) {
$thirdpartystatic->code_compta_fournisseur = $objp->code_compta_fournisseur;
$thirdpartystatic->email = $objp->email;
$thirdpartystatic->country_code = $objp->country_code;
$thirdpartystatic->tva_intra = $objp->tva_intra;
$thirdpartystatic->code_compta = $objp->company_code_sell;
$product_static->ref = $objp->product_ref;
$product_static->id = $objp->product_id;
@ -545,146 +549,84 @@ if ($result) {
$product_static->accountancy_code_buy = $objp->code_buy;
$product_static->accountancy_code_buy_intra = $objp->code_buy_intra;
$product_static->accountancy_code_buy_export = $objp->code_buy_export;
$product_static->tva_tx = $objp->tva_tx_prod;
$product_static->tva_tx = $objp->tva_tx_prod;
$facture_static->ref = $objp->ref;
$facture_static->id = $objp->facid;
$facture_static->type = $objp->ftype;
$facture_static->datef = $objp->datef;
$facture_static_det->id = $objp->rowid;
$facture_static_det->total_ht = $objp->total_ht;
$facture_static_det->tva_tx = $objp->tva_tx_line;
$facture_static_det->vat_src_code = $objp->vat_src_code;
$facture_static_det->product_type = $objp->type_l;
$facture_static_det->desc = $objp->description;
$accoutinAccountArray = array(
'dom'=>$objp->aarowid,
'intra'=>$objp->aarowid_intra,
'export'=>$objp->aarowid_export,
'thirdparty' =>$objp->aarowid_thirdparty);
$code_sell_p_notset = '';
$code_sell_t_notset = '';
$objp->aarowid_suggest = ''; // Will be set later
$isBuyerInEEC = isInEEC($objp);
// Level 1: Search suggested default account for product/service
$suggestedaccountingaccountbydefaultfor = '';
if ($objp->type_l == 1) {
if ($objp->country_code == $mysoc->country_code || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = '';
} else {
if ($isSellerInEEC && $isBuyerInEEC && $objp->tva_tx_line != 0) { // European intravat sale, but with a VAT
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($objp->tva_intra)) { // European intravat sale, without VAT intra community number
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eec';
} else { // Foreign sale
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT) ? $conf->global->ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'export';
}
}
} elseif ($objp->type_l == 0) {
if ($objp->country_code == $mysoc->country_code || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = '';
} else {
if ($isSellerInEEC && $isBuyerInEEC && $objp->tva_tx_line != 0) { // European intravat sale, but with a VAT
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($objp->tva_intra)) { // European intravat sale, without VAT intra community number
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'eec';
} else {
$objp->code_sell_l = (!empty($conf->global->ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT) ? $conf->global->ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT : '');
$suggestedaccountingaccountbydefaultfor = 'export';
}
}
}
if ($objp->code_sell_l == -1) {
$objp->code_sell_l = '';
}
// Level 2: Search suggested account for product/service (similar code exists in page index.php to make automatic binding)
$suggestedaccountingaccountfor = '';
if (($objp->country_code == $mysoc->country_code) || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country)
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = $objp->aarowid;
$suggestedaccountingaccountfor = '';
$return=$accountingAccount->getAccountingCodeToBind($thirdpartystatic, $mysoc, $product_static, $facture_static, $facture_static_det, $accoutinAccountArray);
if (!is_array($return) && $return<0) {
setEventMessage($accountingAccount->error, 'errors');
} else {
if ($isSellerInEEC && $isBuyerInEEC && $objp->tva_tx_line != 0) { // European intravat sale, but with VAT
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = $objp->aarowid;
$suggestedaccountingaccountfor = 'eecwithvat';
} elseif ($isSellerInEEC && $isBuyerInEEC && empty($objp->tva_intra)) { // European intravat sale, without VAT intra community number
$objp->code_sell_p = $objp->code_sell;
$objp->aarowid_suggest = $objp->aarowid; // There is a doubt for this case. Is it an error on vat or we just forgot to fill vat number ?
$suggestedaccountingaccountfor = 'eecwithoutvatnumber';
} elseif ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale
$objp->code_sell_p = $objp->code_sell_intra;
$objp->aarowid_suggest = $objp->aarowid_intra;
$suggestedaccountingaccountfor = 'eec';
} else { // Foreign sale
$objp->code_sell_p = $objp->code_sell_export;
$objp->aarowid_suggest = $objp->aarowid_export;
$suggestedaccountingaccountfor = 'export';
}
$suggestedid=$return['suggestedid'];
$suggestedaccountingaccountfor=$return['suggestedaccountingaccountfor'];
$suggestedaccountingaccountbydefaultfor=$return['suggestedaccountingaccountbydefaultfor'];
$code_sell_l=$return['code_sell_l'];
$code_sell_p=$return['code_sell_p'];
$code_sell_t=$return['code_sell_t'];
}
//var_dump($return);
// Level 3: Search suggested account for this thirdparty (similar code exists in page index.php to make automatic binding)
if (!empty($conf->global->ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY)) {
if (!empty($objp->company_code_sell)) {
$objp->code_sell_t = $objp->company_code_sell;
$objp->aarowid_suggest = $objp->aarowid_thirdparty;
$suggestedaccountingaccountfor = '';
}
}
// Manage Deposit
if ($objp->description == "(DEPOSIT)") {
$accountdeposittoventilated = new AccountingAccount($db);
$accountdeposittoventilated->fetch('', $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER_DEPOSIT, 1);
$objp->code_sell_l = $accountdeposittoventilated->ref;
$objp->aarowid_suggest = $accountdeposittoventilated->rowid;
}
if (!empty($objp->code_sell_p)) {
if (!empty($code_sell_p)) {
// Value was defined previously
} else {
$code_sell_p_notset = 'color:orange';
}
if (empty($objp->code_sell_l) && empty($objp->code_sell_p)) {
if (empty($code_sell_l) && empty($code_sell_p)) {
$code_sell_p_notset = 'color:red';
}
if ($suggestedaccountingaccountfor == 'eecwithoutvatnumber' && empty($code_sell_p_notset)) {
$code_sell_p_notset = 'color:orange';
}
// $objp->code_sell_l is now default code of product/service
// $objp->code_sell_p is now code of product/service
// $objp->code_sell_t is now code of thirdparty
// $code_sell_l is now default code of product/service
// $code_sell_p is now code of product/service
// $code_sell_t is now code of thirdparty
print '<tr class="oddeven">';
// Line id
print '<td>'.$objp->rowid.'</td>';
print '<td>'.$facture_static_det->id.'</td>';
// Ref Invoice
print '<td class="nowraponall">'.$facture_static->getNomUrl(1).'</td>';
print '<td class="center">'.dol_print_date($db->jdate($objp->datef), 'day').'</td>';
print '<td class="center">'.dol_print_date($db->jdate($facture_static->datef), 'day').'</td>';
// Ref Product
print '<td class="tdoverflowmax150">';
if ($product_static->id > 0) {
print $product_static->getNomUrl(1);
}
if ($objp->product_label) {
print '<br><span class="opacitymedium small">'.$objp->product_label.'</span>';
if ($product_static->label) {
print '<br><span class="opacitymedium small">'.$product_static->label.'</span>';
}
print '</td>';
// Description
print '<td class="tdoverflowonsmartphone small">';
$text = dolGetFirstLineOfText(dol_string_nohtmltag($objp->description));
$text = dolGetFirstLineOfText(dol_string_nohtmltag($facture_static_det->desc));
$trunclength = empty($conf->global->ACCOUNTING_LENGTH_DESCRIPTION) ? 32 : $conf->global->ACCOUNTING_LENGTH_DESCRIPTION;
print $form->textwithtooltip(dol_trunc($text, $trunclength), $objp->description);
print $form->textwithtooltip(dol_trunc($text, $trunclength), $facture_static_det->desc);
print '</td>';
print '<td class="right nowraponall amount">';
@ -692,11 +634,12 @@ if ($result) {
print '</td>';
// Vat rate
if ($objp->vat_tx_l != $objp->vat_tx_p) {
$code_vat_differ='';
if ($product_static->tva_tx !== $facture_static_det->tva_tx) {
$code_vat_differ = 'font-weight:bold; text-decoration:blink; color:red';
}
print '<td style="'.$code_vat_differ.'" class="right">';
print vatrate($objp->tva_tx_line.($objp->vat_src_code ? ' ('.$objp->vat_src_code.')' : ''));
print vatrate($facture_static_det->tva_tx.($facture_static_det->vat_src_code ? ' ('.$facture_static_det->vat_src_code.')' : ''));
print '</td>';
// Thirdparty
@ -713,18 +656,18 @@ if ($result) {
// Found accounts
print '<td class="small">';
$s = '1. '.(($objp->type_l == 1) ? $langs->trans("DefaultForService") : $langs->trans("DefaultForProduct")).': ';
$s = '1. '.(($facture_static_det->product_type == 1) ? $langs->trans("DefaultForService") : $langs->trans("DefaultForProduct")).': ';
$shelp = '';
if ($suggestedaccountingaccountbydefaultfor == 'eec') {
$shelp .= $langs->trans("SaleEEC");
} elseif ($suggestedaccountingaccountbydefaultfor == 'export') {
$shelp .= $langs->trans("SaleExport");
}
$s .= ($objp->code_sell_l > 0 ? length_accountg($objp->code_sell_l) : '<span style="'.$code_sell_p_notset.'">'.$langs->trans("NotDefined").'</span>');
$s .= ($code_sell_l > 0 ? length_accountg($code_sell_l) : '<span style="'.$code_sell_p_notset.'">'.$langs->trans("NotDefined").'</span>');
print $form->textwithpicto($s, $shelp, 1, 'help', '', 0, 2, '', 1);
if ($objp->product_id > 0) {
if ($product_static->id > 0) {
print '<br>';
$s = '2. '.(($objp->type_l == 1) ? $langs->trans("ThisService") : $langs->trans("ThisProduct")).': ';
$s = '2. '.(($facture_static_det->product_type == 1) ? $langs->trans("ThisService") : $langs->trans("ThisProduct")).': ';
$shelp = ''; $ttype = 'help';
if ($suggestedaccountingaccountfor == 'eec') {
$shelp = $langs->trans("SaleEEC");
@ -736,7 +679,7 @@ if ($result) {
} elseif ($suggestedaccountingaccountfor == 'export') {
$shelp = $langs->trans("SaleExport");
}
$s .= (empty($objp->code_sell_p) ? '<span style="'.$code_sell_p_notset.'">'.$langs->trans("NotDefined").'</span>' : length_accountg($objp->code_sell_p));
$s .= (empty($code_sell_p) ? '<span style="'.$code_sell_p_notset.'">'.$langs->trans("NotDefined").'</span>' : length_accountg($code_sell_p));
print $form->textwithpicto($s, $shelp, 1, $ttype, '', 0, 2, '', 1);
} else {
print '<br>';
@ -747,38 +690,26 @@ if ($result) {
}
if (!empty($conf->global->ACCOUNTANCY_USE_PRODUCT_ACCOUNT_ON_THIRDPARTY)) {
print '<br>';
$s = '3. '.(($objp->type_l == 1) ? $langs->trans("ServiceForThisThirdparty") : $langs->trans("ProductForThisThirdparty")).': ';
$s = '3. '.(($facture_static_det->product_type == 1) ? $langs->trans("ServiceForThisThirdparty") : $langs->trans("ProductForThisThirdparty")).': ';
$shelp = '';
$s .= ($objp->code_sell_t > 0 ? length_accountg($objp->code_sell_t) : '<span style="'.$code_sell_t_notset.'">'.$langs->trans("NotDefined").'</span>');
$s .= ($code_sell_t > 0 ? length_accountg($code_sell_t) : '<span style="'.$code_sell_t_notset.'">'.$langs->trans("NotDefined").'</span>');
print $form->textwithpicto($s, $shelp, 1, 'help', '', 0, 2, '', 1);
}
print '</td>';
// Suggested accounting account
print '<td>';
$suggestedid = $objp->aarowid_suggest;
if (empty($suggestedid) && empty($objp->code_sell_p) && !empty($objp->code_sell_l) && empty($conf->global->ACCOUNTANCY_DO_NOT_AUTOFILL_ACCOUNT_WITH_GENERIC)) {
if (empty($accountingaccount_codetotid_cache[$objp->code_sell_l])) {
$tmpaccount = new AccountingAccount($db);
$tmpaccount->fetch(0, $objp->code_sell_l, 1);
if ($tmpaccount->id > 0) {
$suggestedid = $tmpaccount->id;
}
$accountingaccount_codetotid_cache[$objp->code_sell_l] = $tmpaccount->id;
} else {
$suggestedid = $accountingaccount_codetotid_cache[$objp->code_sell_l];
}
}
print $formaccounting->select_account($suggestedid, 'codeventil'.$objp->rowid, 1, array(), 0, 0, 'codeventil maxwidth200 maxwidthonsmartphone', 'cachewithshowemptyone');
print $formaccounting->select_account($suggestedid, 'codeventil'.$facture_static_det->id, 1, array(), 0, 0, 'codeventil maxwidth200 maxwidthonsmartphone', 'cachewithshowemptyone');
print '</td>';
// Column with checkbox
print '<td class="center">';
$ischecked = $objp->aarowid_suggest;
if ($suggestedaccountingaccountfor == 'eecwithoutvatnumber') {
if (!empty($suggestedid) && $suggestedaccountingaccountfor<>'') {
$ischecked=1;
} elseif ($suggestedaccountingaccountfor == 'eecwithoutvatnumber') {
$ischecked = 0;
}
print '<input type="checkbox" class="flat checkforselect checkforselect'.$objp->rowid.'" name="toselect[]" value="'.$objp->rowid."_".$i.'"'.($ischecked ? "checked" : "").'/>';
print '<input type="checkbox" class="flat checkforselect checkforselect'.$facture_static_det->id.'" name="toselect[]" value="'.$facture_static_det->id."_".$i.'"'.($ischecked ? "checked" : "").'/>';
print '</td>';
print '</tr>';

View File

@ -4,7 +4,7 @@
* Copyright (C) 2017 Regis Houssin <regis.houssin@inodbox.com>
* Copyright (C) 2017 Neil Orley <neil.orley@oeris.fr>
* Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2018-2020 Thibault FOUCART <support@ptibogxiv.net>
* Copyright (C) 2018-2021 Thibault FOUCART <support@ptibogxiv.net>
*
*
* This program is free software; you can redistribute it and/or modify
@ -1340,6 +1340,64 @@ class Setup extends DolibarrApi
return $list;
}
/**
* Get the list of staff.
*
* @param string $sortfield Sort field
* @param string $sortorder Sort order
* @param int $limit Number of items per page
* @param int $page Page number (starting from zero)
* @param int $active Staff is active or not {@min 0} {@max 1}
* @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
* @return array List of staff
*
* @url GET dictionary/staff
*
* @throws RestException
*/
public function getListOfStaff($sortfield = "id", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
{
$list = array();
$sql = "SELECT t.id, t.code, t.libelle, t.active, t.module";
$sql .= " FROM ".MAIN_DB_PREFIX."c_effectif as t";
$sql .= " WHERE t.active = ".((int) $active);
// Add sql filters
if ($sqlfilters) {
if (!DolibarrApi::_checkFilters($sqlfilters)) {
throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
}
$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}
$sql .= $this->db->order($sortfield, $sortorder);
if ($limit) {
if ($page < 0) {
$page = 0;
}
$offset = $limit * $page;
$sql .= $this->db->plimit($limit, $offset);
}
$result = $this->db->query($sql);
if ($result) {
$num = $this->db->num_rows($result);
$min = min($num, ($limit <= 0 ? $num : $limit));
for ($i = 0; $i < $min; $i++) {
$list[] = $this->db->fetch_object($result);
}
} else {
throw new RestException(503, 'Error when retrieving list of staff: '.$this->db->lasterror());
}
return $list;
}
/**
* Get the list of social networks.
*

View File

@ -1503,7 +1503,7 @@ class Account extends CommonObject
{
$country_code = $this->getCountryCode();
if (in_array($country_code, array('FR', 'ES', 'GA', 'IT', 'NC'))) {
if (in_array($country_code, array('AD', 'FR', 'ES', 'GA', 'IT', 'NC'))) {
return 1; // France, Spain, Gabon, ... - Not valid for CH
}
if (in_array($country_code, array('AU', 'BE', 'CA', 'DE', 'DK', 'GR', 'GB', 'ID', 'IE', 'IR', 'KR', 'NL', 'NZ', 'UK', 'US'))) {

View File

@ -99,6 +99,8 @@ if (GETPOST('roworder', 'alpha', 3) && GETPOST('table_element_line', 'aZ09', 3)
$perm = 1;
} elseif ($table_element_line == 'ecm_files' && $fk_element == 'fk_ticket' && !empty($user->rights->ticket->write)) {
$perm = 1;
} elseif ($table_element_line == 'product_association' && $fk_element == 'fk_product' && !empty($user->rights->produit->creer)) {
$perm = 1;
} elseif ($table_element_line == 'projet_task' && $fk_element == 'fk_projet' && $user->rights->projet->creer) {
$perm = 1;
} else {

View File

@ -3038,7 +3038,7 @@ abstract class CommonObject
*
* @param int $rowid Id of line
* @param int $rang Position
* @return void
* @return int <0 if KO, >0 if OK
*/
public function updateRangOfLine($rowid, $rang)
{
@ -3054,10 +3054,13 @@ abstract class CommonObject
dol_syslog(get_class($this)."::updateRangOfLine", LOG_DEBUG);
if (!$this->db->query($sql)) {
dol_print_error($this->db);
return -1;
} else {
$parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
$action='';
$reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
return 1;
}
$parameters=array('rowid'=>$rowid, 'rang'=>$rang, 'fieldposition' => $fieldposition);
$action='';
$reshook = $hookmanager->executeHooks('afterRankOfLineUpdate', $parameters, $this, $action);
}
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps

View File

@ -103,6 +103,7 @@ ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_categorie_ro
ALTER TABLE llx_categorie_ticket ADD CONSTRAINT fk_categorie_ticket_ticket_rowid FOREIGN KEY (fk_ticket) REFERENCES llx_ticket (rowid);
ALTER TABLE llx_product_fournisseur_price MODIFY COLUMN ref_fourn varchar(128);
ALTER TABLE llx_product_customer_price MODIFY COLUMN ref_customer varchar(128);
ALTER TABLE llx_product_association ADD COLUMN rang integer DEFAULT 0;
-- -- add action trigger
INSERT INTO llx_c_action_trigger (code,label,description,elementtype,rang) VALUES ('ORDER_SUPPLIER_CANCEL','Supplier order request canceled','Executed when a supplier order is canceled','order_supplier',13);

View File

@ -23,6 +23,7 @@ create table llx_product_association
fk_product_pere integer NOT NULL DEFAULT 0, -- id du produit maitre
fk_product_fils integer NOT NULL DEFAULT 0, -- id du sous-produit
qty double NULL,
incdec integer DEFAULT 1 -- when set to 1 changing stock of product will change stock of linked product too
incdec integer DEFAULT 1, -- when set to 1 changing stock of product will change stock of linked product too
rang integer DEFAULT 0
)ENGINE=innodb;

View File

@ -401,11 +401,10 @@ DeleteLinkedProduct=Delete the child product linked to the combination
AmountUsedToUpdateWAP=Amount to use to update the Weighted Average Price
PMPValue=Weighted average price
PMPValueShort=WAP
mandatoryperiod=Mandatory periods
mandatoryPeriodNeedTobeSet=Attention periods not entered and mandatory
mandatoryPeriodNeedTobeSetMsgValidate=A service requires a start and end period
mandatoryHelper=Message to the user on the need to enter a start date and an end date on a service when creating / validating an invoice, commercial proposal, sales order. <br> This action is not blocking in the process of confirmation
DefaultBOM=Default BOM
DefaultBOMDesc=The default BOM recommended to use to manufacture this product. This field can be set only if nature of product is '%s'.
DefaultBOMDesc=The default BOM recommended to use to manufacture this product. This field can be set only if nature of product is '%s'.
Rank=Rank

View File

@ -399,6 +399,7 @@ ProductSupplierExtraFields=Attributs supplémentaires (Prix fournisseur)
DeleteLinkedProduct=Supprimer le produit enfant lié à la combinaison
PMPValue=Prix moyen pondéré (PMP)
PMPValueShort=PMP
Rank=Rang
mandatoryperiod=Périodes obligatoires
mandatoryPeriodNeedTobeSet=Attention périodes non saisies et obligatoires
mandatoryPeriodNeedTobeSetMsgValidate=Un service nécessite une période de début et de fin

View File

@ -4021,28 +4021,31 @@ class Product extends CommonObject
}
// Check not already father of id_pere (to avoid father -> child -> father links)
$sql = 'SELECT fk_product_pere from '.MAIN_DB_PREFIX.'product_association';
$sql .= ' WHERE fk_product_pere = '.((int) $id_fils).' AND fk_product_fils = '.((int) $id_pere);
$sql = "SELECT fk_product_pere from ".MAIN_DB_PREFIX."product_association";
$sql .= " WHERE fk_product_pere = ".((int) $id_fils)." AND fk_product_fils = ".((int) $id_pere);
if (!$this->db->query($sql)) {
dol_print_error($this->db);
return -1;
} else {
$result = $this->db->query($sql);
if ($result) {
$num = $this->db->num_rows($result);
if ($num > 0) {
$this->error = "isFatherOfThis";
//Selection of the highest row
$sql = "SELECT MAX(rang) as max_rank FROM ".MAIN_DB_PREFIX."product_association";
$sql .= " WHERE fk_product_pere = ".((int) $id_pere);
$resql = $this->db->query($sql);
if ($resql > 0) {
$obj = $this->db->fetch_object($resql);
$rank = $obj->max_rank + 1;
//Addition of a product with the highest rank +1
$sql = "INSERT INTO ".MAIN_DB_PREFIX."product_association(fk_product_pere,fk_product_fils,qty,incdec,rang)";
$sql .= " VALUES (".((int) $id_pere).", ".((int) $id_fils).", ".((float) $qty).", ".((float) $incdec).", ".$this->db->escape($rank).")";
if (! $this->db->query($sql)) {
dol_print_error($this->db);
return -1;
} else {
$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_association(fk_product_pere,fk_product_fils,qty,incdec)';
$sql .= ' VALUES ('.((int) $id_pere).', '.((int) $id_fils).', '.((float) $qty).', '.((int) $incdec).')';
if (!$this->db->query($sql)) {
dol_print_error($this->db);
return -1;
} else {
return 1;
}
return 1;
}
} else {
dol_print_error($this->db);
return -1;
}
}
}
@ -4115,6 +4118,24 @@ class Product extends CommonObject
return -1;
}
//Updated ranks so that none are missing
$sqlrank = 'SELECT rowid, rang FROM '.MAIN_DB_PREFIX.'product_association';
$sqlrank.= ' WHERE fk_product_pere = '.$this->db->escape($fk_parent);
$sqlrank.= ' ORDER BY rang';
$resqlrank = $this->db->query($sqlrank);
if ($resqlrank) {
$cpt = 0;
while ($objrank = $this->db->fetch_object($resqlrank)) {
$cpt++;
$sql = 'UPDATE '.MAIN_DB_PREFIX.'product_association';
$sql.= ' SET rang ='.$cpt;
$sql.= ' WHERE rowid ='.$this->db->escape($objrank->rowid);
if (! $this->db->query($sql)) {
dol_print_error($this->db);
return -1;
}
}
}
return 1;
}
@ -4679,12 +4700,14 @@ class Product extends CommonObject
}
$sql = "SELECT p.rowid, p.ref, p.label as label, p.fk_product_type,";
$sql .= " pa.qty as qty, pa.fk_product_fils as id, pa.incdec";
$sql .= " pa.qty as qty, pa.fk_product_fils as id, pa.incdec,";
$sql .= " pa.rowid as fk_association, pa.rang";
$sql .= " FROM ".MAIN_DB_PREFIX."product as p,";
$sql .= " ".MAIN_DB_PREFIX."product_association as pa";
$sql .= " WHERE p.rowid = pa.fk_product_fils";
$sql .= " AND pa.fk_product_pere = ".((int) $id);
$sql .= " AND pa.fk_product_fils <> ".((int) $id); // This should not happens, it is to avoid infinite loop if it happens
$sql.= " ORDER BY pa.rang";
dol_syslog(get_class($this).'::getChildsArbo id='.$id.' level='.$level, LOG_DEBUG);
@ -4711,7 +4734,9 @@ class Product extends CommonObject
2=>$rec['fk_product_type'],
3=>$this->db->escape($rec['label']),
4=>$rec['incdec'],
5=>$rec['ref']
5=>$rec['ref'],
6=>$rec['fk_association'],
7=>$rec['rang']
);
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty'],2=>$rec['fk_product_type']);
//$prods[$this->db->escape($rec['label'])]= array(0=>$rec['id'],1=>$rec['qty']);
@ -5306,7 +5331,7 @@ class Product extends CommonObject
}
$stock_commande_fournisseur = $this->stats_commande_fournisseur['qty'];
}
if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) && empty($conf->reception->enabled)) {
if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled) || !empty($conf->supplier_invoice->enabled)) && !empty($conf->reception->enabled)) {
$filterStatus = '4';
if (isset($includedraftpoforvirtual)) {
$filterStatus = '0,'.$filterStatus;

View File

@ -132,6 +132,8 @@ if ($action == 'add_prod' && ($user->rights->produit->creer || $user->rights->se
setEventMessages('RecordSaved', null);
}
$action = '';
header("Location: ".$_SERVER["PHP_SELF"].'?id='.$object->id);
exit;
}
@ -268,8 +270,18 @@ if ($id > 0 || !empty($ref)) {
$prodsfather = $object->getFather(); // Parent Products
$object->get_sousproduits_arbo(); // Load $object->sousprods
$parent_label = $object->label;
$prods_arbo = $object->get_arbo_each_prod();
$tmpid = $id;
if (! empty($conf->use_javascript_ajax)) {
$nboflines = $prods_arbo;
$table_element_line='product_association';
include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php';
}
$id = $tmpid;
$nbofsubsubproducts = count($prods_arbo); // This include sub sub product into nb
$prodschild = $object->getChildsArbo($id, 1);
$nbofsubproducts = count($prodschild); // This include only first level of childs
@ -323,9 +335,10 @@ if ($id > 0 || !empty($ref)) {
print '<input type="hidden" name="action" value="save_composed_product" />';
print '<input type="hidden" name="id" value="'.$id.'" />';
print '<table class="liste">';
print '<table id="tablelines" class="ui-sortable liste">';
print '<tr class="liste_titre">';
print '<tr class="liste_titre nodrag nodrop">';
print '<td>'.$langs->trans('Rank').'</td>';
print '<td>'.$langs->trans('ComposedProduct').'</td>';
print '<td>'.$langs->trans('Label').'</td>';
print '<td class="right" colspan="2">'.$langs->trans('MinSupplierPrice').'</td>';
@ -335,6 +348,7 @@ if ($id > 0 || !empty($ref)) {
}
print '<td class="center">'.$langs->trans('Qty').'</td>';
print '<td class="center">'.$langs->trans('ComposedProductIncDecStock').'</td>';
print '<td class="linecolmove" style="width: 10px"></td>';
print '</tr>'."\n";
$totalsell = 0;
@ -343,7 +357,9 @@ if ($id > 0 || !empty($ref)) {
$productstatic->fetch($value['id']);
if ($value['level'] <= 1) {
print '<tr class="oddeven">';
print '<tr id="'.$object->sousprods[$parent_label][$value['id']][6].'" class="drag drop oddeven level1">';
print '<td>'.$object->sousprods[$parent_label][$value['id']][7].'</td>';
$notdefined = 0;
$nb_of_subproduct = $value['nb'];
@ -407,6 +423,8 @@ if ($id > 0 || !empty($ref)) {
print '<td>'.($value['incdec'] == 1 ? 'x' : '').'</td>';
}
print '<td class="linecolmove tdlineupdown center">';
print '</td>';
print '</tr>'."\n";
} else {
$hide = '';
@ -414,10 +432,11 @@ if ($id > 0 || !empty($ref)) {
$hide = ' hideobject'; // By default, we do not show this. It makes screen very difficult to understand
}
print '<tr class="oddeven'.$hide.'" id="sub-'.$value['id_parent'].'">';
print '<tr class="oddeven'.$hide.'" id="sub-'.$value['id_parent'].'" data-ignoreidfordnd=1>';
//$productstatic->ref=$value['label'];
$productstatic->ref = $value['ref'];
print '<td></td>';
print '<td>';
for ($i = 0; $i < $value['level']; $i++) {
print ' &nbsp; &nbsp; '; // Add indentation
@ -437,6 +456,7 @@ if ($id > 0 || !empty($ref)) {
}
print '<td class="center">'.$value['nb'].'</td>';
print '<td>&nbsp;</td>';
print '<td>&nbsp;</td>';
print '</tr>'."\n";
}

View File

@ -454,7 +454,7 @@ class Tasks extends DolibarrApi
throw new RestException(404, 'Task not found');
}
if (!DolibarrApi::_checkAccessToResource('tasks', $this->project->id)) {
if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}
foreach ($request_data as $field => $value) {
@ -488,7 +488,7 @@ class Tasks extends DolibarrApi
throw new RestException(404, 'Task not found');
}
if (!DolibarrApi::_checkAccessToResource('tasks', $this->project->id)) {
if (!DolibarrApi::_checkAccessToResource('task', $this->task->id)) {
throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
}