api_accountancy.class.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <?php
  2. /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  3. * Copyright (C) 2019 Cedric Ancelin <icedo.anc@gmail.com>
  4. * Copyright (C) 2023 Lionel Vessiller <lvessiller@open-dsi.fr>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. use Luracast\Restler\RestException;
  20. /**
  21. * API class for accountancy
  22. *
  23. * @access protected
  24. * @class DolibarrApiAccess {@requires user,external}
  25. *
  26. */
  27. class Accountancy extends DolibarrApi
  28. {
  29. /**
  30. *
  31. * @var array $FIELDS Mandatory fields, checked when create and update object
  32. */
  33. public static $FIELDS = array();
  34. /**
  35. * @var BookKeeping $bookkeeping {@type BookKeeping}
  36. */
  37. public $bookkeeping;
  38. /**
  39. * @var AccountancyExport $accountancy_export {@type AccountancyExport}
  40. */
  41. public $accountancyexport;
  42. /**
  43. * Constructor
  44. */
  45. public function __construct()
  46. {
  47. global $db, $langs;
  48. $this->db = $db;
  49. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/bookkeeping.class.php';
  50. require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountancyexport.class.php';
  51. $langs->load('accountancy');
  52. $this->bookkeeping = new BookKeeping($this->db);
  53. $this->accountancyexport = new AccountancyExport($this->db);
  54. }
  55. /**
  56. * Accountancy export data
  57. *
  58. * @param string $period Period : 'lastmonth', 'currentmonth', 'last3months', 'last6months', 'currentyear', 'lastyear', 'fiscalyear', 'lastfiscalyear', 'actualandlastfiscalyear' or 'custom' (see above)
  59. * @param string $date_min [=''] Start date of period if 'custom' is set in period parameter
  60. * Date format is 'YYYY-MM-DD'
  61. * @param string $date_max [=''] End date of period if 'custom' is set in period parameter
  62. * Date format is 'YYYY-MM-DD'
  63. * @param string $format [=''] by default uses '1' for 'Configurable (CSV)' for format number
  64. * or '1000' for FEC
  65. * or '1010' for FEC2
  66. * (see AccountancyExport class)
  67. * @param int $lettering [=0] by default don't export or 1 to export lettering data (columns 'letterring_code' and 'date_lettering' returns empty or not)
  68. * @param int $alreadyexport [=0] by default export data only if it's not yet exported or 1 already exported (always export data even if 'date_export" is set)
  69. * @param int $notnotifiedasexport [=0] by default notified as exported or 1 not notified as exported (when the export is done, notified or not the column 'date_export')
  70. *
  71. * @return string
  72. *
  73. * @url GET exportdata
  74. *
  75. * @throws RestException 401 Insufficient rights
  76. * @throws RestException 404 Accountancy export period not found
  77. * @throws RestException 404 Accountancy export start or end date not defined
  78. * @throws RestException 404 Accountancy export format not found
  79. * @throws RestException 500 Error on accountancy export
  80. */
  81. public function exportData($period, $date_min = '', $date_max = '', $format = '', $lettering = 0, $alreadyexport = 0, $notnotifiedasexport = 0)
  82. {
  83. global $conf, $langs;
  84. // check rights
  85. if (!DolibarrApiAccess::$user->rights->accounting->mouvements->export) {
  86. throw new RestException(401, 'No permission to export accounting');
  87. }
  88. // check parameters
  89. $period_available_list = array('lastmonth', 'currentmonth', 'last3months', 'last6months', 'currentyear', 'lastyear', 'fiscalyear', 'lastfiscalyear', 'actualandlastfiscalyear', 'custom');
  90. if (!in_array($period, $period_available_list)) {
  91. throw new RestException(404, 'Accountancy export period not found');
  92. }
  93. if ($period == 'custom') {
  94. if ($date_min == '' && $date_max == '') {
  95. throw new RestException(404, 'Accountancy export start and end date for custom period not defined');
  96. }
  97. }
  98. if ($format == '') {
  99. $format = AccountancyExport::$EXPORT_TYPE_CONFIGURABLE; // uses default
  100. }
  101. // get objects
  102. $bookkeeping = $this->bookkeeping;
  103. $accountancyexport = $this->accountancyexport;
  104. // find export format code from format number
  105. $format_number_available_list = $accountancyexport->getType();
  106. if (is_numeric($format)) {
  107. $format_number = (int) $format;
  108. } else {
  109. $format_number = 0;
  110. $format_label_available_list = array_flip($format_number_available_list);
  111. if (isset($format_label_available_list[$format])) {
  112. $format_number = $format_label_available_list[$format];
  113. }
  114. }
  115. // get all format available and check if exists
  116. if (!array_key_exists($format_number, $format_number_available_list)) {
  117. throw new RestException(404, 'Accountancy export format not found');
  118. }
  119. $sortorder = 'ASC'; // by default
  120. $sortfield = 't.piece_num, t.rowid'; // by default
  121. // set filter for each period available
  122. $filter = array();
  123. $doc_date_start = null;
  124. $doc_date_end= null;
  125. $now = dol_now();
  126. $now_arr = dol_getdate($now);
  127. $now_month = $now_arr['mon'];
  128. $now_year = $now_arr['year'];
  129. if ($period == 'custom') {
  130. if ($date_min != '') {
  131. $time_min = strtotime($date_min);
  132. if ($time_min !== false) {
  133. $doc_date_start = $time_min;
  134. }
  135. }
  136. if ($date_max != '') {
  137. $time_max = strtotime($date_max);
  138. if ($time_max !== false) {
  139. $doc_date_end = $time_max;
  140. }
  141. }
  142. } elseif ($period == 'lastmonth') {
  143. $prev_date_arr = dol_get_prev_month($now_month, $now_year); // get previous month and year if month is january
  144. $doc_date_start = dol_mktime(0, 0, 0, $prev_date_arr['month'], 1, $prev_date_arr['year']); // first day of previous month
  145. $doc_date_end = dol_get_last_day($prev_date_arr['year'], $prev_date_arr['month']); // last day of previous month
  146. } elseif ($period == 'currentmonth') {
  147. $doc_date_start = dol_mktime(0, 0, 0, $now_month, 1, $now_year); // first day of current month
  148. $doc_date_end = dol_get_last_day($now_year, $now_month); // last day of current month
  149. } elseif ($period == 'last3months' || $period == 'last6months') {
  150. if ($period == 'last3months') {
  151. // last 3 months
  152. $nb_prev_month = 3;
  153. } else {
  154. // last 6 months
  155. $nb_prev_month = 6;
  156. }
  157. $prev_month_date_list = array();
  158. $prev_month_date_list[] = dol_get_prev_month($now_month, $now_year); // get previous month for index = 0
  159. for ($i = 1; $i < $nb_prev_month; $i++) {
  160. $prev_month_date_list[] = dol_get_prev_month($prev_month_date_list[$i-1]['month'], $prev_month_date_list[$i-1]['year']); // get i+1 previous month for index=i
  161. }
  162. $doc_date_start = dol_mktime(0, 0, 0, $prev_month_date_list[$nb_prev_month-1]['month'], 1, $prev_month_date_list[$nb_prev_month-1]['year']); // first day of n previous month for index=n-1
  163. $doc_date_end = dol_get_last_day($prev_month_date_list[0]['year'], $prev_month_date_list[0]['month']); // last day of previous month for index = 0
  164. } elseif ($period == 'currentyear' || $period == 'lastyear') {
  165. $period_year = $now_year;
  166. if ($period == 'lastyear') {
  167. $period_year--;
  168. }
  169. $doc_date_start = dol_mktime(0, 0, 0, 1, 1, $period_year); // first day of year
  170. $doc_date_end = dol_mktime(23, 59, 59, 12, 31, $period_year); // last day of year
  171. } elseif ($period == 'fiscalyear' || $period == 'lastfiscalyear' || $period == 'actualandlastfiscalyear') {
  172. // find actual fiscal year
  173. $cur_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf);
  174. $cur_fiscal_date_start = $cur_fiscal_period['date_start'];
  175. $cur_fiscal_date_end = $cur_fiscal_period['date_end'];
  176. if ($period == 'fiscalyear') {
  177. $doc_date_start = $cur_fiscal_date_start;
  178. $doc_date_end = $cur_fiscal_date_end;
  179. } else {
  180. // get one day before current fiscal date start (to find previous fiscal period)
  181. $prev_fiscal_date_search = dol_time_plus_duree($cur_fiscal_date_start, -1, 'd');
  182. // find previous fiscal year from current fiscal year
  183. $prev_fiscal_period = getCurrentPeriodOfFiscalYear($this->db, $conf, $prev_fiscal_date_search);
  184. $prev_fiscal_date_start = $prev_fiscal_period['date_start'];
  185. $prev_fiscal_date_end = $prev_fiscal_period['date_end'];
  186. if ($period == 'lastfiscalyear') {
  187. $doc_date_start = $prev_fiscal_date_start;
  188. $doc_date_end = $prev_fiscal_date_end;
  189. } else {
  190. // period == 'actualandlastfiscalyear'
  191. $doc_date_start = $prev_fiscal_date_start;
  192. $doc_date_end = $cur_fiscal_date_end;
  193. }
  194. }
  195. }
  196. if (is_numeric($doc_date_start)) {
  197. $filter['t.doc_date>='] = $doc_date_start;
  198. }
  199. if (is_numeric($doc_date_end)) {
  200. $filter['t.doc_date<='] = $doc_date_end;
  201. }
  202. $result = $bookkeeping->fetchAll($sortorder, $sortfield, 0, 0, $filter, 'AND', $alreadyexport);
  203. if ($result < 0) {
  204. throw new RestException(500, 'Error bookkeeping fetch all : '.$bookkeeping->errorsToString());
  205. } else {
  206. // export files then exit
  207. if (empty($lettering)) {
  208. if (is_array($bookkeeping->lines)) {
  209. foreach ($bookkeeping->lines as $k => $movement) {
  210. unset($bookkeeping->lines[$k]->lettering_code);
  211. unset($bookkeeping->lines[$k]->date_lettering);
  212. }
  213. }
  214. }
  215. $error = 0;
  216. $this->db->begin();
  217. if (empty($notnotifiedasexport)) {
  218. if (is_array($bookkeeping->lines)) {
  219. foreach ($bookkeeping->lines as $movement) {
  220. $now = dol_now();
  221. $sql = " UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping";
  222. $sql .= " SET date_export = '" . $this->db->idate($now) . "'";
  223. $sql .= " WHERE rowid = " . ((int) $movement->id);
  224. $result = $this->db->query($sql);
  225. if (!$result) {
  226. $accountancyexport->errors[] = $langs->trans('NotAllExportedMovementsCouldBeRecordedAsExportedOrValidated');
  227. $error++;
  228. break;
  229. }
  230. }
  231. }
  232. }
  233. // export and only write file without downloading
  234. if (!$error) {
  235. $result = $accountancyexport->export($bookkeeping->lines, $format_number, 0, 1, 2);
  236. if ($result < 0) {
  237. $error++;
  238. }
  239. }
  240. if ($error) {
  241. $this->db->rollback();
  242. throw new RestException(500, 'Error accountancy export : '.implode(',', $accountancyexport->errors));
  243. } else {
  244. $this->db->commit();
  245. exit();
  246. }
  247. }
  248. }
  249. }