/doc/plugins/hnb/

script' src='/cgit.js'>
summaryrefslogtreecommitdiff
path: root/LedgerSMB/AA.pm
blob: 22c490dc4d90306dea147b569cac938493f7867d (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. $form->{invnumber} = $form->update_defaults( $myconfig, $invnumber )
  40. unless $form->{invnumber};
  41. # connect to database
  42. my $dbh = $form->{dbh};
  43. my $query;
  44. my $sth;
  45. my $null;
  46. ( $null, $form->{department_id} ) = split( /--/, $form->{department} );
  47. $form->{department_id} *= 1;
  48. my $ml = 1;
  49. my $table = 'ar';
  50. my $buysell = 'buy';
  51. my $ARAP = 'AR';
  52. my $invnumber = "sinumber";
  53. my $keepcleared;
  54. if ( $form->{vc} eq 'vendor' ) {
  55. $table = 'ap';
  56. $buysell = 'sell';
  57. $ARAP = 'AP';
  58. $ml = -1;
  59. $invnumber = "vinumber";
  60. }
  61. if ( $form->{currency} eq $form->{defaultcurrency} ) {
  62. $form->{exchangerate} = 1;
  63. }
  64. else {
  65. $exchangerate =
  66. $form->check_exchangerate( $myconfig, $form->{currency},
  67. $form->{transdate}, $buysell );
  68. $form->{exchangerate} =
  69. ($exchangerate)
  70. ? $exchangerate
  71. : $form->parse_amount( $myconfig, $form->{exchangerate} );
  72. }
  73. my @taxaccounts = split / /, $form->{taxaccounts};
  74. my $tax = 0;
  75. my $fxtax = 0;
  76. my $amount;
  77. my $diff;
  78. my %tax = ();
  79. my $accno;
  80. # add taxes
  81. foreach $accno (@taxaccounts) {
  82. $fxtax += $tax{fxamount}{$accno} =
  83. $form->parse_amount( $myconfig, $form->{"tax_$accno"} );
  84. $tax += $tax{fxamount}{$accno};
  85. push @{ $form->{acc_trans}{taxes} },
  86. {
  87. accno => $accno,
  88. amount => $tax{fxamount}{$accno},
  89. project_id => undef,
  90. fx_transaction => 0
  91. };
  92. $amount = $tax{fxamount}{$accno} * $form->{exchangerate};
  93. $tax{amount}{$accno} = $form->round_amount( $amount - $diff, 2 );
  94. $diff = $tax{amount}{$accno} - ( $amount - $diff );
  95. $amount = $tax{amount}{$accno} - $tax{fxamount}{$accno};
  96. $tax += $amount;
  97. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  98. push @{ $form->{acc_trans}{taxes} },
  99. {
  100. accno => $accno,
  101. amount => $amount,
  102. project_id => undef,
  103. fx_transaction => 1
  104. };
  105. }
  106. }
  107. my %amount = ();
  108. my $fxinvamount = 0;
  109. for ( 1 .. $form->{rowcount} ) {
  110. $fxinvamount += $amount{fxamount}{$_} =
  111. $form->parse_amount( $myconfig, $form->{"amount_$_"} );
  112. }
  113. $form->{taxincluded} *= 1;
  114. my $i;
  115. my $project_id;
  116. my $cleared = 0;
  117. $diff = 0;
  118. # deduct tax from amounts if tax included
  119. for $i ( 1 .. $form->{rowcount} ) {
  120. if ( $amount{fxamount}{$i} ) {
  121. if ( $form->{taxincluded} ) {
  122. $amount =
  123. ($fxinvamount)
  124. ? $fxtax * $amount{fxamount}{$i} / $fxinvamount
  125. : 0;
  126. $amount{fxamount}{$i} -= $amount;
  127. }
  128. # multiply by exchangerate
  129. $amount = $amount{fxamount}{$i} * $form->{exchangerate};
  130. $amount{amount}{$i} = $form->round_amount( $amount - $diff, 2 );
  131. $diff = $amount{amount}{$i} - ( $amount - $diff );
  132. ( $null, $project_id ) = split /--/, $form->{"projectnumber_$i"};
  133. $project_id ||= undef;
  134. ($accno) = split /--/, $form->{"${ARAP}_amount_$i"};
  135. if ($keepcleared) {
  136. $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;
  137. }
  138. push @{ $form->{acc_trans}{lineitems} },
  139. {
  140. accno => $accno,
  141. amount => $amount{fxamount}{$i},
  142. project_id => $project_id,
  143. description => $form->{"description_$i"},
  144. cleared => $cleared,
  145. fx_transaction => 0
  146. };
  147. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  148. $amount = $amount{amount}{$i} - $amount{fxamount}{$i};
  149. push @{ $form->{acc_trans}{lineitems} },
  150. {
  151. accno => $accno,
  152. amount => $amount,
  153. project_id => $project_id,
  154. description => $form->{"description_$i"},
  155. cleared => $cleared,
  156. fx_transaction => 1
  157. };
  158. }
  159. }
  160. }
  161. my $invnetamount = 0;
  162. for ( @{ $form->{acc_trans}{lineitems} } ) { $invnetamount += $_->{amount} }
  163. my $invamount = $invnetamount + $tax;
  164. # adjust paidaccounts if there is no date in the last row
  165. $form->{paidaccounts}--
  166. unless ( $form->{"datepaid_$form->{paidaccounts}"} );
  167. if ( $form->{vc} ne "customer" ) {
  168. $form->{vc} = "vendor";
  169. }
  170. my $paid = 0;
  171. my $fxamount;
  172. $diff = 0;
  173. # add payments
  174. for $i ( 1 .. $form->{paidaccounts} ) {
  175. $fxamount = $form->parse_amount( $myconfig, $form->{"paid_$i"} );
  176. if ($fxamount) {
  177. $paid += $fxamount;
  178. $paidamount = $fxamount * $form->{exchangerate};
  179. $amount = $form->round_amount( $paidamount - $diff, 2 );
  180. $diff = $amount - ( $paidamount - $diff );
  181. $form->{datepaid} = $form->{"datepaid_$i"};
  182. $paid{fxamount}{$i} = $fxamount;
  183. $paid{amount}{$i} = $amount;
  184. }
  185. }
  186. $fxinvamount += $fxtax unless $form->{taxincluded};
  187. $fxinvamount = $form->round_amount( $fxinvamount, 2 );
  188. $invamount = $form->round_amount( $invamount, 2 );
  189. $paid = $form->round_amount( $paid, 2 );
  190. $paid =
  191. ( $fxinvamount == $paid )
  192. ? $invamount
  193. : $form->round_amount( $paid * $form->{exchangerate}, 2 );
  194. $query = q|
  195. SELECT (SELECT value FROM defaults
  196. WHERE setting_key = 'fxgain_accno_id'),
  197. (SELECT value FROM defaults
  198. WHERE setting_key = 'fxloss_accno_id')|;
  199. my ( $fxgain_accno_id, $fxloss_accno_id ) = $dbh->selectrow_array($query);
  200. ( $null, $form->{employee_id} ) = split /--/, $form->{employee};
  201. unless ( $form->{employee_id} ) {
  202. ( $form->{employee}, $form->{employee_id} ) = $form->get_employee($dbh);
  203. }
  204. # check if id really exists
  205. if ( $form->{id} ) {
  206. my $id = $dbh->quote( $form->{id} );
  207. $keepcleared = 1;
  208. $query = qq|
  209. SELECT id
  210. FROM $table
  211. WHERE id = $id|;
  212. if ( $dbh->selectrow_array($query) ) {
  213. # delete detail records
  214. $query = qq|
  215. DELETE FROM acc_trans
  216. WHERE trans_id = $id|;
  217. $dbh->do($query) || $form->dberror($query);
  218. }
  219. }
  220. else {
  221. my $uid = localtime;
  222. $uid .= "$$";
  223. $query = qq|
  224. INSERT INTO $table (invnumber)
  225. VALUES ('$uid')|;
  226. $dbh->do($query) || $form->dberror($query);
  227. $query = qq|
  228. SELECT id FROM $table
  229. WHERE invnumber = '$uid'|;
  230. ( $form->{id} ) = $dbh->selectrow_array($query);
  231. }
  232. # record last payment date in ar/ap table
  233. $form->{datepaid} = $form->{transdate} unless $form->{datepaid};
  234. my $datepaid = ($paid) ? qq|'$form->{datepaid}'| : 'NOW';
  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. @queries = $form->run_custom_queries( $table, 'INSERT' );
  266. # update exchangerate
  267. my $buy = $form->{exchangerate};
  268. my $sell = 0;
  269. if ( $form->{vc} eq 'vendor' ) {
  270. $buy = 0;
  271. $sell = $form->{exchangerate};
  272. }
  273. if ( ( $form->{currency} ne $form->{defaultcurrency} ) && !$exchangerate ) {
  274. $form->update_exchangerate( $dbh, $form->{currency}, $form->{transdate},
  275. $buy, $sell );
  276. }
  277. my $ref;
  278. # add individual transactions
  279. foreach $ref ( @{ $form->{acc_trans}{lineitems} } ) {
  280. # insert detail records in acc_trans
  281. if ( $ref->{amount} ) {
  282. $query = qq|
  283. INSERT INTO acc_trans
  284. (trans_id, chart_id, amount,
  285. transdate, project_id, memo,
  286. fx_transaction, cleared)
  287. VALUES (?, (SELECT id FROM chart
  288. WHERE accno = ?),
  289. ?, ?, ?, ?, ?, ?)|;
  290. @queryargs = (
  291. $form->{id}, $ref->{accno},
  292. $ref->{amount} * $ml, $form->{transdate},
  293. $ref->{project_id}, $ref->{description},
  294. $ref->{fx_transaction}, $ref->{cleared}
  295. );
  296. $dbh->prepare($query)->execute(@queryargs)
  297. || $form->dberror($query);
  298. }
  299. }
  300. # save taxes
  301. foreach $ref ( @{ $form->{acc_trans}{taxes} } ) {
  302. if ( $ref->{amount} ) {
  303. $query = qq|
  304. INSERT INTO acc_trans
  305. (trans_id, chart_id, amount,
  306. transdate, fx_transaction)
  307. VALUES (?, (SELECT id FROM chart
  308. WHERE accno = ?),
  309. ?, ?, ?)|;
  310. @queryargs = (
  311. $form->{id}, $ref->{accno}, $ref->{amount} * $ml,
  312. $form->{transdate}, $ref->{fx_transaction}
  313. );
  314. $dbh->prepare($query)->execute(@queryargs)
  315. || $form->dberror($query);
  316. }
  317. }
  318. my $arap;
  319. # record ar/ap
  320. if ( ( $arap = $invamount ) ) {
  321. ($accno) = split /--/, $form->{$ARAP};
  322. $query = qq|
  323. INSERT INTO acc_trans
  324. (trans_id, chart_id, amount, transdate)
  325. VALUES (?, (SELECT id FROM chart
  326. WHERE accno = ?),
  327. ?, ?)|;
  328. @queryargs =
  329. ( $form->{id}, $accno, $invamount * -1 * $ml, $form->{transdate} );
  330. $dbh->prepare($query)->execute(@queryargs)
  331. || $form->dberror($query);
  332. }
  333. # if there is no amount force ar/ap
  334. if ( $fxinvamount == 0 ) {
  335. $arap = 1;
  336. }
  337. my $exchangerate;
  338. # add paid transactions
  339. for $i ( 1 .. $form->{paidaccounts} ) {
  340. if ( $paid{fxamount}{$i} ) {
  341. ($accno) = split( /--/, $form->{"${ARAP}_paid_$i"} );
  342. $form->{"datepaid_$i"} = $form->{transdate}
  343. unless ( $form->{"datepaid_$i"} );
  344. $exchangerate = 0;
  345. if ( $form->{currency} eq $form->{defaultcurrency} ) {
  346. $form->{"exchangerate_$i"} = 1;
  347. }
  348. else {
  349. $exchangerate =
  350. $form->check_exchangerate( $myconfig, $form->{currency},
  351. $form->{"datepaid_$i"}, $buysell );
  352. $form->{"exchangerate_$i"} =
  353. ($exchangerate)
  354. ? $exchangerate
  355. : $form->parse_amount( $myconfig,
  356. $form->{"exchangerate_$i"} );
  357. }
  358. # if there is no amount
  359. if ( $fxinvamount == 0 ) {
  360. $form->{exchangerate} = $form->{"exchangerate_$i"};
  361. }
  362. # ar/ap amount
  363. if ($arap) {
  364. ($accno) = split /--/, $form->{$ARAP};
  365. # add ar/ap
  366. $query = qq|
  367. INSERT INTO acc_trans
  368. (trans_id, chart_id,
  369. amount,transdate)
  370. VALUES (?, (SELECT id FROM chart
  371. WHERE accno = ?),
  372. ?, ?)|;
  373. @queryargs = (
  374. $form->{id}, $accno,
  375. $paid{amount}{$i} * $ml,
  376. $form->{"datepaid_$i"}
  377. );
  378. $dbh->prepare($query)->execute(@queryargs)
  379. || $form->dberror($query);
  380. }
  381. $arap = $paid{amount}{$i};
  382. # add payment
  383. if ( $paid{fxamount}{$i} ) {
  384. ($accno) = split /--/, $form->{"${ARAP}_paid_$i"};
  385. my $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;
  386. $amount = $paid{fxamount}{$i};
  387. $query = qq|
  388. INSERT INTO acc_trans
  389. (trans_id, chart_id, amount,
  390. transdate, source, memo,
  391. cleared)
  392. VALUES (?, (SELECT id FROM chart
  393. WHERE accno = ?),
  394. ?, ?, ?, ?, ?)|;
  395. @queryargs = (
  396. $form->{id}, $accno,
  397. $amount * -1 * $ml, $form->{"datepaid_$i"},
  398. $form->{"source_$i"}, $form->{"memo_$i"},
  399. $cleared
  400. );
  401. $dbh->prepare($query)->execute(@queryargs)
  402. || $form->dberror($query);
  403. if ( $form->{currency} ne $form->{defaultcurrency} ) {
  404. # exchangerate gain/loss
  405. $amount = (
  406. $form->round_amount(
  407. $paid{fxamount}{$i} * $form->{exchangerate}, 2 ) -
  408. $form->round_amount(
  409. $paid{fxamount}{$i} * $form->{"exchangerate_$i"}, 2
  410. )
  411. ) * -1;
  412. if ($amount) {
  413. my $accno_id =
  414. ( ( $amount * $ml ) > 0 )
  415. ? $fxgain_accno_id
  416. : $fxloss_accno_id;
  417. $query = qq|
  418. INSERT INTO acc_trans
  419. (trans_id,
  420. chart_id,
  421. amount,
  422. transdate,
  423. fx_transaction,
  424. cleared)
  425. VALUES (?, ?,
  426. ?,
  427. ?, '1', ?)|;
  428. @queryargs = (
  429. $form->{id}, $accno_id,
  430. $amount * $ml,
  431. $form->{"datepaid_$i"}, $cleared
  432. );
  433. $sth = $dbh->prepare($query);
  434. $sth->execute(@queryargs)
  435. || $form->dberror($query);
  436. }
  437. # exchangerate difference
  438. $amount = $paid{amount}{$i} - $paid{fxamount}{$i} + $amount;
  439. $query = qq|
  440. INSERT INTO acc_trans
  441. (trans_id, chart_id,
  442. amount,
  443. transdate,
  444. fx_transaction,
  445. cleared, source)
  446. VALUES (?, (SELECT id