summaryrefslogtreecommitdiff
path: root/LedgerSMB/GL.pm
blob: 7ee7ba8965671ba8e8a0c41f04479708bc21c2a3 (plain)
  1. #=====================================================================
  2. # LedgerSMB
  3. # Small Medium Business Accounting software
  4. # http://www.ledgersmb.org/
  5. #
  6. # Copyright (C) 2006
  7. # This work contains copyrighted information from a number of sources all used
  8. # with permission.
  9. #
  10. # This file contains source code included with or based on SQL-Ledger which
  11. # is Copyright Dieter Simader and DWS Systems Inc. 2000-2005 and licensed
  12. # under the GNU General Public License version 2 or, at your option, any later
  13. # version. For a full list including contact information of contributors,
  14. # maintainers, and copyright holders, see the CONTRIBUTORS file.
  15. #
  16. # Original Copyright Notice from SQL-Ledger 2.6.17 (before the fork):
  17. # Copyright (C) 2000
  18. #
  19. # Author: DWS Systems Inc.
  20. # Web: http://www.sql-ledger.org
  21. #
  22. # Contributors:
  23. #
  24. #======================================================================
  25. #
  26. # This file has undergone whitespace cleanup.
  27. #
  28. #======================================================================
  29. #
  30. # General ledger backend code
  31. #
  32. #======================================================================
  33. package GL;
  34. sub delete_transaction {
  35. my ( $self, $myconfig, $form ) = @_;
  36. # connect to database
  37. my $dbh = $form->{dbh};
  38. my %audittrail = (
  39. tablename => 'gl',
  40. reference => $form->{reference},
  41. formname => 'transaction',
  42. action => 'deleted',
  43. id => $form->{id}
  44. );
  45. $form->audittrail( $dbh, "", \%audittrail );
  46. my $id = $dbh->quote( $form->{id} );
  47. my $query = qq|DELETE FROM gl WHERE id = $id|;
  48. $dbh->do($query) || $form->dberror($query);
  49. $query = qq|DELETE FROM acc_trans WHERE trans_id = $id|;
  50. $dbh->do($query) || $form->dberror($query);
  51. # commit and redirect
  52. my $rc = $dbh->commit;
  53. $rc;
  54. }
  55. sub post_transaction {
  56. my ( $self, $myconfig, $form ) = @_;
  57. $form->{reference} = $form->update_defaults( $myconfig, 'glnumber', $dbh )
  58. unless $form->{reference};
  59. my $null;
  60. my $project_id;
  61. my $department_id;
  62. my $i;
  63. # connect to database, turn off AutoCommit
  64. my $dbh = $form->{dbh};
  65. my $query;
  66. my $sth;
  67. my $id = $dbh->quote( $form->{id} );
  68. if ($form->{separate_duties}){
  69. $form->{approved} = '0';
  70. }
  71. if ( $form->{id} ) {
  72. $query = qq|SELECT id FROM gl WHERE id = $id|;
  73. ( $form->{id} ) = $dbh->selectrow_array($query);
  74. if ( $form->{id} ) {
  75. # delete individual transactions
  76. $query = qq|
  77. DELETE FROM acc_trans WHERE trans_id = $id|;
  78. $dbh->do($query) || $form->dberror($query);
  79. }
  80. }
  81. if ( !$form->{id} ) {
  82. my $uid = localtime;
  83. $uid .= "$$";
  84. $query = qq|
  85. INSERT INTO gl (reference)
  86. VALUES ('$uid')|;
  87. $sth = $dbh->prepare($query);
  88. $sth->execute() || $form->dberror($query);
  89. $query = qq|
  90. SELECT id
  91. FROM gl
  92. WHERE reference = '$uid'|;
  93. ( $form->{id} ) = $dbh->selectrow_array($query);
  94. }
  95. ( $null, $department_id ) = split /--/, $form->{department};
  96. $department_id *= 1;
  97. $form->{reference} ||= $form->{id};
  98. $query = qq|
  99. UPDATE gl
  100. SET reference = | . $dbh->quote( $form->{reference} ) . qq|,
  101. description = | . $dbh->quote( $form->{description} ) . qq|,
  102. notes = | . $dbh->quote( $form->{notes} ) . qq|,
  103. transdate = ?,
  104. department_id = ?
  105. WHERE id = ?|;
  106. if (defined $form->{approved}) {
  107. my $query = qq| UPDATE gl SET approved = ? WHERE id = ?|;
  108. $dbh->prepare($query)->execute($form->{approved}, $form->{id})
  109. || $form->dberror($query);
  110. if (!$form->{approved} and $form->{batch_id}){
  111. if (not defined $form->{batch_id}){
  112. $form->error($locale->text('Batch ID Missing'));
  113. }
  114. my $query = qq|
  115. INSERT INTO voucher (batch_id, trans_id, batch_class)
  116. VALUES (?, ?, (select id FROM batch_class
  117. WHERE class = ?))|;
  118. my $sth2 = $dbh->prepare($query);
  119. $sth2->execute($form->{batch_id}, $form->{id}, 'gl') ||
  120. $form->dberror($query);
  121. }
  122. }
  123. $sth = $dbh->prepare($query);
  124. print STDERR $query;
  125. $sth->execute( $form->{transdate}, $department_id, $form->{id} )
  126. || $form->dberror($query);
  127. my $amount = 0;
  128. my $posted = 0;
  129. my $debit;
  130. my $credit;
  131. # insert acc_trans transactions
  132. for $i ( 1 .. $form->{rowcount} ) {
  133. $debit = $form->parse_amount( $myconfig, $form->{"debit_$i"} );
  134. $credit = $form->parse_amount( $myconfig, $form->{"credit_$i"} );
  135. # extract accno
  136. ($accno) = split( /--/, $form->{"accno_$i"} );
  137. if ($credit) {
  138. $amount = $credit;
  139. $posted = 0;
  140. }
  141. if ($debit) {
  142. $amount = $debit * -1;
  143. $posted = 0;
  144. }
  145. # add the record
  146. if ( !$posted ) {
  147. ( $null, $project_id ) = split /--/, $form->{"projectnumber_$i"};
  148. $project_id ||= undef;
  149. $query = qq|
  150. INSERT INTO acc_trans
  151. (trans_id, chart_id, amount,
  152. transdate, source, project_id,
  153. fx_transaction, memo, cleared)
  154. VALUES (?, (SELECT id
  155. FROM chart
  156. WHERE accno = ?),
  157. ?, ?, ?, ?, ?, ?, ?)|;
  158. $sth = $dbh->prepare($query);
  159. $sth->execute(
  160. $form->{id}, $accno,
  161. $amount, $form->{transdate},
  162. $form->{"source_$i"}, $project_id,
  163. ($form->{"fx_transaction_$i"} || 0), $form->{"memo_$i"},
  164. ($form->{"cleared_$i"} || 0)
  165. ) || $form->dberror($query);
  166. $posted = 1;
  167. }
  168. }
  169. my %audittrail = (
  170. tablename => 'gl',
  171. reference => $form->{reference},
  172. formname => 'transaction',
  173. action => 'posted',
  174. id => $form->{id}
  175. );
  176. $form->audittrail( $dbh, "", \%audittrail );
  177. $form->save_recurring( $dbh, $myconfig );
  178. # commit and redirect
  179. my $rc = $dbh->commit;
  180. $rc;
  181. }
  182. sub all_transactions {
  183. my ( $self, $myconfig, $form ) = @_;
  184. # connect to database
  185. my $dbh = $form->{dbh};
  186. my $query;
  187. my $sth;
  188. my $var;
  189. my $null;
  190. if ($form->{accno} and !$form->{chart_id}){
  191. my $sth = $dbh->prepare('SELECT id FROM chart WHERE accno = ?');
  192. $sth->execute($form->{accno});
  193. ($form->{chart_id}) = $sth->fetchrow_array();
  194. delete $form->{accno};
  195. }
  196. my ( $glwhere, $arwhere, $apwhere ) = ( "1 = 1", "1 = 1", "1 = 1" );
  197. if ( $form->{reference} ne "" ) {
  198. $var = $dbh->quote( $form->like( lc $form->{reference} ) );
  199. $glwhere .= " AND lower(g.reference) LIKE $var";
  200. $arwhere .= " AND lower(a.invnumber) LIKE $var";
  201. $apwhere .= " AND lower(a.invnumber) LIKE $var";
  202. }
  203. if ( $form->{department} ne "" ) {
  204. ( $null, $var ) = split /--/, $form->{department};
  205. $var = $dbh->quote($var);
  206. $glwhere .= " AND g.department_id = $var";
  207. $arwhere .= " AND a.department_id = $var";
  208. $apwhere .= " AND a.department_id = $var";
  209. }
  210. if ( $form->{source} ne "" ) {
  211. $var = $dbh->quote( $form->like( lc $form->{source} ) );
  212. $glwhere .= " AND lower(ac.source) LIKE $var";
  213. $arwhere .= " AND lower(ac.source) LIKE $var";
  214. $apwhere .= " AND lower(ac.source) LIKE $var";
  215. }
  216. if ( $form->{memo} ne "" ) {
  217. $var = $dbh->quote( $form->like( lc $form->{memo} ) );
  218. $glwhere .= " AND lower(ac.memo) LIKE $var";
  219. $arwhere .= " AND lower(ac.memo) LIKE $var";
  220. $apwhere .= " AND lower(ac.memo) LIKE $var";
  221. }
  222. if (!form->{datefrom} && !$form->{dateto}
  223. && form->{year} && $form->{month}){
  224. ( $form->{datefrom}, $form->{dateto} ) =
  225. $form->from_to( $form->{year}, $form->{month}, $form->{interval} );
  226. }
  227. if ( $form->{datefrom} ) {
  228. $glwhere .= " AND ac.transdate >= " . $dbh->quote( $form->{datefrom} );
  229. $arwhere .= " AND ac.transdate >= " . $dbh->quote( $form->{datefrom} );
  230. $apwhere .= " AND ac.transdate >= " . $dbh->quote( $form->{datefrom} );
  231. }
  232. if ( $form->{dateto} ) {
  233. $glwhere .= " AND ac.transdate <= " . $dbh->quote( $form->{dateto} );
  234. $arwhere .= " AND ac.transdate <= " . $dbh->quote( $form->{dateto} );
  235. $apwhere .= " AND ac.transdate <= " . $dbh->quote( $form->{dateto} );
  236. }
  237. if ( $form->{amountfrom} ) {
  238. $glwhere .=
  239. " AND abs(ac.amount) >= " . $dbh->quote( $form->{amountfrom} );
  240. $arwhere .=
  241. " AND abs(ac.amount) >= " . $dbh->quote( $form->{amountfrom} );
  242. $apwhere .=
  243. " AND abs(ac.amount) >= " . $dbh->quote( $form->{amountfrom} );
  244. }
  245. if ( $form->{amountto} ) {
  246. $glwhere .=
  247. " AND abs(ac.amount) <= " . $dbh->quote( $form->{amountto} );
  248. $arwhere .=
  249. " AND abs(ac.amount) <= " . $dbh->quote( $form->{amountto} );
  250. $apwhere .=
  251. " AND abs(ac.amount) <= " . $dbh->quote( $form->{amountto} );
  252. }
  253. if ( $form->{description} ) {
  254. $var = $dbh->quote( $form->like( lc $form->{description} ) );
  255. $glwhere .= " AND lower(g.description) LIKE $var";
  256. $arwhere .= " AND (lower(e.name) LIKE $var
  257. OR lower(ac.memo) LIKE $var
  258. OR a.id IN (SELECT DISTINCT trans_id
  259. FROM invoice
  260. WHERE lower(description) LIKE $var))";
  261. $apwhere .= " AND (lower(e.name) LIKE $var
  262. OR lower(ac.memo) LIKE $var
  263. OR a.id IN (SELECT DISTINCT trans_id
  264. FROM invoice
  265. WHERE lower(description) LIKE $var))";
  266. }
  267. if ( $form->{notes} ) {
  268. $var = $dbh->quote( $form->like( lc $form->{notes} ) );
  269. $glwhere .= " AND lower(g.notes) LIKE $var";
  270. $arwhere .= " AND lower(a.notes) LIKE $var";
  271. $apwhere .= " AND lower(a.notes) LIKE $var";
  272. }
  273. if ( $form->{accno} ) {
  274. $var = $dbh->quote( $form->{accno} );
  275. $glwhere .= " AND c.accno = $var";
  276. $arwhere .= " AND c.accno = $var";
  277. $apwhere .= " AND c.accno = $var";
  278. }
  279. if ( $form->{gifi_accno} ) {
  280. $var = $dbh->quote( $form->{gifi_accno} );
  281. $glwhere .= " AND c.gifi_accno = $var";
  282. $arwhere .= " AND c.gifi_accno = $var";
  283. $apwhere .= " AND c.gifi_accno = $var";
  284. }
  285. if ( $form->{category} ne 'X' ) {
  286. $var = $dbh->quote( $form->{category} );
  287. $glwhere .= " AND c.category = $var";
  288. $arwhere .= " AND c.category = $var";
  289. $apwhere .= " AND c.category = $var";
  290. }
  291. if ( $form->{accno} ) {
  292. my $accno = $dbh->quote( $form->{accno} );
  293. # get category for account
  294. $query = qq|SELECT category, link, contra, description
  295. FROM chart
  296. WHERE accno = $accno|;
  297. (
  298. $form->{category}, $form->{link}, $form->{contra},
  299. $form->{account_description}
  300. ) = $dbh->selectrow_array($query);
  301. if ( $form->{datefrom} ) {
  302. $query = qq|
  303. SELECT SUM(ac.amount)
  304. FROM acc_trans ac
  305. JOIN chart c ON (ac.chart_id = c.id)
  306. WHERE c.accno = $accno
  307. AND ac.transdate < date | . $dbh->quote( $form->{datefrom} );
  308. ( $form->{balance} ) = $dbh->selectrow_array($query);
  309. }
  310. }
  311. if ( $form->{gifi_accno} ) {
  312. my $gifi = $dbh->quote( $form->{gifi_accno} );
  313. # get category for account
  314. $query = qq|SELECT c.category, c.link, c.contra, g.description
  315. FROM chart c
  316. LEFT JOIN gifi g ON (g.accno = c.gifi_accno)
  317. WHERE c.gifi_accno = $gifi|;
  318. (
  319. $form->{category}, $form->{link}, $form->{contra},
  320. $form->{gifi_account_description}
  321. ) = $dbh->selectrow_array($query);
  322. if ( $form->{datefrom} ) {
  323. $query = qq|
  324. SELECT SUM(ac.amount)
  325. FROM acc_trans ac
  326. JOIN chart c ON (ac.chart_id = c.id)
  327. WHERE c.gifi_accno = $gifi
  328. AND ac.transdate < date | . $dbh->quote( $form->{datefrom} );
  329. ( $form->{balance} ) = $dbh->selectrow_array($query);
  330. }
  331. }
  332. my $false = 'FALSE';
  333. my %ordinal = (
  334. id => 1,
  335. reference => 4,
  336. description => 5,
  337. transdate => 6,
  338. source => 7,
  339. accno => 9,
  340. department => 15,
  341. memo => 16
  342. );
  343. my @a = ( id, transdate, reference, source, description, accno );
  344. my $sortorder = $form->sort_order( \@a, \%ordinal );
  345. my $chart_id;
  346. if ($form->{chart_id}){
  347. $chart_id = $dbh->quote($form->{chart_id});
  348. } else {
  349. $chart_id = 'NULL';
  350. }
  351. if (!defined $form->{approved}){
  352. $approved = 'true';
  353. } elsif ($form->{approved} eq 'all') {
  354. $approved = 'NULL';
  355. } else {
  356. $approved = $dbh->quote($form->{approved});
  357. }
  358. my $query = qq|SELECT g.id, 'gl' AS type, $false AS invoice, g.reference,
  359. g.description, ac.transdate, ac.source,
  360. ac.amount, c.accno, c.gifi_accno, g.notes, c.link,
  361. '' AS till, ac.cleared, d.description AS department,
  362. ac.memo, c.description AS accname
  363. FROM gl AS g
  364. JOIN acc_trans ac ON (g.id = ac.trans_id)
  365. JOIN chart c ON (ac.chart_id = c.id)
  366. LEFT JOIN department d ON (d.id = g.department_id)
  367. WHERE $glwhere
  368. AND (ac.chart_id = $chart_id OR
  369. $chart_id IS NULL)
  370. AND ($approved IS NULL OR
  371. $approved =
  372. (ac.approved AND g.approved))
  373. UNION ALL
  374. SELECT a.id, 'ar' AS type, a.invoice, a.invnumber,
  375. e.name, ac.transdate, ac.source,
  376. ac.amount, c.accno, c.gifi_accno, a.notes, c.link,
  377. a.till, ac.cleared, d.description AS department,
  378. ac.memo, c.description AS accname
  379. FROM ar a
  380. JOIN acc_trans ac ON (a.id = ac.trans_id)
  381. JOIN chart c ON (ac.chart_id = c.id)
  382. JOIN entity_credit_account ec ON (a.entity_credit_account = ec.id)
  383. JOIN entity e ON (ec.entity_id = e.id)
  384. LEFT JOIN department d ON (d.id = a.department_id)
  385. WHERE $arwhere
  386. AND (ac.chart_id = $chart_id OR
  387. $chart_id IS NULL)
  388. AND ($approved IS NULL OR
  389. $approved =
  390. (ac.approved AND a.approved))
  391. UNION ALL
  392. SELECT a.id, 'ap' AS type, a.invoice, a.invnumber,
  393. e.name, ac.transdate, ac.source,
  394. ac.amount, c.accno, c.gifi_accno, a.notes, c.link,
  395. a.till, ac.cleared, d.description AS department,
  396. ac.memo, c.description AS accname
  397. FROM ap a
  398. JOIN acc_trans ac ON (a.id = ac.trans_id)
  399. JOIN chart c ON (ac.chart_id = c.id)
  400. JOIN entity_credit_account ec ON (a.entity_credit_account = ec.id)
  401. JOIN entity e ON (ec.entity_id = e.id)
  402. LEFT JOIN department d ON (d.id = a.department_id)
  403. WHERE $apwhere
  404. AND (ac.chart_id = $chart_id OR
  405. $chart_id IS NULL)
  406. AND ($approved IS NULL OR
  407. $approved =
  408. (ac.approved AND a.approved))
  409. ORDER BY $sortorder|;
  410. my $sth = $dbh->prepare($query);
  411. $sth->execute || $form->dberror($query);
  412. while ( my $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  413. # gl
  414. if ( $ref->{type} eq "gl" ) {
  415. $ref->{module} = "gl";
  416. }
  417. # ap
  418. if ( $ref->{type} eq "ap" ) {
  419. if ( $ref->{invoice} ) {
  420. $ref->{module} = "ir";
  421. }
  422. else {
  423. $ref->{module} = "ap";
  424. }
  425. }
  426. # ar
  427. if ( $ref->{type} eq "ar" ) {
  428. if ( $ref->{invoice} ) {
  429. $ref->{module} = ( $ref->{till} ) ? "ps" : "is";
  430. }
  431. else {
  432. $ref->{module} = "ar";
  433. }
  434. }
  435. if ( $ref->{amount} < 0 ) {
  436. $ref->{debit} = $ref->{amount} * -1;
  437. $ref->{credit} = 0;
  438. }
  439. else {
  440. $ref->{credit} = $ref->{amount};
  441. $ref->{debit} = 0;
  442. }
  443. push @{ $form->{GL} }, $ref;
  444. }
  445. $sth->finish;
  446. }
  447. sub transaction {
  448. my ( $self, $myconfig, $form ) = @_;
  449. my ( $query, $sth, $ref );
  450. # connect to database
  451. my $dbh = $form->{dbh};
  452. if ( $form->{id} ) {
  453. $query = "SELECT setting_key, value
  454. FROM defaults
  455. WHERE setting_key IN
  456. ('closedto',
  457. 'revtrans',
  458. 'separate_duties')";
  459. $sth = $dbh->prepare($query);
  460. $sth->execute || $form->dberror($query);
  461. my $results = $sth->fetchall_hashref('setting_key');
  462. $form->{closedto} = $results->{'closedto'}->{'value'};
  463. $form->{revtrans} = $results->{'revtrans'}->{'value'};
  464. #$form->{separate_duties} = $results->{'separate_duties'}->{'value'};
  465. $sth->finish;
  466. $query = qq|SELECT g.*, d.description AS department
  467. FROM gl g
  468. LEFT JOIN department d ON (d.id = g.department_id)
  469. WHERE g.id = ?|;
  470. $sth = $dbh->prepare($query);
  471. $sth->execute( $form->{id} ) || $form->dberror($query);
  472. $ref = $sth->fetchrow_hashref(NAME_lc);
  473. for ( keys %$ref ) { $form->{$_} = $ref->{$_} }
  474. $sth->finish;
  475. # retrieve individual rows
  476. $query = qq|SELECT ac.*, c.accno, c.description, p.projectnumber
  477. FROM acc_trans ac
  478. JOIN chart c ON (ac.chart_id = c.id)
  479. LEFT JOIN project p ON (p.id = ac.project_id)
  480. WHERE ac.trans_id = ?
  481. ORDER BY accno|;
  482. $sth = $dbh->prepare($query);
  483. $sth->execute( $form->{id} ) || $form->dberror($query);
  484. while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  485. if ( $ref->{fx_transaction} ) {
  486. $form->{transfer} = 1;
  487. }
  488. push @{ $form->{GL} }, $ref;
  489. }
  490. # get recurring transaction
  491. $form->get_recurring($dbh);
  492. }
  493. else {
  494. $query = "SELECT current_date AS transdate, setting_key, value
  495. FROM defaults
  496. WHERE setting_key IN
  497. ('closedto',
  498. 'separate_duties',
  499. 'revtrans')";
  500. $sth = $dbh->prepare($query);
  501. $sth->execute || $form->dberror($query);
  502. my $results = $sth->fetchall_hashref('setting_key');
  503. $form->{separate_duties} = $results->{'separate_duties'}->{'value'};
  504. $form->{closedto} = $results->{'closedto'}->{'value'};
  505. $form->{revtrans} = $results->{'revtrans'}->{'value'};
  506. if (!$form->{transdate}){
  507. $form->{transdate} = $results->{'revtrans'}->{'transdate'};
  508. }
  509. }
  510. $sth->finish;
  511. # get chart of accounts
  512. $query = qq|SELECT accno,description
  513. FROM chart
  514. WHERE charttype = 'A'
  515. ORDER BY accno|;
  516. $sth = $dbh->prepare($query);
  517. $sth->execute || $form->dberror($query);
  518. while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  519. push @{ $form->{all_accno} }, $ref;
  520. }
  521. $sth->finish;
  522. # get departments
  523. $form->all_departments( $myconfig, $dbh );
  524. # get projects
  525. $form->all_projects( $myconfig, $dbh, $form->{transdate} );
  526. $dbh->commit;
  527. }
  528. 1;