| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062 |
- <?php
- /* Copyright (C) 2017-2022 OpenDSI <support@open-dsi.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/accountancy/class/accountingjournal.class.php
- * \ingroup Accountancy (Double entries)
- * \brief File of class to manage accounting journals
- */
- /**
- * Class to manage accounting accounts
- */
- class AccountingJournal extends CommonObject
- {
- /**
- * @var string ID to identify managed object
- */
- public $element = 'accounting_journal';
- /**
- * @var string Name of table without prefix where object is stored
- */
- public $table_element = 'accounting_journal';
- /**
- * @var string Fieldname with ID of parent key if this field has a parent
- */
- public $fk_element = '';
- /**
- * @var int 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
- */
- public $ismultientitymanaged = 0;
- /**
- * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
- */
- public $picto = 'generic';
- /**
- * @var int ID
- */
- public $rowid;
- /**
- * @var string Accounting journal code
- */
- public $code;
- /**
- * @var string Accounting Journal label
- */
- public $label;
- /**
- * @var int 1:various operations, 2:sale, 3:purchase, 4:bank, 5:expense-report, 8:inventory, 9: has-new
- */
- public $nature;
- /**
- * @var int is active or not
- */
- public $active;
- /**
- * @var array array of lines
- */
- public $lines;
- /**
- * @var array Accounting account cached
- */
- static public $accounting_account_cached = array();
- /**
- * @var array Nature mapping
- */
- static public $nature_maps = array(
- 1 => 'variousoperations',
- 2 => 'sells',
- 3 => 'purchases',
- 4 => 'bank',
- 5 => 'expensereports',
- 8 => 'inventories',
- 9 => 'hasnew',
- );
- /**
- * Constructor
- *
- * @param DoliDB $db Database handle
- */
- public function __construct($db)
- {
- $this->db = $db;
- }
- /**
- * Load an object from database
- *
- * @param int $rowid Id of record to load
- * @param string $journal_code Journal code
- * @return int <0 if KO, Id of record if OK and found
- */
- public function fetch($rowid = null, $journal_code = null)
- {
- global $conf;
- if ($rowid || $journal_code) {
- $sql = "SELECT rowid, code, label, nature, active";
- $sql .= " FROM ".MAIN_DB_PREFIX."accounting_journal";
- $sql .= " WHERE";
- if ($rowid) {
- $sql .= " rowid = ".((int) $rowid);
- } elseif ($journal_code) {
- $sql .= " code = '".$this->db->escape($journal_code)."'";
- $sql .= " AND entity = ".$conf->entity;
- }
- dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
- $result = $this->db->query($sql);
- if ($result) {
- $obj = $this->db->fetch_object($result);
- if ($obj) {
- $this->id = $obj->rowid;
- $this->rowid = $obj->rowid;
- $this->code = $obj->code;
- $this->ref = $obj->code;
- $this->label = $obj->label;
- $this->nature = $obj->nature;
- $this->active = $obj->active;
- return $this->id;
- } else {
- return 0;
- }
- } else {
- $this->error = "Error ".$this->db->lasterror();
- $this->errors[] = "Error ".$this->db->lasterror();
- }
- }
- return -1;
- }
- /**
- * Load object in memory from the database
- *
- * @param string $sortorder Sort Order
- * @param string $sortfield Sort field
- * @param int $limit offset limit
- * @param int $offset offset limit
- * @param array $filter filter array
- * @param string $filtermode filter mode (AND or OR)
- *
- * @return int <0 if KO, >0 if OK
- */
- public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
- {
- $sql = "SELECT rowid, code, label, nature, active";
- $sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t';
- // Manage filter
- $sqlwhere = array();
- if (count($filter) > 0) {
- foreach ($filter as $key => $value) {
- if ($key == 't.code' || $key == 't.label' || $key == 't.nature') {
- $sqlwhere[] = $key.'\''.$this->db->escape($value).'\'';
- } elseif ($key == 't.rowid' || $key == 't.active') {
- $sqlwhere[] = $key.'='.$value;
- }
- }
- }
- $sql .= ' WHERE 1 = 1';
- $sql .= " AND entity IN (".getEntity('accountancy').")";
- if (count($sqlwhere) > 0) {
- $sql .= " AND ".implode(" ".$filtermode." ", $sqlwhere);
- }
- if (!empty($sortfield)) {
- $sql .= $this->db->order($sortfield, $sortorder);
- }
- if (!empty($limit)) {
- $sql .= $this->db->plimit($limit + 1, $offset);
- }
- $this->lines = array();
- dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
- $resql = $this->db->query($sql);
- if ($resql) {
- $num = $this->db->num_rows($resql);
- while ($obj = $this->db->fetch_object($resql)) {
- $line = new self($this->db);
- $line->id = $obj->rowid;
- $line->code = $obj->code;
- $line->label = $obj->label;
- $line->nature = $obj->nature;
- $line->active = $obj->active;
- $this->lines[] = $line;
- }
- $this->db->free($resql);
- return $num;
- } else {
- $this->errors[] = 'Error '.$this->db->lasterror();
- dol_syslog(__METHOD__.' '.join(',', $this->errors), LOG_ERR);
- return -1;
- }
- }
- /**
- * 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 journal, 2=Include nature of journal
- * @param int $nourl 1=Disable url
- * @param string $moretitle Add more text to title tooltip
- * @param int $notooltip 1=Disable tooltip
- * @return string String with URL
- */
- public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
- {
- global $langs, $conf, $user, $hookmanager;
- if (!empty($conf->dol_no_mouse_hover)) {
- $notooltip = 1; // Force disable tooltips
- }
- $result = '';
- $url = DOL_URL_ROOT.'/accountancy/admin/journals_list.php?id=35';
- $label = '<u>'.$langs->trans("ShowAccountingJournal").'</u>';
- if (!empty($this->code)) {
- $label .= '<br><b>'.$langs->trans('Code').':</b> '.$this->code;
- }
- if (!empty($this->label)) {
- $label .= '<br><b>'.$langs->trans('Label').':</b> '.$langs->transnoentities($this->label);
- }
- if ($moretitle) {
- $label .= ' - '.$moretitle;
- }
- $linkclose = '';
- if (empty($notooltip)) {
- if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
- $label = $langs->trans("ShowAccountingJournal");
- $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
- }
- $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
- $linkclose .= ' class="classfortooltip"';
- }
- $linkstart = '<a href="'.$url.'"';
- $linkstart .= $linkclose.'>';
- $linkend = '</a>';
- if ($nourl) {
- $linkstart = '';
- $linkclose = '';
- $linkend = '';
- }
- $label_link = $this->code;
- if ($withlabel != 2 && !empty($this->label)) {
- $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$langs->transnoentities($this->label).($nourl ? '</span>' : '');
- }
- if ($withlabel == 2 && !empty($this->nature)) {
- $key = $langs->trans("AccountingJournalType".strtoupper($this->nature));
- $transferlabel = ($this->nature && $key != "AccountingJournalType".strtoupper($langs->trans($this->nature)) ? $key : $this->label);
- $label_link .= ' - '.($nourl ? '<span class="opacitymedium">' : '').$transferlabel.($nourl ? '</span>' : '');
- }
- $result .= $linkstart;
- if ($withpicto) {
- $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
- }
- if ($withpicto != 2) {
- $result .= $label_link;
- }
- $result .= $linkend;
- global $action;
- $hookmanager->initHooks(array('accountingjournaldao'));
- $parameters = array('id'=>$this->id, 'getnomurl' => &$result);
- $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
- if ($reshook > 0) {
- $result = $hookmanager->resPrint;
- } else {
- $result .= $hookmanager->resPrint;
- }
- return $result;
- }
- /**
- * Retourne le libelle du statut d'un user (actif, inactif)
- *
- * @param int $mode 0=libelle long, 1=libelle court
- * @return string Label of type
- */
- public function getLibType($mode = 0)
- {
- return $this->LibType($this->nature, $mode);
- }
- // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
- /**
- * Return type of an accounting journal
- *
- * @param int $nature Id type
- * @param int $mode 0=libelle long, 1=libelle court
- * @return string Label of type
- */
- public function LibType($nature, $mode = 0)
- {
- // phpcs:enable
- global $langs;
- $langs->loadLangs(array("accountancy"));
- if ($mode == 0) {
- $prefix = '';
- if ($nature == 9) {
- return $langs->trans('AccountingJournalType9');
- } elseif ($nature == 5) {
- return $langs->trans('AccountingJournalType5');
- } elseif ($nature == 4) {
- return $langs->trans('AccountingJournalType4');
- } elseif ($nature == 3) {
- return $langs->trans('AccountingJournalType3');
- } elseif ($nature == 2) {
- return $langs->trans('AccountingJournalType2');
- } elseif ($nature == 1) {
- return $langs->trans('AccountingJournalType1');
- }
- } elseif ($mode == 1) {
- if ($nature == 9) {
- return $langs->trans('AccountingJournalType9');
- } elseif ($nature == 5) {
- return $langs->trans('AccountingJournalType5');
- } elseif ($nature == 4) {
- return $langs->trans('AccountingJournalType4');
- } elseif ($nature == 3) {
- return $langs->trans('AccountingJournalType3');
- } elseif ($nature == 2) {
- return $langs->trans('AccountingJournalType2');
- } elseif ($nature == 1) {
- return $langs->trans('AccountingJournalType1');
- }
- }
- }
- /**
- * Get journal data
- *
- * @param User $user User who get infos
- * @param string $type Type data returned ('view', 'bookkeeping', 'csv')
- * @param int $date_start Filter 'start date'
- * @param int $date_end Filter 'end date'
- * @param string $in_bookkeeping Filter 'in bookkeeping' ('already', 'notyet')
- * @return array|int <0 if KO, >0 if OK
- */
- public function getData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
- {
- global $hookmanager;
- // Clean parameters
- if (empty($type)) $type = 'view';
- if (empty($in_bookkeeping)) $in_bookkeeping = 'notyet';
- // Hook
- if (!is_object($hookmanager)) {
- include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
- $hookmanager = new HookManager($this->db);
- }
- $data = array();
- $hookmanager->initHooks(array('accountingjournaldao'));
- $parameters = array('data' => &$data, 'user' => $user, 'type' => $type, 'date_start' => $date_start, 'date_end' => $date_end, 'in_bookkeeping' => $in_bookkeeping);
- $reshook = $hookmanager->executeHooks('getData', $parameters, $this); // Note that $action and $object may have been
- if ($reshook < 0) {
- $this->error = $hookmanager->error;
- $this->errors = $hookmanager->errors;
- return -1;
- } elseif (empty($reshook)) {
- switch ($this->nature) {
- case 1: // Various Journal
- $data = $this->getAssetData($user, $type, $date_start, $date_end, $in_bookkeeping);
- break;
- // case 2: // Sells Journal
- // case 3: // Purchases Journal
- // case 4: // Bank Journal
- // case 5: // Expense reports Journal
- // case 8: // Inventory Journal
- // case 9: // hasnew Journal
- }
- }
- return $data;
- }
- /**
- * Get asset data for various journal
- *
- * @param User $user User who get infos
- * @param string $type Type data returned ('view', 'bookkeeping', 'csv')
- * @param int $date_start Filter 'start date'
- * @param int $date_end Filter 'end date'
- * @param string $in_bookkeeping Filter 'in bookkeeping' ('already', 'notyet')
- * @return array|int <0 if KO, >0 if OK
- */
- public function getAssetData(User $user, $type = 'view', $date_start = null, $date_end = null, $in_bookkeeping = 'notyet')
- {
- global $conf, $langs;
- if (!isModEnabled('asset')) {
- return array();
- }
- require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
- require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
- require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
- require_once DOL_DOCUMENT_ROOT . '/asset/class/assetdepreciationoptions.class.php';
- $langs->loadLangs(array("assets"));
- // Clean parameters
- if (empty($type)) {
- $type = 'view';
- }
- if (empty($in_bookkeeping)) {
- $in_bookkeeping = 'notyet';
- }
- $sql = "";
- // FIXME sql error with Mysql 5.7
- /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
- $sql .= "WITH in_accounting_bookkeeping(fk_docdet) AS (";
- $sql .= " SELECT DISTINCT fk_docdet";
- $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping";
- $sql .= " WHERE doc_type = 'asset'";
- $sql .= ") ";
- }*/
- $sql .= "SELECT ad.fk_asset AS rowid, a.ref AS asset_ref, a.label AS asset_label, a.acquisition_value_ht AS asset_acquisition_value_ht";
- $sql .= ", a.disposal_date AS asset_disposal_date, a.disposal_amount_ht AS asset_disposal_amount_ht, a.disposal_subject_to_vat AS asset_disposal_subject_to_vat";
- $sql .= ", ad.rowid AS depreciation_id, ad.depreciation_mode, ad.ref AS depreciation_ref, ad.depreciation_date, ad.depreciation_ht, ad.accountancy_code_debit, ad.accountancy_code_credit";
- $sql .= " FROM " . MAIN_DB_PREFIX . "asset_depreciation as ad";
- $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "asset as a ON a.rowid = ad.fk_asset";
- // FIXME sql error with Mysql 5.7
- /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
- $sql .= " LEFT JOIN in_accounting_bookkeeping as iab ON iab.fk_docdet = ad.rowid";
- }*/
- $sql .= " WHERE a.entity IN (" . getEntity('asset', 0) . ')'; // We don't share object for accountancy, we use source object sharing
- // Compatibility with Mysql 5.7
- if ($in_bookkeeping == 'already') {
- $sql .= " AND EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
- } elseif ($in_bookkeeping == 'notyet') {
- $sql .= " AND NOT EXISTS (SELECT iab.fk_docdet FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping AS iab WHERE iab.fk_docdet = ad.rowid AND doc_type = 'asset')";
- }
- $sql .= " AND ad.ref != ''"; // not reversal lines
- if ($date_start && $date_end) {
- $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($date_start) . "' AND ad.depreciation_date <= '" . $this->db->idate($date_end) . "'";
- }
- // Define begin binding date
- if (!empty($conf->global->ACCOUNTING_DATE_START_BINDING)) {
- $sql .= " AND ad.depreciation_date >= '" . $this->db->idate($conf->global->ACCOUNTING_DATE_START_BINDING) . "'";
- }
- // Already in bookkeeping or not
- // FIXME sql error with Mysql 5.7
- /*if ($in_bookkeeping == 'already' || $in_bookkeeping == 'notyet') {
- $sql .= " AND iab.fk_docdet IS" . ($in_bookkeeping == 'already' ? " NOT" : "") . " NULL";
- }*/
- $sql .= " ORDER BY ad.depreciation_date";
- dol_syslog(__METHOD__, LOG_DEBUG);
- $resql = $this->db->query($sql);
- if (!$resql) {
- $this->errors[] = $this->db->lasterror();
- return -1;
- }
- $pre_data = array(
- 'elements' => array(),
- );
- while ($obj = $this->db->fetch_object($resql)) {
- if (!isset($pre_data['elements'][$obj->rowid])) {
- $pre_data['elements'][$obj->rowid] = array(
- 'ref' => $obj->asset_ref,
- 'label' => $obj->asset_label,
- 'acquisition_value_ht' => $obj->asset_acquisition_value_ht,
- 'depreciation' => array(),
- );
- // Disposal infos
- if (isset($obj->asset_disposal_date)) {
- $pre_data['elements'][$obj->rowid]['disposal'] = array(
- 'date' => $this->db->jdate($obj->asset_disposal_date),
- 'amount' => $obj->asset_disposal_amount_ht,
- 'subject_to_vat' => !empty($obj->asset_disposal_subject_to_vat),
- );
- }
- }
- $compta_debit = empty($obj->accountancy_code_debit) ? 'NotDefined' : $obj->accountancy_code_debit;
- $compta_credit = empty($obj->accountancy_code_credit) ? 'NotDefined' : $obj->accountancy_code_credit;
- $pre_data['elements'][$obj->rowid]['depreciation'][$obj->depreciation_id] = array(
- 'date' => $this->db->jdate($obj->depreciation_date),
- 'ref' => $obj->depreciation_ref,
- 'lines' => array(
- $compta_debit => -$obj->depreciation_ht,
- $compta_credit => $obj->depreciation_ht,
- ),
- );
- }
- $disposal_ref = $langs->transnoentitiesnoconv('AssetDisposal');
- $journal = $this->code;
- $journal_label = $this->label;
- $journal_label_formatted = $langs->transnoentities($journal_label);
- $now = dol_now();
- $element_static = new Asset($this->db);
- $journal_data = array();
- foreach ($pre_data['elements'] as $pre_data_id => $pre_data_info) {
- $element_static->id = $pre_data_id;
- $element_static->ref = (string) $pre_data_info["ref"];
- $element_static->label = (string) $pre_data_info["label"];
- $element_static->acquisition_value_ht = $pre_data_info["acquisition_value_ht"];
- $element_link = $element_static->getNomUrl(1, 'with_label');
- $element_name_formatted_0 = dol_trunc($element_static->label, 16);
- $element_name_formatted_1 = utf8_decode(dol_trunc($element_static->label, 32));
- $element_name_formatted_2 = utf8_decode(dol_trunc($element_static->label, 16));
- $label_operation = $element_static->getNomUrl(0, 'label', 16);
- $element = array(
- 'ref' => dol_trunc($element_static->ref, 16, 'right', 'UTF-8', 1),
- 'error' => $pre_data_info['error'],
- 'blocks' => array(),
- );
- // Depreciation lines
- //--------------------
- foreach ($pre_data_info['depreciation'] as $depreciation_id => $line) {
- $depreciation_ref = $line["ref"];
- $depreciation_date = $line["date"];
- $depreciation_date_formatted = dol_print_date($depreciation_date, 'day');
- // lines
- $blocks = array();
- foreach ($line['lines'] as $account => $mt) {
- $account_infos = $this->getAccountingAccountInfos($account);
- if ($type == 'view') {
- $account_to_show = length_accounta($account);
- if (($account_to_show == "") || $account_to_show == 'NotDefined') {
- $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
- }
- $blocks[] = array(
- 'date' => $depreciation_date_formatted,
- 'piece' => $element_link,
- 'account_accounting' => $account_to_show,
- 'subledger_account' => '',
- 'label_operation' => $label_operation . ' - ' . $depreciation_ref,
- 'debit' => $mt < 0 ? price(-$mt) : '',
- 'credit' => $mt >= 0 ? price($mt) : '',
- );
- } elseif ($type == 'bookkeeping') {
- if ($account_infos['found']) {
- $blocks[] = array(
- 'doc_date' => $depreciation_date,
- 'date_lim_reglement' => '',
- 'doc_ref' => $element_static->ref,
- 'date_creation' => $now,
- 'doc_type' => 'asset',
- 'fk_doc' => $element_static->id,
- 'fk_docdet' => $depreciation_id, // Useless, can be several lines that are source of this record to add
- 'thirdparty_code' => '',
- 'subledger_account' => '',
- 'subledger_label' => '',
- 'numero_compte' => $account,
- 'label_compte' => $account_infos['label'],
- 'label_operation' => $element_name_formatted_0 . ' - ' . $depreciation_ref,
- 'montant' => $mt,
- 'sens' => $mt < 0 ? 'D' : 'C',
- 'debit' => $mt < 0 ? -$mt : 0,
- 'credit' => $mt >= 0 ? $mt : 0,
- 'code_journal' => $journal,
- 'journal_label' => $journal_label_formatted,
- 'piece_num' => '',
- 'import_key' => '',
- 'fk_user_author' => $user->id,
- 'entity' => $conf->entity,
- );
- }
- } else { // $type == 'csv'
- $blocks[] = array(
- $depreciation_date, // Date
- $element_static->ref, // Piece
- $account_infos['code_formatted_1'], // AccountAccounting
- $element_name_formatted_0 . ' - ' . $depreciation_ref, // LabelOperation
- $mt < 0 ? price(-$mt) : '', // Debit
- $mt >= 0 ? price($mt) : '', // Credit
- );
- }
- }
- $element['blocks'][] = $blocks;
- }
- // Disposal line
- //--------------------
- if (!empty($pre_data_info['disposal'])) {
- $disposal_date = $pre_data_info['disposal']['date'];
- if ((!($date_start && $date_end) || ($date_start <= $disposal_date && $disposal_date <= $date_end)) &&
- (empty($conf->global->ACCOUNTING_DATE_START_BINDING) || $conf->global->ACCOUNTING_DATE_START_BINDING <= $disposal_date)
- ) {
- $disposal_amount = $pre_data_info['disposal']['amount'];
- $disposal_subject_to_vat = $pre_data_info['disposal']['subject_to_vat'];
- $disposal_date_formatted = dol_print_date($disposal_date, 'day');
- $disposal_vat = $conf->global->ASSET_DISPOSAL_VAT > 0 ? $conf->global->ASSET_DISPOSAL_VAT : 20;
- // Get accountancy codes
- //---------------------------
- require_once DOL_DOCUMENT_ROOT . '/asset/class/assetaccountancycodes.class.php';
- $accountancy_codes = new AssetAccountancyCodes($this->db);
- $result = $accountancy_codes->fetchAccountancyCodes($element_static->id);
- if ($result < 0) {
- $element['error'] = $accountancy_codes->errorsToString();
- } else {
- // Get last depreciation cumulative amount
- $element_static->fetchDepreciationLines();
- foreach ($element_static->depreciation_lines as $mode_key => $depreciation_lines) {
- $accountancy_codes_list = $accountancy_codes->accountancy_codes[$mode_key];
- if (!isset($accountancy_codes_list['value_asset_sold'])) {
- continue;
- }
- $accountancy_code_value_asset_sold = empty($accountancy_codes_list['value_asset_sold']) ? 'NotDefined' : $accountancy_codes_list['value_asset_sold'];
- $accountancy_code_depreciation_asset = empty($accountancy_codes_list['depreciation_asset']) ? 'NotDefined' : $accountancy_codes_list['depreciation_asset'];
- $accountancy_code_asset = empty($accountancy_codes_list['asset']) ? 'NotDefined' : $accountancy_codes_list['asset'];
- $accountancy_code_receivable_on_assignment = empty($accountancy_codes_list['receivable_on_assignment']) ? 'NotDefined' : $accountancy_codes_list['receivable_on_assignment'];
- $accountancy_code_vat_collected = empty($accountancy_codes_list['vat_collected']) ? 'NotDefined' : $accountancy_codes_list['vat_collected'];
- $accountancy_code_proceeds_from_sales = empty($accountancy_codes_list['proceeds_from_sales']) ? 'NotDefined' : $accountancy_codes_list['proceeds_from_sales'];
- $last_cumulative_amount_ht = 0;
- $depreciated_ids = array_keys($pre_data_info['depreciation']);
- foreach ($depreciation_lines as $line) {
- $last_cumulative_amount_ht = $line['cumulative_depreciation_ht'];
- if (!in_array($line['id'], $depreciated_ids) && empty($line['bookkeeping']) && !empty($line['ref'])) {
- break;
- }
- }
- $lines = array();
- $lines[0][$accountancy_code_value_asset_sold] = -($element_static->acquisition_value_ht - $last_cumulative_amount_ht);
- $lines[0][$accountancy_code_depreciation_asset] = -$last_cumulative_amount_ht;
- $lines[0][$accountancy_code_asset] = $element_static->acquisition_value_ht;
- $disposal_amount_vat = $disposal_subject_to_vat ? (double) price2num($disposal_amount * $disposal_vat / 100, 'MT') : 0;
- $lines[1][$accountancy_code_receivable_on_assignment] = -($disposal_amount + $disposal_amount_vat);
- if ($disposal_subject_to_vat) $lines[1][$accountancy_code_vat_collected] = $disposal_amount_vat;
- $lines[1][$accountancy_code_proceeds_from_sales] = $disposal_amount;
- foreach ($lines as $lines_block) {
- $blocks = array();
- foreach ($lines_block as $account => $mt) {
- $account_infos = $this->getAccountingAccountInfos($account);
- if ($type == 'view') {
- $account_to_show = length_accounta($account);
- if (($account_to_show == "") || $account_to_show == 'NotDefined') {
- $account_to_show = '<span class="error">' . $langs->trans("AssetInAccountNotDefined") . '</span>';
- }
- $blocks[] = array(
- 'date' => $disposal_date_formatted,
- 'piece' => $element_link,
- 'account_accounting' => $account_to_show,
- 'subledger_account' => '',
- 'label_operation' => $label_operation . ' - ' . $disposal_ref,
- 'debit' => $mt < 0 ? price(-$mt) : '',
- 'credit' => $mt >= 0 ? price($mt) : '',
- );
- } elseif ($type == 'bookkeeping') {
- if ($account_infos['found']) {
- $blocks[] = array(
- 'doc_date' => $disposal_date,
- 'date_lim_reglement' => '',
- 'doc_ref' => $element_static->ref,
- 'date_creation' => $now,
- 'doc_type' => 'asset',
- 'fk_doc' => $element_static->id,
- 'fk_docdet' => 0, // Useless, can be several lines that are source of this record to add
- 'thirdparty_code' => '',
- 'subledger_account' => '',
- 'subledger_label' => '',
- 'numero_compte' => $account,
- 'label_compte' => $account_infos['label'],
- 'label_operation' => $element_name_formatted_0 . ' - ' . $disposal_ref,
- 'montant' => $mt,
- 'sens' => $mt < 0 ? 'D' : 'C',
- 'debit' => $mt < 0 ? -$mt : 0,
- 'credit' => $mt >= 0 ? $mt : 0,
- 'code_journal' => $journal,
- 'journal_label' => $journal_label_formatted,
- 'piece_num' => '',
- 'import_key' => '',
- 'fk_user_author' => $user->id,
- 'entity' => $conf->entity,
- );
- }
- } else { // $type == 'csv'
- $blocks[] = array(
- $disposal_date, // Date
- $element_static->ref, // Piece
- $account_infos['code_formatted_1'], // AccountAccounting
- $element_name_formatted_0 . ' - ' . $disposal_ref, // LabelOperation
- $mt < 0 ? price(-$mt) : '', // Debit
- $mt >= 0 ? price($mt) : '', // Credit
- );
- }
- }
- $element['blocks'][] = $blocks;
- }
- }
- }
- }
- }
- $journal_data[$pre_data_id] = $element;
- }
- unset($pre_data);
- return $journal_data;
- }
- /**
- * Write bookkeeping
- *
- * @param User $user User who write in the bookkeeping
- * @param array $journal_data Journal data to write in the bookkeeping
- * $journal_data = array(
- * id_element => array(
- * 'ref' => 'ref',
- * 'error' => '',
- * 'blocks' => array(
- * pos_block => array(
- * num_line => array(
- * 'doc_date' => '',
- * 'date_lim_reglement' => '',
- * 'doc_ref' => '',
- * 'date_creation' => '',
- * 'doc_type' => '',
- * 'fk_doc' => '',
- * 'fk_docdet' => '',
- * 'thirdparty_code' => '',
- * 'subledger_account' => '',
- * 'subledger_label' => '',
- * 'numero_compte' => '',
- * 'label_compte' => '',
- * 'label_operation' => '',
- * 'montant' => '',
- * 'sens' => '',
- * 'debit' => '',
- * 'credit' => '',
- * 'code_journal' => '',
- * 'journal_label' => '',
- * 'piece_num' => '',
- * 'import_key' => '',
- * 'fk_user_author' => '',
- * 'entity' => '',
- * ),
- * ),
- * ),
- * ),
- * );
- * @param int $max_nb_errors Nb error authorized before stop the process
- * @return int <0 if KO, >0 if OK
- */
- public function writeIntoBookkeeping(User $user, &$journal_data = array(), $max_nb_errors = 10)
- {
- global $conf, $langs, $hookmanager;
- require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
- // Hook
- if (!is_object($hookmanager)) {
- include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
- $hookmanager = new HookManager($this->db);
- }
- $error = 0;
- $hookmanager->initHooks(array('accountingjournaldao'));
- $parameters = array('journal_data' => &$journal_data);
- $reshook = $hookmanager->executeHooks('writeBookkeeping', $parameters, $this); // Note that $action and $object may have been
- if ($reshook < 0) {
- $this->error = $hookmanager->error;
- $this->errors = $hookmanager->errors;
- return -1;
- } elseif (empty($reshook)) {
- // Clean parameters
- $journal_data = is_array($journal_data) ? $journal_data : array();
- foreach ($journal_data as $element_id => $element) {
- $error_for_line = 0;
- $total_credit = 0;
- $total_debit = 0;
- $this->db->begin();
- if ($element['error'] == 'somelinesarenotbound') {
- $error++;
- $error_for_line++;
- $this->errors[] = $langs->trans('ErrorInvoiceContainsLinesNotYetBounded', $element['ref']);
- }
- if (!$error_for_line) {
- foreach ($element['blocks'] as $lines) {
- foreach ($lines as $line) {
- $bookkeeping = new BookKeeping($this->db);
- $bookkeeping->doc_date = $line['doc_date'];
- $bookkeeping->date_lim_reglement = $line['date_lim_reglement'];
- $bookkeeping->doc_ref = $line['doc_ref'];
- $bookkeeping->date_creation = $line['date_creation']; // not used
- $bookkeeping->doc_type = $line['doc_type'];
- $bookkeeping->fk_doc = $line['fk_doc'];
- $bookkeeping->fk_docdet = $line['fk_docdet'];
- $bookkeeping->thirdparty_code = $line['thirdparty_code'];
- $bookkeeping->subledger_account = $line['subledger_account'];
- $bookkeeping->subledger_label = $line['subledger_label'];
- $bookkeeping->numero_compte = $line['numero_compte'];
- $bookkeeping->label_compte = $line['label_compte'];
- $bookkeeping->label_operation = $line['label_operation'];
- $bookkeeping->montant = $line['montant'];
- $bookkeeping->sens = $line['sens'];
- $bookkeeping->debit = $line['debit'];
- $bookkeeping->credit = $line['credit'];
- $bookkeeping->code_journal = $line['code_journal'];
- $bookkeeping->journal_label = $line['journal_label'];
- $bookkeeping->piece_num = $line['piece_num'];
- $bookkeeping->import_key = $line['import_key'];
- $bookkeeping->fk_user_author = $user->id;
- $bookkeeping->entity = $conf->entity;
- $total_debit += $bookkeeping->debit;
- $total_credit += $bookkeeping->credit;
- $result = $bookkeeping->create($user);
- if ($result < 0) {
- if ($bookkeeping->error == 'BookkeepingRecordAlreadyExists') { // Already exists
- $error++;
- $error_for_line++;
- $journal_data[$element_id]['error'] = 'alreadyjournalized';
- } else {
- $error++;
- $error_for_line++;
- $journal_data[$element_id]['error'] = 'other';
- $this->errors[] = $bookkeeping->errorsToString();
- }
- }
- //
- // if (!$error_for_line && isModEnabled('asset') && $this->nature == 1 && $bookkeeping->fk_doc > 0) {
- // // Set last cumulative depreciation
- // require_once DOL_DOCUMENT_ROOT . '/asset/class/asset.class.php';
- // $asset = new Asset($this->db);
- // $result = $asset->setLastCumulativeDepreciation($bookkeeping->fk_doc);
- // if ($result < 0) {
- // $error++;
- // $error_for_line++;
- // $journal_data[$element_id]['error'] = 'other';
- // $this->errors[] = $asset->errorsToString();
- // }
- // }
- }
- if ($error_for_line) {
- break;
- }
- }
- }
- // Protection against a bug on lines before
- if (!$error_for_line && (price2num($total_debit, 'MT') != price2num($total_credit, 'MT'))) {
- $error++;
- $error_for_line++;
- $journal_data[$element_id]['error'] = 'amountsnotbalanced';
- $this->errors[] = 'Try to insert a non balanced transaction in book for ' . $element['blocks'] . '. Canceled. Surely a bug.';
- }
- if (!$error_for_line) {
- $this->db->commit();
- } else {
- $this->db->rollback();
- if ($error >= $max_nb_errors) {
- $this->errors[] = $langs->trans("ErrorTooManyErrorsProcessStopped");
- break; // Break in the foreach
- }
- }
- }
- }
- return $error ? -$error : 1;
- }
- /**
- * Export journal CSV
- * ISO and not UTF8 !
- *
- * @param array $journal_data Journal data to write in the bookkeeping
- * $journal_data = array(
- * id_element => array(
- * 'continue' => false,
- * 'blocks' => array(
- * pos_block => array(
- * num_line => array(
- * data to write in the CSV line
- * ),
- * ),
- * ),
- * ),
- * );
- * @param int $search_date_end Search date end
- * @param string $sep CSV separator
- * @return int|string <0 if KO, >0 if OK
- */
- public function exportCsv(&$journal_data = array(), $search_date_end = 0, $sep = '')
- {
- global $conf, $langs, $hookmanager;
- if (empty($sep)) $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
- $out = '';
- // Hook
- if (!is_object($hookmanager)) {
- include_once DOL_DOCUMENT_ROOT . '/core/class/hookmanager.class.php';
- $hookmanager = new HookManager($this->db);
- }
- $hookmanager->initHooks(array('accountingjournaldao'));
- $parameters = array('journal_data' => &$journal_data, 'search_date_end' => &$search_date_end, 'sep' => &$sep, 'out' => &$out);
- $reshook = $hookmanager->executeHooks('exportCsv', $parameters, $this); // Note that $action and $object may have been
- if ($reshook < 0) {
- $this->error = $hookmanager->error;
- $this->errors = $hookmanager->errors;
- return -1;
- } elseif (empty($reshook)) {
- // Clean parameters
- $journal_data = is_array($journal_data) ? $journal_data : array();
- // CSV header line
- $header = array();
- if ($this->nature == 4) {
- $header = array(
- $langs->transnoentitiesnoconv("BankId"),
- $langs->transnoentitiesnoconv("Date"),
- $langs->transnoentitiesnoconv("PaymentMode"),
- $langs->transnoentitiesnoconv("AccountAccounting"),
- $langs->transnoentitiesnoconv("LedgerAccount"),
- $langs->transnoentitiesnoconv("SubledgerAccount"),
- $langs->transnoentitiesnoconv("Label"),
- $langs->transnoentitiesnoconv("AccountingDebit"),
- $langs->transnoentitiesnoconv("AccountingCredit"),
- $langs->transnoentitiesnoconv("Journal"),
- $langs->transnoentitiesnoconv("Note"),
- );
- } elseif ($this->nature == 5) {
- $header = array(
- $langs->transnoentitiesnoconv("Date"),
- $langs->transnoentitiesnoconv("Piece"),
- $langs->transnoentitiesnoconv("AccountAccounting"),
- $langs->transnoentitiesnoconv("LabelOperation"),
- $langs->transnoentitiesnoconv("AccountingDebit"),
- $langs->transnoentitiesnoconv("AccountingCredit"),
- );
- } elseif ($this->nature == 1) {
- $header = array(
- $langs->transnoentitiesnoconv("Date"),
- $langs->transnoentitiesnoconv("Piece"),
- $langs->transnoentitiesnoconv("AccountAccounting"),
- $langs->transnoentitiesnoconv("LabelOperation"),
- $langs->transnoentitiesnoconv("AccountingDebit"),
- $langs->transnoentitiesnoconv("AccountingCredit"),
- );
- }
- if (!empty($header)) $out .= '"' . implode('"' . $sep . '"', $header) . '"' . "\n";
- foreach ($journal_data as $element_id => $element) {
- foreach ($element['blocks'] as $lines) {
- foreach ($lines as $line) {
- $out .= '"' . implode('"' . $sep . '"', $line) . '"' . "\n";
- }
- }
- }
- }
- return $out;
- }
- /**
- * Get accounting account infos
- *
- * @param string $account Accounting account number
- * @return array Accounting account infos
- */
- public function getAccountingAccountInfos($account)
- {
- if (!isset(self::$accounting_account_cached[$account])) {
- require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
- require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
- $accountingaccount = new AccountingAccount($this->db);
- $result = $accountingaccount->fetch(null, $account, true);
- if ($result > 0) {
- self::$accounting_account_cached[$account] = array(
- 'found' => true,
- 'label' => $accountingaccount->label,
- 'code_formatted_1' => length_accounta(html_entity_decode($account)),
- 'label_formatted_1' => utf8_decode(dol_trunc($accountingaccount->label, 32)),
- 'label_formatted_2' => dol_trunc($accountingaccount->label, 32),
- );
- } else {
- self::$accounting_account_cached[$account] = array(
- 'found' => false,
- 'label' => '',
- 'code_formatted_1' => length_accounta(html_entity_decode($account)),
- 'label_formatted_1' => '',
- 'label_formatted_2' => '',
- );
- }
- }
- return self::$accounting_account_cached[$account];
- }
- }
|