summaryrefslogtreecommitdiff
path: root/LedgerSMB/AA.pm
blob: 29bf8ce3f7f32f80033cdac8602ef8a23e4b8cb3 (plain)
  1. #=====================================================================
  2. # LedgerSMB
  3. # Small Medium Business Accounting software
  4. # http://www.ledgersmb.org/
  5. # Copyright (C) 2006
  6. # This work contains copyrighted information from a number of sources all used
  7. # with permission.
  8. #
  9. # This file contains source code included with or based on SQL-Ledger which
  10. # is Copyright Dieter Simader and DWS Systems Inc. 2000-2005 and licensed
  11. # under the GNU General Public License version 2 or, at your option, any later
  12. # version. For a full list including contact information of contributors,
  13. # maintainers, and copyright holders, see the CONTRIBUTORS file.
  14. #
  15. # Original Copyright Notice from SQL-Ledger 2.6.17 (before the fork):
  16. # Copyright (C) 2006
  17. #
  18. # Author: DWS Systems Inc.
  19. # Web: http://www.sql-ledger.org
  20. #
  21. # Contributors:
  22. #
  23. #
  24. # See COPYRIGHT file for copyright information
  25. #======================================================================
  26. #
  27. # This file has undergone whitespace cleanup.
  28. #
  29. #======================================================================
  30. #
  31. # AR/AP backend routines
  32. # common routines
  33. #
  34. #======================================================================
  35. package AA;
  36. use LedgerSMB::Sysconfig;
  37. sub post_transaction {
  38. my ( $self, $myconfig, $form ) = @_;
  39. for (1 .. $form->{rowcount}){
  40. $form->{"amount_$_"} = $form->parse_amount(
  41. $myconfig, $form->{"amount_$_"}
  42. );
  43. $form->{"amount_$_"} *= -1 if $form->{reverse};
  44. }
  45. # connect to database
  46. my $dbh = $form->{dbh};
  47. $form->{invnumber} = $form->update_defaults( $myconfig, $invnumber )
  48. unless $form->{invnumber};
  49. my $query;
  50. my $sth;
  51. my $null;
  52. ( $null, $form->{department_id} ) = split( /--/, $form->{department} );
  53. $form->{department_id} *= 1;
  54. my $ml = 1;
  55. my $table = 'ar';
  56. my $buysell = 'buy';
  57. my $ARAP = 'AR';
  58. my $invnumber = "sinumber";
  59. my $keepcleared;
  60. if ( $form->{vc} eq 'vendor' ) {
  61. $table = 'ap';
  62. $buysell = 'sell';
  63. $ARAP = 'AP';
  64. $ml = -1;
  65. $invnumber = "vinumber";
  66. }
  67. if ( $form->{currency} eq $form->{defaultcurrency} ) {
  68. $form->{exchangerate} = 1;
  69. }
  70. else {
  71. $exchangerate =
  72. $form->check_exchangerate( $myconfig, $form->{currency},
  73. $form->{transdate}, $buysell );
  74. $form->{exchangerate} =
  75. ($exchangerate)
  76. ? $exchangerate
  77. : $form->parse_amount( $myconfig, $form->{exchangerate} );
  78. }
  79. my @taxaccounts = split / /, $form->{taxaccounts};
  80. my $tax = 0;
  81. my $fxtax = 0;
  82. my $amount;
  83. my $diff;
  84. my %tax = ();
  85. my $accno;
  86. # add taxes
  87. foreach $accno (@taxaccounts) {
  88. $form->{"tax_$accno"} *= -1 if $form->{reverse};
  89. $fxtax += $tax{fxamount}{$accno} = $form->{"tax_$accno"};
  90. $tax += $tax{fxamount}{$accno};
  91. push @{ $form->{acc_trans}{taxes} },
  92. {
  93. accno => $accno,
  94. amount => $tax{fxamount}{$accno},
  95. project_id => undef,
  96. fx_transaction => 0
  97. };
  98. $amount = $tax{fxamount}{$accno} * $form->{exchangerate};
  99. $tax{amount}{$accno} = $form->round_amount( $amount - $diff, 2 );
  100. $diff = $tax{amount}{$accno} - ( $amount - $diff );
  101. $amount = $tax{amount}{$accno} - $tax{fxamount}{$accno};
  102. $tax += $amount;
  103. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  104. push @{ $form->{acc_trans}{taxes} },
  105. {
  106. accno => $accno,
  107. amount => $amount,
  108. project_id => undef,
  109. fx_transaction => 1
  110. };
  111. }
  112. }
  113. my %amount = ();
  114. my $fxinvamount = 0;
  115. for ( 1 .. $form->{rowcount} ) {
  116. $fxinvamount += $amount{fxamount}{$_} = $form->{"amount_$_"};
  117. }
  118. $form->{taxincluded} *= 1;
  119. my $i;
  120. my $project_id;
  121. my $cleared = 0;
  122. $diff = 0;
  123. # deduct tax from amounts if tax included
  124. for $i ( 1 .. $form->{rowcount} ) {
  125. if ( $amount{fxamount}{$i} ) {
  126. if ( $form->{taxincluded} ) {
  127. $amount =
  128. ($fxinvamount)
  129. ? $fxtax * $amount{fxamount}{$i} / $fxinvamount
  130. : 0;
  131. $amount{fxamount}{$i} -= $amount;
  132. }
  133. # multiply by exchangerate
  134. $amount = $amount{fxamount}{$i} * $form->{exchangerate};
  135. $amount{amount}{$i} = $form->round_amount( $amount - $diff, 2 );
  136. $diff = $amount{amount}{$i} - ( $amount - $diff );
  137. ( $null, $project_id ) = split /--/, $form->{"projectnumber_$i"};
  138. $project_id ||= undef;
  139. ($accno) = split /--/, $form->{"${ARAP}_amount_$i"};
  140. if ($keepcleared) {
  141. $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;
  142. }
  143. push @{ $form->{acc_trans}{lineitems} },
  144. {
  145. accno => $accno,
  146. amount => $amount{fxamount}{$i},
  147. project_id => $project_id,
  148. description => $form->{"description_$i"},
  149. cleared => $cleared,
  150. fx_transaction => 0
  151. };
  152. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  153. $amount = $amount{amount}{$i} - $amount{fxamount}{$i};
  154. push @{ $form->{acc_trans}{lineitems} },
  155. {
  156. accno => $accno,
  157. amount => $amount,
  158. project_id => $project_id,
  159. description => $form->{"description_$i"},
  160. cleared => $cleared,
  161. fx_transaction => 1
  162. };
  163. }
  164. }
  165. }
  166. my $invnetamount = 0;
  167. for ( @{ $form->{acc_trans}{lineitems} } ) { $invnetamount += $_->{amount} }
  168. my $invamount = $invnetamount + $tax;
  169. # adjust paidaccounts if there is no date in the last row
  170. $form->{paidaccounts}--
  171. unless ( $form->{"datepaid_$form->{paidaccounts}"} );
  172. if ( $form->{vc} ne "customer" ) {
  173. $form->{vc} = "vendor";
  174. }
  175. my $paid = 0;
  176. my $fxamount;
  177. $diff = 0;
  178. # add payments
  179. for $i ( 1 .. $form->{paidaccounts} ) {
  180. $form->{"paid_$i"} = $form->parse_amount(
  181. $myconfig, $form->{"paid_$i"}
  182. );
  183. $form->{"paid_$i"} *= -1 if $form->{reverse};
  184. $fxamount = $form->{"paid_$i"};
  185. if ($fxamount) {
  186. $paid += $fxamount;
  187. $paidamount = $fxamount * $form->{exchangerate};
  188. $amount = $form->round_amount( $paidamount - $diff, 2 );
  189. $diff = $amount - ( $paidamount - $diff );
  190. $form->{datepaid} = $form->{"datepaid_$i"};
  191. $paid{fxamount}{$i} = $fxamount;
  192. $paid{amount}{$i} = $amount;
  193. }
  194. }
  195. $fxinvamount += $fxtax unless $form->{taxincluded};
  196. $fxinvamount = $form->round_amount( $fxinvamount, 2 );
  197. $invamount = $form->round_amount( $invamount, 2 );
  198. $paid = $form->round_amount( $paid, 2 );
  199. $paid =
  200. ( $fxinvamount == $paid )
  201. ? $invamount
  202. : $form->round_amount( $paid * $form->{exchangerate}, 2 );
  203. $query = q|
  204. SELECT (SELECT value FROM defaults
  205. WHERE setting_key = 'fxgain_accno_id'),
  206. (SELECT value FROM defaults
  207. WHERE setting_key = 'fxloss_accno_id')|;
  208. my ( $fxgain_accno_id, $fxloss_accno_id ) = $dbh->selectrow_array($query);
  209. ( $null, $form->{employee_id} ) = split /--/, $form->{employee};
  210. unless ( $form->{employee_id} ) {
  211. ( $form->{employee}, $form->{employee_id} ) = $form->get_employee($dbh);
  212. }
  213. # check if id really exists
  214. if ( $form->{id} ) {
  215. my $id = $dbh->quote( $form->{id} );
  216. $keepcleared = 1;
  217. $query = qq|
  218. SELECT id
  219. FROM $table
  220. WHERE id = $id|;
  221. if ( $dbh->selectrow_array($query) ) {
  222. # delete detail records
  223. $query = qq|
  224. DELETE FROM acc_trans
  225. WHERE trans_id = $id|;
  226. $dbh->do($query) || $form->dberror($query);
  227. }
  228. }
  229. else {
  230. my $uid = localtime;
  231. $uid .= "$$";
  232. $query = qq|
  233. INSERT INTO $table (invnumber)
  234. VALUES ('$uid')|;
  235. $dbh->do($query) || $form->dberror($query);
  236. $query = qq|
  237. SELECT id FROM $table
  238. WHERE invnumber = '$uid'|;
  239. ( $form->{id} ) = $dbh->selectrow_array($query);
  240. }
  241. # record last payment date in ar/ap table
  242. $form->{datepaid} = $form->{transdate} unless $form->{datepaid};
  243. my $datepaid = ($paid) ? qq|'$form->{datepaid}'| : 'NOW';
  244. $query = qq|
  245. UPDATE $table
  246. SET invnumber = ?,
  247. ordnumber = ?,
  248. transdate = ?,
  249. entity_id = ?,
  250. taxincluded = ?,
  251. amount = ?,
  252. duedate = ?,
  253. paid = ?,
  254. datepaid = ?,
  255. netamount = ?,
  256. curr = ?,
  257. notes = ?,
  258. department_id = ?,
  259. person_id = ?,
  260. ponumber = ?
  261. WHERE id = ?
  262. |;
  263. my @queryargs = (
  264. $form->{invnumber}, $form->{ordnumber},
  265. $form->{transdate}, $form->{"$form->{vc}_id"},
  266. $form->{taxincluded}, $invamount,
  267. $form->{duedate}, $paid,
  268. $datepaid, $invnetamout,
  269. $form->{currency}, $form->{notes},
  270. $form->{department_id}, $form->{employee_id},
  271. $form->{ponumber}, $form->{id}
  272. );
  273. $dbh->prepare($query)->execute(@queryargs) || $form->dberror($query);
  274. if (defined $form->{approved}) {
  275. $query = qq| UPDATE $table SET approved = ? WHERE id = ?|;
  276. $dbh->prepare($query)->execute($form->{approved}, $form->{id}) ||
  277. $form->dberror($query);
  278. if (!$form->{approved}){
  279. if (not defined $form->{batch_id}){
  280. $form->error($locale->text('Batch ID Missing'));
  281. }
  282. $query = qq|
  283. INSERT INTO voucher (batch_id, trans_id) VALUES (?, ?)|;
  284. $dbh->prepare($query)->execute($form->{batch_id}, $form->{id}) ||
  285. $form->dberror($query);
  286. }
  287. }
  288. @queries = $form->run_custom_queries( $table, 'INSERT' );
  289. # update exchangerate
  290. my $buy = $form->{exchangerate};
  291. my $sell = 0;
  292. if ( $form->{vc} eq 'vendor' ) {
  293. $buy = 0;
  294. $sell = $form->{exchangerate};
  295. }
  296. if ( ( $form->{currency} ne $form->{defaultcurrency} ) && !$exchangerate ) {
  297. $form->update_exchangerate( $dbh, $form->{currency}, $form->{transdate},
  298. $buy, $sell );
  299. }
  300. my $ref;
  301. # add individual transactions
  302. foreach $ref ( @{ $form->{acc_trans}{lineitems} } ) {
  303. # insert detail records in acc_trans
  304. if ( $ref->{amount} ) {
  305. $query = qq|
  306. INSERT INTO acc_trans
  307. (trans_id, chart_id, amount,
  308. transdate, project_id, memo,
  309. fx_transaction, cleared)
  310. VALUES (?, (SELECT id FROM chart
  311. WHERE accno = ?),
  312. ?, ?, ?, ?, ?, ?)|;
  313. @queryargs = (
  314. $form->{id}, $ref->{accno},
  315. $ref->{amount} * $ml, $form->{transdate},
  316. $ref->{project_id}, $ref->{description},
  317. $ref->{fx_transaction}, $ref->{cleared}
  318. );
  319. $dbh->prepare($query)->execute(@queryargs)
  320. || $form->dberror($query);
  321. }
  322. }
  323. # save taxes
  324. foreach $ref ( @{ $form->{acc_trans}{taxes} } ) {
  325. if ( $ref->{amount} ) {
  326. $query = qq|
  327. INSERT INTO acc_trans
  328. (trans_id, chart_id, amount,
  329. transdate, fx_transaction)
  330. VALUES (?, (SELECT id FROM chart
  331. WHERE accno = ?),
  332. ?, ?, ?)|;
  333. @queryargs = (
  334. $form->{id}, $ref->{accno}, $ref->{amount} * $ml,
  335. $form->{transdate}, $ref->{fx_transaction}
  336. );
  337. $dbh->prepare($query)->execute(@queryargs)
  338. || $form->dberror($query);
  339. }
  340. }
  341. my $arap;
  342. # record ar/ap
  343. if ( ( $arap = $invamount ) ) {
  344. ($accno) = split /--/, $form->{$ARAP};
  345. $query = qq|
  346. INSERT INTO acc_trans
  347. (trans_id, chart_id, amount, transdate)
  348. VALUES (?, (SELECT id FROM chart
  349. WHERE accno = ?),
  350. ?, ?)|;
  351. @queryargs =
  352. ( $form->{id}, $accno, $invamount * -1 * $ml, $form->{transdate} );
  353. $dbh->prepare($query)->execute(@queryargs)
  354. || $form->dberror($query);
  355. }
  356. # if there is no amount force ar/ap
  357. if ( $fxinvamount == 0 ) {
  358. $arap = 1;
  359. }
  360. my $exchangerate;
  361. # add paid transactions
  362. for $i ( 1 .. $form->{paidaccounts} ) {
  363. if ( $paid{fxamount}{$i} ) {
  364. ($accno) = split( /--/, $form->{"${ARAP}_paid_$i"} );
  365. $form->{"datepaid_$i"} = $form->{transdate}
  366. unless ( $form->{"datepaid_$i"} );
  367. $exchangerate = 0;
  368. if ( $form->{currency} eq $form->{defaultcurrency} ) {
  369. $form->{"exchangerate_$i"} = 1;
  370. }
  371. else {
  372. $exchangerate =
  373. $form->check_exchangerate( $myconfig, $form->{currency},
  374. $form->{"datepaid_$i"}, $buysell );
  375. $form->{"exchangerate_$i"} =
  376. ($exchangerate)
  377. ? $exchangerate
  378. : $form->parse_amount( $myconfig,
  379. $form->{"exchangerate_$i"} );
  380. }
  381. # if there is no amount
  382. if ( $fxinvamount == 0 ) {
  383. $form->{exchangerate} = $form->{"exchangerate_$i"};
  384. }
  385. # ar/ap amount
  386. if ($arap) {
  387. ($accno) = split /--/, $form->{$ARAP};
  388. # add ar/ap
  389. $query = qq|
  390. INSERT INTO acc_trans
  391. (trans_id, chart_id,
  392. amount,transdate)
  393. VALUES (?, (SELECT id FROM chart
  394. WHERE accno = ?),
  395. ?, ?)|;
  396. @queryargs = (
  397. $form->{id}, $accno,
  398. $paid{amount}{$i} * $ml,
  399. $form->{"datepaid_$i"}
  400. );
  401. $dbh->prepare($query)->execute(@queryargs)
  402. || $form->dberror($query);
  403. }
  404. $arap = $paid{amount}{$i};
  405. # add payment
  406. if ( $paid{fxamount}{$i} ) {
  407. ($accno) = split /--/, $form->{"${ARAP}_paid_$i"};
  408. my $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;
  409. $amount = $paid{fxamount}{$i};
  410. $query = qq|
  411. INSERT INTO acc_trans
  412. (trans_id, chart_id, amount,
  413. transdate, source, memo,
  414. cleared)
  415. VALUES (?, (SELECT id FROM chart
  416. WHERE accno = ?),
  417. ?, ?, ?, ?, ?)|;
  418. @queryargs = (
  419. $form->{id}, $accno,
  420. $amount * -1 * $ml, $form->{"datepaid_$i"},
  421. $form->{"source_$i"}, $form->{"memo_$i"},
  422. $cleared
  423. );
  424. $dbh->prepare($query)->execute(@queryargs)
  425. || $form->dberror($query);
  426. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  427. # exchangerate gain/loss
  428. $amount = (
  429. $form->round_amount(
  430. $paid{fxamount}{$i} * $form->{exchangerate}, 2 ) -
  431. $form->round_amount(
  432. $paid{fxamount}{$i} * $form->{"exchangerate_$i"}, 2
  433. )
  434. ) * -1;
  435. if ($amount) {
  436. my $accno_id =
  437. ( ( $amount * $ml ) > 0 )
  438. ? $fxgain_accno_id
  439. : $fxloss_accno_id;
  440. $query = qq|
  441. INSERT INTO acc_trans
  442. (trans_id,
  443. chart_id,
  444. amount,
  445. transdate,
  446. fx_transaction,
  447. cleared)
  448. VALUES (?, ?,
  449. ?,
  450. ?, '1', ?)|;
  451. @queryargs = (
  452. $form->{id}, $accno_id,
  453. $amount * $ml,
  454. $form->{"datepaid_$i"}, $cleared
  455. );
  456. $sth = $dbh->prepare($query);
  457. $sth->execute(@queryargs)
  458. || $form->dberror($query);
  459. }
  460. # exchangerate difference
  461. $amount = $paid{amount}{$i} - $paid{fxamount}{$i} + $amount;
  462. $query = qq|
  463. INSERT INTO acc_trans
  464. (trans_id, chart_id,
  465. amount,
  466. transdate,
  467. fx_transaction,
  468. cleared, source)
  469. VALUES (?, (SELECT id
  470. FROM chart
  471. WHERE accno
  472. = ?),
  473. ?, ?,
  474. '1', ?, ?)|;
  475. @queryargs = (
  476. $form->{id}, $accno,
  477. $amount * -1 * $ml,
  478. $form->{"datepaid_$i"},
  479. $cleared, $form->{"source_$i"}
  480. );
  481. $sth = $dbh->prepare($query);
  482. $sth->execute(@queryargs)
  483. || $form->dberror($query);
  484. }
  485. # update exchangerate record
  486. $buy = $form->{"exchangerate_$i"};
  487. $sell = 0;
  488. if ( $form->{vc} eq 'vendor' ) {
  489. $buy = 0;
  490. $sell = $form->{"exchangerate_$i"};
  491. }
  492. if ( ( $form->{currency} ne $form->{defaultcurrency} )
  493. && !$exchangerate )
  494. {
  495. $form->update_exchangerate( $dbh, $form->{currency},
  496. $form->{"datepaid_$i"},
  497. $buy, $sell );
  498. }
  499. }
  500. }
  501. }
  502. # save printed and queued
  503. $form->save_status($dbh);
  504. my %audittrail = (
  505. tablename => $table,
  506. reference => $form->{invnumber},
  507. formname => 'transaction',
  508. action => 'posted',
  509. id => $form->{id}
  510. );
  511. $form->audittrail( $dbh, "", \%audittrail );
  512. $form->save_recurring( $dbh, $myconfig );
  513. my $rc = $dbh->commit;
  514. $rc;
  515. }
  516. sub delete_transaction {
  517. my ( $self, $myconfig, $form ) = @_;
  518. # connect to database, turn AutoCommit off
  519. my $dbh = $form->{dbh};
  520. my $table = ( $form->{vc} eq 'customer' ) ? 'ar' : 'ap';
  521. my %audittrail = (
  522. tablename => $table,
  523. reference => $form->{invnumber},
  524. formname => 'transaction',
  525. action => 'deleted',
  526. id => $form->{id}
  527. );
  528. $form->audittrail( $dbh, "", \%audittrail );
  529. my $query = qq|DELETE FROM $table WHERE id = $form->{id}|;
  530. $dbh->do($query) || $form->dberror($query);
  531. $query = qq|DELETE FROM acc_trans WHERE trans_id = ?|;
  532. $dbh->prepare($query)->execute( $form->{id} ) || $form->dberror($query);
  533. # get spool files
  534. $query = qq|SELECT spoolfile
  535. FROM status
  536. WHERE trans_id = ?
  537. AND spoolfile IS NOT NULL|;
  538. my $sth = $dbh->prepare($query);
  539. $sth->execute( $form->{id} ) || $form->dberror($query);
  540. my $spoolfile;
  541. my @spoolfiles = ();
  542. while ( ($spoolfile) = $sth->fetchrow_array ) {
  543. push @spoolfiles, $spoolfile;
  544. }
  545. $sth->finish;
  546. $query = qq|DELETE FROM status WHERE trans_id = ?|;
  547. $dbh->prepare($query)->execute( $form->{id} ) || $form->dberror($query);
  548. # commit
  549. my $rc = $dbh->commit;
  550. if ($rc) {
  551. foreach $spoolfile (@spoolfiles) {
  552. unlink "${LedgerSMB::Sysconfig::spool}/$spoolfile" if $spoolfile;
  553. }
  554. }
  555. $rc;
  556. }
  557. sub transactions {
  558. my ( $self, $myconfig, $form ) = @_;
  559. # connect to database
  560. my $dbh = $form->{dbh};
  561. my $null;
  562. my $var;
  563. my $paid = "a.paid";
  564. my $ml = 1;
  565. my $ARAP = 'AR';
  566. my $table = 'ar';
  567. my $buysell = 'buy';
  568. my $acc_trans_join;
  569. my $acc_trans_flds;
  570. if ( $form->{vc} eq 'vendor' ) {
  571. $ml = -1;
  572. $ARAP = 'AP';
  573. $table = 'ap';
  574. $buysell = 'sell';
  575. }
  576. ( $form->{transdatefrom}, $form->{transdateto} ) =
  577. $form->from_to( $form->{year}, $form->{month}, $form->{interval} )
  578. if $form->{year} && $form->{month};
  579. my @paidargs = ();
  580. if ( $form->{outstanding} ) {
  581. $paid = qq|
  582. SELECT SUM(ac.amount) * -1 * $ml
  583. FROM acc_trans ac
  584. JOIN chart c ON (c.id = ac.chart_id)
  585. WHERE ac.trans_id = a.id
  586. AND (c.link LIKE '%${ARAP}_paid%'
  587. OR c.link = '')|;
  588. if ( $form->{transdateto} ) {
  589. $paid .= qq|
  590. AND ac.transdate <= ?|;
  591. push @paidargs, $form->{transdateto};
  592. }
  593. $form->{summary} = 1;
  594. }
  595. if ( !$form->{summary} ) {
  596. $acc_trans_flds = qq|
  597. , c.accno, ac.source,
  598. pr.projectnumber, ac.memo AS description,
  599. ac.amount AS linetotal,
  600. i.description AS linedescription|;
  601. $acc_trans_join = qq|
  602. JOIN acc_trans ac ON (a.id = ac.trans_id)
  603. JOIN chart c ON (c.id = ac.chart_id)
  604. LEFT JOIN project pr ON (pr.id = ac.project_id)
  605. LEFT JOIN invoice i ON (i.id = ac.invoice_id)|;
  606. }
  607. my $query = qq|
  608. SELECT a.id, a.invnumber, a.ordnumber, a.transdate,
  609. a.duedate, a.netamount, a.amount, ($paid) AS paid,
  610. a.invoice, a.datepaid, a.terms, a.notes,
  611. a.shipvia, a.shippingpoint, ee.name AS employee,
  612. vce.name,
  613. a.entity_id, a.till, me.name AS manager, a.curr,
  614. ex.$buysell AS exchangerate,
  615. d.description AS department,
  616. a.ponumber $acc_trans_flds
  617. FROM $table a
  618. JOIN $form->{vc} vc USING (entity_id)
  619. LEFT JOIN employee e ON (a.person_id = e.entity_id)
  620. LEFT JOIN employee m ON (e.managerid = m.id)
  621. JOIN entity ee ON (e.entity_id = ee.id)
  622. JOIN entity me ON (m.entity_id = me.id)
  623. JOIN entity vce ON (vc.entity_id = vce.id)
  624. LEFT JOIN exchangerate ex ON (ex.curr = a.curr
  625. AND ex.transdate = a.transdate)
  626. LEFT JOIN department d ON (a.department_id = d.id)
  627. $acc_trans_join|;
  628. my %ordinal = (
  629. id => 1,
  630. invnumber => 2,
  631. ordnumber => 3,
  632. transdate => 4,
  633. duedate => 5,
  634. datepaid => 10,
  635. shipvia => 13,
  636. shippingpoint => 14,
  637. employee => 15,
  638. name => 16,
  639. manager => 19,
  640. curr => 20,
  641. department => 22,
  642. ponumber => 23,
  643. accno => 24,
  644. source => 25,
  645. project => 26,
  646. description => 27
  647. );
  648. my @a = ( transdate, invnumber, name );
  649. push @a, "employee" if $form->{l_employee};
  650. push @a, "manager" if $form->{l_manager};
  651. my $sortorder = $form->sort_order( \@a, \%ordinal );
  652. my $where = "1 = 1";
  653. if ( $form->{"$form->{vc}_id"} ) {
  654. $where .= qq| AND a.entity_id = $form->{entity_id}|;
  655. }
  656. else {
  657. if ( $form->{ $form->{vc} } ) {
  658. $var = $dbh->quote( $form->like( lc $form->{ $form->{vc} } ) );
  659. $where .= " AND lower(vc.name) LIKE $var";
  660. }
  661. }
  662. for (qw(department employee)) {
  663. if ( $form->{$_} ) {
  664. ( $null, $var ) = split /--/, $form->{$_};
  665. $var = $dbh->quote($var);
  666. $where .= " AND a.${_}_id = $var";
  667. }
  668. }
  669. for (qw(invnumber ordnumber)) {
  670. if ( $form->{$_} ) {
  671. $var = $dbh->quote( $form->like( lc $form->{$_} ) );
  672. $where .= " AND lower(a.$_) LIKE $var";
  673. $form->{open} = $form->{closed} = 0;
  674. }
  675. }
  676. if ( $form->{partsid} ) {
  677. my $partsid = $dbh->quote( $form->{partsid} );
  678. $where .= " AND a.id IN (select trans_id FROM invoice
  679. WHERE parts_id = $partsid)";
  680. }
  681. for (qw(ponumber shipvia notes)) {
  682. if ( $form->{$_} ) {
  683. $var = $dbh->quote( $form->like( lc $form->{$_} ) );
  684. $where .= " AND lower(a.$_) LIKE $var";
  685. }
  686. }
  687. if ( $form->{description} ) {
  688. if ($acc_trans_flds) {
  689. $var = $dbh->quote( $form->like( lc $form->{description} ) );
  690. $where .= " AND lower(ac.memo) LIKE $var
  691. OR lower(i.description) LIKE $var";
  692. }
  693. else {
  694. $where .= " AND a.id = 0";
  695. }
  696. }
  697. if ( $form->{source} ) {
  698. if ($acc_trans_flds) {
  699. $var = $dbh->quote( $form->like( lc $form->{source} ) );
  700. $where .= " AND lower(ac.source) LIKE $var";
  701. }
  702. else {
  703. $where .= " AND a.id = 0";
  704. }
  705. }
  706. my $transdatefrom = $dbh->quote( $form->{transdatefrom} );
  707. $where .= " AND a.transdate >= $transdatefrom"
  708. if $form->{transdatefrom};
  709. my $transdateto = $dbh->quote( $form->{transdateto} );
  710. $where .= " AND a.transdate <= $transdateto" if $form->{transdateto};
  711. if ( $form->{open} || $form->{closed} ) {
  712. unless ( $form->{open} && $form->{closed} ) {
  713. $where .= " AND a.amount != a.paid" if ( $form->{open} );
  714. $where .= " AND a.amount = a.paid" if ( $form->{closed} );
  715. }
  716. }
  717. if ( $form->{till} ne "" ) {
  718. $where .= " AND a.invoice = '1'
  719. AND a.till = $form->{till}";
  720. if ( $myconfig->{role} eq 'user' ) {
  721. my $login = $dbh->quote( $form->{login} );
  722. $where .= " AND e.login = $login";
  723. }
  724. }
  725. if ( $form->{$ARAP} ) {
  726. my ($accno) = split /--/, $form->{$ARAP};
  727. $accno = $dbh->quote($accno);
  728. $where .= qq|
  729. AND a.id IN (SELECT ac.trans_id
  730. FROM acc_trans ac
  731. JOIN chart c ON (c.id = ac.chart_id)
  732. WHERE a.id = ac.trans_id
  733. AND c.accno = $accno)|;
  734. }
  735. if ( $form->{description} ) {
  736. $var = $dbh->quote( $form->like( lc $form->{description} ) );
  737. $where .= qq|
  738. AND (a.id IN (SELECT DISTINCT trans_id
  739. FROM acc_trans
  740. WHERE lower(memo) LIKE '$var')
  741. OR a.id IN
  742. (SELECT DISTINCT trans_id
  743. FROM invoice
  744. WHERE lower(description)
  745. LIKE '$var'))|;
  746. }
  747. if ($form->{invoice_type}) {
  748. if ( $form->{invoice_type} == 2 ) {
  749. $where .= qq|
  750. AND a.on_hold = 'f'
  751. |;
  752. }
  753. if ($form->{invoice_type} == 3) {
  754. $where .= qq|
  755. AND a.on_hold = 't'
  756. |;
  757. }
  758. }
  759. # the third state, all invoices, sets no explicit toggles. It just selects them all, as normal.
  760. $query .= "WHERE $where
  761. ORDER BY $sortorder";
  762. my $sth = $dbh->prepare($query);
  763. $sth->execute(@paidargs) || $form->dberror($query);
  764. while ( my $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  765. $form->db_parse_numeric(sth => $sth, hashref => $ref);
  766. $ref->{exchangerate} = 1 unless $ref->{exchangerate};
  767. if ( $ref->{linetotal} <= 0 ) {
  768. $ref->{debit} = $ref->{linetotal} * -1;
  769. $ref->{credit} = 0;
  770. }
  771. else {
  772. $ref->{debit} = 0;
  773. $ref->{credit} = $ref->{linetotal};
  774. }
  775. if ( $ref->{invoice} ) {
  776. $ref->{description} ||= $ref->{linedescription};
  777. }
  778. if ( $form->{outstanding} ) {
  779. next
  780. if $form->round_amount( $ref->{amount}, 2 ) ==
  781. $form->round_amount( $ref->{paid}, 2 );
  782. }
  783. push @{ $form->{transactions} }, $ref;
  784. }
  785. $sth->finish;
  786. $dbh->commit;
  787. }
  788. # this is used in IS, IR to retrieve the name
  789. sub get_name {
  790. my ( $self, $myconfig, $form ) = @_;
  791. # sanitize $form->{vc}
  792. if ( $form->{vc} ne 'customer' ) {
  793. $form->{vc} = 'vendor';
  794. }
  795. else {
  796. $form->{vc} = 'customer';
  797. }
  798. # connect to database
  799. my $dbh = $form->{dbh};
  800. my $dateformat = $myconfig->{dateformat};
  801. if ( $myconfig->{dateformat} !~ /^y/ ) {
  802. my @a = split /\W/, $form->{transdate};
  803. $dateformat .= "yy" if ( length $a[2] > 2 );
  804. }
  805. if ( $form->{transdate} !~ /\W/ ) {
  806. $dateformat = 'yyyymmdd';
  807. }
  808. my $duedate;
  809. $dateformat = $dbh->quote($dateformat);
  810. my $tdate = $dbh->quote( $form->{transdate} );
  811. $duedate = ( $form->{transdate} )
  812. ? "to_date($tdate, $dateformat)
  813. + c.terms"
  814. : "current_date + c.terms";
  815. $form->{"$form->{vc}_id"} *= 1;
  816. # get customer/vendor
  817. my $query = qq|
  818. SELECT entity.name AS $form->{vc}, c.discount,
  819. c.creditlimit,
  820. c.terms, c.taxincluded,
  821. c.curr AS currency,
  822. c.language_code, $duedate AS duedate,
  823. b.discount AS tradediscount,
  824. b.description AS business
  825. FROM $form->{vc} c
  826. JOIN entity ON (entity.id = c.entity_id)
  827. LEFT JOIN business b ON (b.id = c.business_id)
  828. WHERE c.entity_id = ?|;
  829. # TODO: Add location join
  830. @queryargs = ( $form->{"$form->{vc}_id"} );
  831. my $sth = $dbh->prepare($query);
  832. $sth->execute(@queryargs) || $form->dberror($query);
  833. $ref = $sth->fetchrow_hashref(NAME_lc);
  834. $form->db_parse_numeric(sth => $sth, hashref => $ref);
  835. if ( $form->{id} ) {
  836. for (qw(currency employee employee_id intnotes)) {
  837. delete $ref->{$_};
  838. }
  839. }
  840. for ( keys %$ref ) { $form->{$_} = $ref->{$_} }
  841. $sth->finish;
  842. # TODO: Retrieve contact records
  843. my $buysell = ( $form->{vc} eq 'customer' ) ? "buy" : "sell";
  844. # if no currency use defaultcurrency
  845. $form->{currency} =
  846. ( $form->{currency} )
  847. ? $form->{currency}
  848. : $form->{defaultcurrency};
  849. $form->{exchangerate} = 0
  850. if $form->{currency} eq $form->{defaultcurrency};
  851. if ( $form->{transdate}
  852. && ( $form->{currency} ne $form->{defaultcurrency} ) )
  853. {
  854. $form->{exchangerate} =
  855. $form->get_exchangerate( $dbh, $form->{currency}, $form->{transdate},
  856. $buysell );
  857. }
  858. $form->{forex} = $form->{exchangerate};
  859. # if no employee, default to login
  860. ( $form->{employee}, $form->{employee_id} ) = $form->get_employee($dbh)
  861. unless $form->{employee_id};
  862. my $arap = ( $form->{vc} eq 'customer' ) ? 'ar' : 'ap';
  863. my $ARAP = uc $arap;
  864. $form->{creditremaining} = $form->{creditlimit};
  865. $query = qq|
  866. SELECT SUM(amount - paid)
  867. FROM $arap
  868. WHERE id = ?|;
  869. $sth = $dbh->prepare($query);
  870. $sth->execute( $form->{"$form->{vc}_id"} )
  871. || $form->dberror($query);
  872. ( $form->{creditremaining} ) -= $sth->fetchrow_array;
  873. $sth->finish;
  874. if ( $form->{vc} ne "customer" ) {
  875. $form->{vc} = 'vendor';
  876. }
  877. $query = qq|
  878. SELECT o.amount, (SELECT e.$buysell FROM exchangerate e
  879. WHERE e.curr = o.curr
  880. AND e.transdate = o.transdate)
  881. FROM oe o
  882. WHERE o.entity_id =
  883. (select entity_id from $form->{vc} WHERE id = ?)
  884. AND o.quotation = '0' AND o.closed = '0'|;
  885. $sth = $dbh->prepare($query);
  886. $sth->execute( $form->{"$form->{vc}_id"} ) || $form->dberror($query);
  887. while ( my @ref = $sth->fetchrow_array ) {
  888. $form->db_parse_numeric(sth => $sth, arrayref => \@ref);
  889. my ($amount, $exch) = @ref;
  890. $exch = 1 unless $exch;
  891. $form->{creditremaining} -= $amount * $exch;
  892. }
  893. $sth->finish;
  894. # get shipto if we did not converted an order or invoice
  895. if ( !$form->{shipto} ) {
  896. for (
  897. qw(shiptoname shiptoaddress1 shiptoaddress2
  898. shiptocity shiptostate shiptozipcode
  899. shiptocountry shiptocontact shiptophone
  900. shiptofax shiptoemail)
  901. )
  902. {
  903. delete $form->{$_};
  904. }
  905. ## needs fixing (SELECT *)
  906. $query = qq|
  907. SELECT *
  908. FROM shipto
  909. WHERE trans_id = $form->{"$form->{vc}_id"}|;
  910. $sth = $dbh->prepare($query);
  911. $sth->execute || $form->dberror($query);
  912. $ref = $sth->fetchrow_hashref(NAME_lc);
  913. for ( keys %$ref ) { $form->{$_} = $ref->{$_} }
  914. $sth->finish;
  915. }
  916. # get taxes
  917. $query = qq|
  918. SELECT c.accno
  919. FROM chart c
  920. JOIN $form->{vc}tax ct ON (ct.chart_id = c.id)
  921. WHERE ct.$form->{vc}_id = ?|;
  922. $sth = $dbh->prepare($query);
  923. $sth->execute( $form->{"$form->{vc}_id"} ) || $form->dberror($query);
  924. my %tax;
  925. while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  926. $tax{ $ref->{accno} } = 1;
  927. }
  928. $sth->finish;
  929. $transdate = $dbh->quote( $form->{transdate} );
  930. my $where = qq|AND (t.validto >= $transdate OR t.validto IS NULL)|
  931. if $form->{transdate};
  932. # get tax rates and description
  933. $query = qq|
  934. SELECT c.accno, c.description, t.rate, t.taxnumber
  935. FROM chart c
  936. JOIN tax t ON (c.id = t.chart_id)
  937. WHERE c.link LIKE '%${ARAP}_tax%'
  938. $where
  939. ORDER BY accno, validto|;
  940. $sth = $dbh->prepare($query);
  941. $sth->execute || $form->dberror($query);
  942. $form->{taxaccounts} = "";
  943. my %a = ();
  944. while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  945. $form->db_parse_numeric(sth => $sth, hashref => $hashref);
  946. if ( $tax{ $ref->{accno} } ) {
  947. if ( not exists $a{ $ref->{accno} } ) {
  948. for (qw(rate description taxnumber)) {
  949. $form->{"$ref->{accno}_$_"} = $ref->{$_};
  950. }
  951. $form->{taxaccounts} .= "$ref->{accno} ";
  952. $a{ $ref->{accno} } = 1;
  953. }
  954. }
  955. }
  956. $sth->finish;
  957. chop $form->{taxaccounts};
  958. # setup last accounts used for this customer/vendor
  959. if ( !$form->{id} && $form->{type} !~ /_(order|quotation)/ ) {
  960. $query = qq|
  961. SELECT c.accno, c.description, c.link,
  962. c.category,
  963. ac.project_id,
  964. a.department_id
  965. FROM chart c
  966. JOIN acc_trans ac ON (ac.chart_id = c.id)
  967. JOIN $arap a ON (a.id = ac.trans_id)
  968. WHERE a.entity_id = ?
  969. AND a.id = (SELECT max(id)
  970. FROM $arap
  971. WHERE entity_id =
  972. ?)
  973. |;
  974. $sth = $dbh->prepare($query);
  975. $sth->execute( $form->{"$form->{vc}_id"}, $form->{"$form->{vc}_id"} )
  976. || $form->dberror($query);
  977. my $i = 0;
  978. while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
  979. $form->{department_id} = $ref->{department_id};
  980. if ( $ref->{link} =~ /_amount/ ) {
  981. $i++;
  982. $form->{"$form->{ARAP}_amount_$i"} =
  983. "$ref->{accno}--$ref->{description}"
  984. if $ref->{accno};
  985. $form->{"projectnumber_$i"} =
  986. "$ref->{projectnumber}--" . "$ref->{project_id}"
  987. if $ref->{project_id};
  988. }
  989. if ( $ref->{link} eq $form->{ARAP} ) {
  990. $form->{ $form->{ARAP} } = $form->{"$form->{ARAP}_1"} =
  991. "$ref->{accno}--" . "$ref->{description}"
  992. if $ref->{accno};
  993. }
  994. }
  995. $sth->finish;
  996. $query = "select description from department where id = ?";
  997. $sth = $dbh->prepare($query);
  998. $sth->execute($form->{department_id});
  999. ($form->{department}) = $sth->fetchrow_array;
  1000. $form->{rowcount} = $i if ( $i && !$form->{type} );
  1001. }
  1002. $dbh->commit;
  1003. }
  1004. 1;