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