|
@@ -1,5 +1,5 @@
|
|
|
<?php
|
|
|
-/* Copyright (C) 2017 Alexandre Spangaro <aspangaro@open-dsi.fr>
|
|
|
+/* 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
|
|
@@ -81,6 +81,24 @@ class AccountingJournal extends CommonObject
|
|
|
*/
|
|
|
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
|
|
|
*
|
|
@@ -221,7 +239,7 @@ class AccountingJournal extends CommonObject
|
|
|
*/
|
|
|
public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0)
|
|
|
{
|
|
|
- global $langs, $conf, $user;
|
|
|
+ global $langs, $conf, $user, $hookmanager;
|
|
|
|
|
|
if (!empty($conf->dol_no_mouse_hover)) {
|
|
|
$notooltip = 1; // Force disable tooltips
|
|
@@ -276,6 +294,15 @@ class AccountingJournal extends CommonObject
|
|
|
}
|
|
|
$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;
|
|
|
}
|
|
|
|
|
@@ -336,4 +363,680 @@ class AccountingJournal extends CommonObject
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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 (empty($conf->asset->enabled)) {
|
|
|
+ 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 = "";
|
|
|
+ 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";
|
|
|
+ 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
|
|
|
+ $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
|
|
|
+ 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 && !empty($conf->asset->enabled) && $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("Debit"),
|
|
|
+ $langs->transnoentitiesnoconv("Credit"),
|
|
|
+ $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("Debit"),
|
|
|
+ $langs->transnoentitiesnoconv("Credit"),
|
|
|
+ );
|
|
|
+ } elseif ($this->nature == 1) {
|
|
|
+ $header = array(
|
|
|
+ $langs->transnoentitiesnoconv("Date"),
|
|
|
+ $langs->transnoentitiesnoconv("Piece"),
|
|
|
+ $langs->transnoentitiesnoconv("AccountAccounting"),
|
|
|
+ $langs->transnoentitiesnoconv("LabelOperation"),
|
|
|
+ $langs->transnoentitiesnoconv("Debit"),
|
|
|
+ $langs->transnoentitiesnoconv("Credit"),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ 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];
|
|
|
+ }
|
|
|
}
|