summaryrefslogtreecommitdiff
path: root/bin/pos.pl
blob: 35fea78a3829797db04a88fbf0b906e395a07bdf (plain)
  1. #=====================================================================
  2. # LedgerSMB Small Medium Business Accounting
  3. # http://www.ledgersmb.org/
  4. #
  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) 2003
  17. #
  18. # Author: DWS Systems Inc.
  19. # Web: http://www.sql-ledger.org
  20. #
  21. # Contributors: Steve Doerr <sdoerr907@everestkc.net>
  22. #
  23. #
  24. # This program is free software; you can redistribute it and/or modify
  25. # it under the terms of the GNU General Public License as published by
  26. # the Free Software Foundation; either version 2 of the License, or
  27. # (at your option) any later version.
  28. #
  29. # This program is distributed in the hope that it will be useful,
  30. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  32. # GNU General Public License for more details.
  33. # You should have received a copy of the GNU General Public License
  34. # along with this program; if not, write to the Free Software
  35. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  36. #=====================================================================
  37. #
  38. # POS
  39. #
  40. #=====================================================================
  41. use LedgerSMB::Tax;
  42. $form->{currency} = 'USD';
  43. 1;
  44. # end
  45. sub custom_send_to_pd{
  46. socket(SOCK, 2, 1, getprotobynumber($pos_config{'pd_proto'}));
  47. connect(SOCK, $pos_config{'pd_dest'});
  48. my $rn = $numrows - 1;
  49. my $ds_string = sprintf (
  50. '%s%s @ $%-7.2f%s%s%s',
  51. $pd_control{'new_line'},
  52. $form->{"qty_$rn"},
  53. $form->{"sellprice_$rn"},
  54. $pd_control{'new_line'},
  55. "Subtotal: \$".sprintf('%-7.2f', $form->{'invtotal'})
  56. );
  57. print SOCK $ds_string;
  58. close SOCK;
  59. }
  60. sub on_update{
  61. &custom_send_to_pd;
  62. &custom_check_alert;
  63. }
  64. sub open_drawer{
  65. require "pos.conf.pl";
  66. open (PRINTER, "|-", ${'LedgerSMB::Sysconfig::printer'}{Printer});
  67. print PRINTER $pos_config{'rp_cash_open'};
  68. close PRINTER;
  69. sleep 1;
  70. }
  71. sub check_alert {
  72. my $rc = $form->{'rowcount'};
  73. if ( !$form->{"partnumber_$rc"} ) {
  74. --$rc; # Ensures that alert shows up when item is selected from a list;
  75. }
  76. for ( 1 .. $rc ) {
  77. $form->{'check_id'} = ( $form->{'check_id'} || $form->{"check_id_$_"} );
  78. }
  79. }
  80. sub send_to_pd {
  81. socket( SOCK, 2, 1, getprotobynumber( $pos_config{'pd_proto'} ) );
  82. connect( SOCK, $pos_config{'pd_dest'} );
  83. my $rn = $numrows - 1;
  84. my $ds_string = sprintf(
  85. '%s%s @ $%-7.2f%s%s%s',
  86. $pd_control{'new_line'},
  87. $form->{"qty_$rn"},
  88. $form->{"sellprice_$rn"},
  89. $pd_control{'new_line'},
  90. "Subtotal: \$" . sprintf( '%-7.2f', $form->{'invtotal'} )
  91. );
  92. print SOCK $ds_string;
  93. close SOCK;
  94. }
  95. sub on_update {
  96. &send_to_pd;
  97. &check_alert;
  98. }
  99. sub open_till {
  100. &open_drawer;
  101. &update;
  102. }
  103. sub add {
  104. $form->{nextsub} = 'add';
  105. $form->{title} = $locale->text('Add POS Invoice');
  106. $form->{callback} =
  107. "$form->{script}?action=$form->{nextsub}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}";
  108. &invoice_links;
  109. $form->{type} = "pos_invoice";
  110. $form->{format} = "txt";
  111. $form->{media} = ( $myconfig{printer} ) ? $myconfig{printer} : "screen";
  112. $form->{rowcount} = 0;
  113. $form->{readonly} = ( $myconfig{acs} =~ /POS--Sale/ ) ? 1 : 0;
  114. $ENV{REMOTE_ADDR} =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/;
  115. $form->{till} = $4;
  116. $form->{partsgroup} = "";
  117. for ( @{ $form->{all_partsgroup} } ) {
  118. $form->{partsgroup} .= "$_->{partsgroup}--$_->{translation}\n";
  119. }
  120. $form->{dontdisplayend} = 1;
  121. &display_form;
  122. $form->{dontdisplayrows} = 1;
  123. $form->{dontdisplayend} = 0;
  124. &openinvoices;
  125. }
  126. sub openinvoices {
  127. undef %column_data;
  128. undef %column_heading;
  129. $form->{customer} = "";
  130. $form->{customer_id} = 0;
  131. delete $form->{l_subtotal};
  132. delete $form->{subtotal};
  133. $ENV{REMOTE_ADDR} =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/;
  134. $form->{till} = $4;
  135. $form->{sort} = 'transdate';
  136. for (qw(open l_invnumber l_transdate l_name l_amount l_curr l_till)) {
  137. $form->{$_} = 'Y';
  138. }
  139. if ( $myconfig{role} ne 'user' ) {
  140. $form->{l_employee} = 'Y';
  141. }
  142. $form->{title} = $locale->text('Open');
  143. &transactions;
  144. }
  145. sub edit {
  146. $form->{title} = $locale->text('Edit POS Invoice');
  147. $form->{callback} =
  148. "$form->{script}?action=$form->{nextsub}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}";
  149. &invoice_links;
  150. &prepare_invoice;
  151. $form->{type} = "pos_invoice";
  152. $form->{format} = "txt";
  153. $form->{media} = ( $myconfig{printer} ) ? $myconfig{printer} : "screen";
  154. $form->{readonly} = ( $myconfig{acs} =~ /POS--Sale/ ) ? 1 : 0;
  155. $form->{partsgroup} = "";
  156. for ( @{ $form->{all_partsgroup} } ) {
  157. $form->{partsgroup} .= "$_->{partsgroup}--$_->{translation}\n";
  158. }
  159. &display_form;
  160. }
  161. sub form_header {
  162. if ( !$form->{'check_id'} ) {
  163. &check_alert;
  164. }
  165. # set option selected
  166. for (qw(AR currency)) {
  167. $form->{"select$_"} =~ s/ selected//;
  168. $form->{"select$_"} =~
  169. s/option>\Q$form->{$_}\E/option selected>$form->{$_}/;
  170. }
  171. for (qw(customer department employee)) {
  172. $form->{"select$_"} = $form->unescape( $form->{"select$_"} );
  173. $form->{"select$_"} =~ s/ selected//;
  174. $form->{"select$_"} =~ s/(<option value="\Q$form->{$_}\E")/$1 selected/;
  175. }
  176. $form->{exchangerate} =
  177. $form->format_amount( \%myconfig, $form->{exchangerate} );
  178. $exchangerate = qq|<tr>|;
  179. $exchangerate .= qq|
  180. <th align="right" nowrap>| . $locale->text('Currency') . qq|</th>
  181. <td><select name="currency">$form->{selectcurrency}</select></td> |
  182. if $form->{defaultcurrency};
  183. $exchangerate .= qq|
  184. <input type="hidden" name="selectcurrency" value="$form->{selectcurrency}">
  185. <input type="hidden" name="defaultcurrency" value="$form->{defaultcurrency}">
  186. |;
  187. if ( $form->{defaultcurrency}
  188. && $form->{currency} ne $form->{defaultcurrency} )
  189. {
  190. if ( $form->{forex} ) {
  191. $exchangerate .=
  192. qq|<th align="right">|
  193. . $locale->text('Exchange Rate')
  194. . qq|</th><td>$form->{exchangerate}<input type="hidden" name="exchangerate" value="$form->{exchangerate}"></td>|;
  195. }
  196. else {
  197. $exchangerate .=
  198. qq|<th align="right">|
  199. . $locale->text('Exchange Rate')
  200. . qq|</th><td><input name="exchangerate" size="10" value="$form->{exchangerate}"></td>|;
  201. }
  202. }
  203. $exchangerate .= qq|
  204. <input type="hidden" name="forex" value="$form->{forex}">
  205. </tr>
  206. |;
  207. if ( $form->{selectcustomer} ) {
  208. $customer = qq|<select name="customer">$form->{selectcustomer}</select>
  209. <input type="hidden" name="selectcustomer" value="|
  210. . $form->escape( $form->{selectcustomer}, 1 ) . qq|">|;
  211. }
  212. else {
  213. $customer = qq|<input name="customer" value="$form->{customer}" size="35">|;
  214. }
  215. $department = qq|
  216. <tr>
  217. <th align="right" nowrap>| . $locale->text('Department') . qq|</th>
  218. <td colspan="3"><select name="department">$form->{selectdepartment}</select>
  219. <input type="hidden" name="selectdepartment" value="|
  220. . $form->escape( $form->{selectdepartment}, 1 ) . qq|">
  221. </td>
  222. </tr>
  223. | if $form->{selectdepartment};
  224. if ( $form->{change} != $form->{oldchange} ) {
  225. $form->{creditremaining} -= $form->{oldchange};
  226. }
  227. $n = ( $form->{creditremaining} < 0 ) ? "0" : "1";
  228. if ( $form->{business} ) {
  229. $business = qq|
  230. <tr>
  231. <th align="right" nowrap>| . $locale->text('Business') . qq|</th>
  232. <td>$form->{business}</td>
  233. <td width="10"></td>
  234. <th align="right" nowrap>| . $locale->text('Trade Discount') . qq|</th>
  235. <td>|
  236. . $form->format_amount( \%myconfig, $form->{tradediscount} * 100 )
  237. . qq| %</td>
  238. </tr>
  239. |;
  240. }
  241. if ( $form->{selectlanguage} ) {
  242. if ( $form->{language_code} ne $form->{oldlanguage_code} ) {
  243. # rebuild partsgroup
  244. $form->get_partsgroup(\%myconfig, { all => 1});
  245. $form->{partsgroup} = "";
  246. for ( @{ $form->{all_partsgroup} } ) {
  247. $form->{partsgroup} .= "$_->{partsgroup}--$_->{translation}\n";
  248. }
  249. $form->{oldlanguage_code} = $form->{language_code};
  250. }
  251. $form->{"selectlanguage"} =
  252. $form->unescape( $form->{"selectlanguage"} );
  253. $form->{"selectlanguage"} =~ s/ selected//;
  254. $form->{"selectlanguage"} =~
  255. s/(<option value="\Q$form->{language_code}\E")/$1 selected/;
  256. $lang = qq|
  257. <tr>
  258. <th align="right">| . $locale->text('Language') . qq|</th>
  259. <td colspan="3"><select name="language_code">$form->{selectlanguage}</select></td>
  260. </tr>
  261. <input type="hidden" name="oldlanguage_code" value="$form->{oldlanguage_code}">
  262. <input type="hidden" name="selectlanguage" value="|
  263. . $form->escape( $form->{selectlanguage}, 1 ) . qq|">|;
  264. }
  265. $i = $form->{rowcount} + 1;
  266. $focus = "partnumber_$i";
  267. $form->header();
  268. print qq|
  269. <body onLoad="document.forms[0].${focus}.focus()">
  270. <form method="post" action="$form->{script}">
  271. |;
  272. $form->hide_form(
  273. qw(id till type format printed title discount creditlimit creditremaining tradediscount business closedto locked oldtransdate customer_id oldcustomer check_id)
  274. );
  275. print qq|
  276. <input type="hidden" name="vc" value="customer">
  277. <table width="100%">
  278. <tr class="listtop">
  279. <th class="listtop">$form->{title}</font></th>
  280. </tr>|;
  281. if ( $form->{'check_id'} ) {
  282. print qq|
  283. <tr class="listtop">
  284. <th class="listtop" style="background-color: red">|
  285. . $locale->text('Check ID') . qq|
  286. </th>
  287. </tr>|;
  288. }
  289. print qq|
  290. <tr height="5"></tr>
  291. <tr>
  292. <td>
  293. <table width="100%">
  294. <tr valign="top">
  295. <td>
  296. <table>
  297. <tr>
  298. <th align="right" nowrap>| . $locale->text('Customer') . qq|</th>
  299. <td colspan="3">$customer</td>
  300. </tr>
  301. <tr>
  302. <td></td>
  303. <td colspan="3">
  304. <table>
  305. <!-- tr>
  306. <th align="right" nowrap>| . $locale->text('Credit Limit') . qq|</th>
  307. <td>$form->{creditlimit}</td>
  308. <td width="10"></td>
  309. <th align="right" nowrap>| . $locale->text('Remaining') . qq|</th>
  310. <td class="plus$n">|
  311. . $form->format_amount( \%myconfig, $form->{creditremaining}, 0, "0" )
  312. . qq|</font></td>
  313. </tr -->
  314. $business
  315. </table>
  316. </td>
  317. </tr>
  318. <tr>
  319. <th align=right nowrap>| . $locale->text('Record in') . qq|</th>
  320. <td colspan="3"><select name="AR">$form->{selectAR}</select></td>
  321. <input type="hidden" name="selectAR" value="$form->{selectAR}">
  322. </tr>
  323. $department
  324. </table>
  325. </td>
  326. <td>
  327. <table>
  328. $employee
  329. $exchangerate
  330. $lang
  331. </table>
  332. </td>
  333. </tr>
  334. </table>
  335. </td>
  336. </tr>
  337. <tr>
  338. <td>
  339. </td>
  340. </tr>
  341. |;
  342. $form->hide_form(
  343. qw(taxaccounts duedate invnumber transdate selectcurrency defaultcurrency)
  344. );
  345. for ( split / /, $form->{taxaccounts} ) {
  346. $form->hide_form( "${_}_rate", "${_}_description", "${_}_taxnumber" );
  347. }
  348. }
  349. sub form_footer {
  350. _calc_taxes();
  351. $form->{invtotal} = $form->{invsubtotal};
  352. $form->{taxincluded} = ( $form->{taxincluded} ) ? "checked" : "";
  353. $taxincluded = "";
  354. if ( $form->{taxaccounts} ) {
  355. $taxincluded = qq|
  356. <tr height="5"></tr>
  357. <tr>
  358. <td align="right">
  359. <input name="taxincluded" class="checkbox" type="checkbox" value="1" $form->{taxincluded}></td><th align="left">|
  360. . $locale->text('Tax Included')
  361. . qq|</th>
  362. </tr>
  363. |;
  364. }
  365. if ( !$form->{taxincluded} ) {
  366. foreach $item (keys %{$form->{taxes}}) {
  367. my $taccno = $item;
  368. $form->{invtotal} += $form->round_amount($form->{taxes}{$item}, 2);
  369. $form->{"${taccno}_total"} =
  370. $form->format_amount( \%myconfig,
  371. $form->round_amount( $form->{taxes}{$item}, 2 ), 2 );
  372. $tax .= qq|
  373. <tr>
  374. <th align="right">$form->{"${item}_description"}</th>
  375. <td align="right">$form->{"${item}_total"}</td>
  376. </tr>|;
  377. }
  378. $form->{invsubtotal} =
  379. $form->format_amount( \%myconfig, $form->{invsubtotal}, 2, 0 );
  380. $subtotal = qq|
  381. <tr>
  382. <th align="right">| . $locale->text('Subtotal') . qq|</th>
  383. <td align="right">$form->{invsubtotal}</td>
  384. </tr>
  385. |;
  386. }
  387. on_update() if ($form->{action} eq 'update');
  388. @column_index = qw(paid memo source cctrack AR_paid);
  389. $column_data{paid} = "<th>" . $locale->text('Amount') . "</th>";
  390. $column_data{source} = "<th>" . $locale->text('Source') . "</th>";
  391. $column_data{memo} = "<th>" . $locale->text('Memo') . "</th>";
  392. $column_data{cctrack} =
  393. "<th>" . $locale->text('Credit Card Track') . "</th>";
  394. $column_data{AR_paid} = "<th>&nbsp;</th>";
  395. print qq|
  396. <tr>
  397. <td>
  398. <table width="100%">
  399. <tr valign="top">
  400. <td>
  401. <table>
  402. <tr>
  403. |;
  404. for (@column_index) { print "$column_data{$_}\n"; }
  405. print qq|
  406. </tr>
  407. |;
  408. $totalpaid = 0;
  409. $form->{paidaccounts}++ if ( $form->{"paid_$form->{paidaccounts}"} );
  410. my $memoselect = qq|<SELECT name="MEMONAME">|;
  411. for ( sort keys %pos_sources ) {
  412. $memoselect .= qq|<option value="$_">$pos_sources{$_}</option>|;
  413. }
  414. $memoselect .= qq|</SELECT>|;
  415. for $i ( 1 .. $form->{paidaccounts} ) {
  416. $form->{"selectAR_paid_$i"} = $form->{selectAR_paid};
  417. $form->{"selectAR_paid_$i"} =~
  418. s/option>\Q$form->{"AR_paid_$i"}\E/option selected>$form->{"AR_paid_$i"}/;
  419. # format amounts
  420. $totalpaid += $form->{"paid_$i"};
  421. $form->{"paid_$i"} =
  422. $form->format_amount( \%myconfig, $form->{"paid_$i"}, 2 );
  423. $form->{"exchangerate_$i"} =
  424. $form->format_amount( \%myconfig, $form->{"exchangerate_$i"} );
  425. if ( $form->{"paid_$i"} ) {
  426. $column_data{paid} =
  427. qq|<td><input name="paid_$i" size="11" value="$form->{"paid_$i"}"></td>|;
  428. }
  429. else {
  430. $column_data{paid} =
  431. qq|<td><input accesskey='n' name="paid_$i" size="11" value="$form->{"paid_$i"}"></td>|;
  432. }
  433. $column_data{source} =
  434. qq|<td><input name="source_$i" size="10" value="$form->{"source_$i"}"></td>|;
  435. $column_data{memo} = qq|<td>$memoselect</td>|;
  436. $column_data{memo} =~ s/MEMONAME/memo_$i/;
  437. if ( !$form->{"memo_$i"} ) {
  438. $form->{"memo_$i"} = $pos_source_default;
  439. }
  440. my $memval = $form->{"memo_$i"};
  441. $column_data{memo} =~ s/(option value="$memval")/$1 SELECTED/;
  442. $column_data{cctrack} = qq|<td><input type="text" name="cctrack_$i"
  443. value="| . $form->{"cctrack_$i"} . qq|" size="3"></td>|;
  444. if ( $pos_config{till_accno} ) {
  445. if ( !$form->{"AR_paid_$i"} ) {
  446. $form->{"AR_paid_$i"} = $pos_config{till_accno};
  447. }
  448. $column_data{AR_paid} = qq|<input type="hidden" name="AR_paid_$i"
  449. value='$form->{"AR_paid_$i"}'>|;
  450. }
  451. else {
  452. $column_data{AR_paid} =
  453. qq|<td><select name="AR_paid_$i">$form->{"selectAR_paid_$i"}</select></td>|;
  454. }
  455. print qq|
  456. <tr>
  457. |;
  458. for (@column_index) { print "$column_data{$_}\n"; }
  459. print qq|
  460. </tr>
  461. |;
  462. $form->hide_form( "cleared_$i", "exchangerate_$i", "forex_$i" );
  463. }
  464. $form->{change} = 0;
  465. if ( $totalpaid > $form->{invtotal} ) {
  466. $form->{change} = $totalpaid - $form->{invtotal};
  467. }
  468. $form->{oldchange} = $form->{change};
  469. $form->{change} = $form->format_amount( \%myconfig, $form->{change}, 2, 0 );
  470. $form->{totalpaid} = $form->format_amount( \%myconfig, $totalpaid, 2 );
  471. $form->{oldinvtotal} = $form->{invtotal};
  472. $form->{invtotal} =
  473. $form->format_amount( \%myconfig, $form->{invtotal}, 2, 0 );
  474. print qq|
  475. <tr>
  476. <th align="right">| . $locale->text('Change') . qq|</th>
  477. <th>$form->{change}</th>
  478. </tr>
  479. </table>
  480. </td>
  481. <td align="right">
  482. <table>
  483. $subtotal
  484. $tax
  485. <tr>
  486. <th align="right">| . $locale->text('Total') . qq|</th>
  487. <td align="right">$form->{invtotal}</td>
  488. </tr>
  489. $taxincluded
  490. </table>
  491. </td>
  492. </tr>
  493. </table>
  494. </td>
  495. </tr>
  496. <input type="hidden" name="oldtotalpaid" value="$totalpaid">
  497. <input type="hidden" name="datepaid" value="$form->{transdate}">
  498. <tr>
  499. <td>
  500. |;
  501. $form->hide_form(
  502. qw(paidaccounts selectAR_paid oldinvtotal change oldchange invtotal));
  503. &print_options;
  504. print qq|
  505. </td>
  506. </tr>
  507. <tr>
  508. <td><hr size="3" noshade></td>
  509. </tr>
  510. </table>
  511. |;
  512. $transdate = $form->datetonum( \%myconfig, $form->{transdate} );
  513. $closedto = $form->datetonum( \%myconfig, $form->{closedto} );
  514. # type=submit $locale->text('Update')
  515. # type=submit $locale->text('Print')
  516. # type=submit $locale->text('Post')
  517. # type=submit $locale->text('Print and Post')
  518. # type=submit $locale->text('Delete')
  519. if ( !$form->{readonly} ) {
  520. %button = (
  521. 'update' =>
  522. { ndx => 1, key => 'U', value => $locale->text('Update') },
  523. 'open_till' => { ndx => 3, key => 'O', value => $locale->text('Open Till') },
  524. 'print_and_post' => {
  525. ndx => 4,
  526. key => 'P',
  527. value => $locale->text('Print and Post')
  528. },
  529. 'delete' =>
  530. { ndx => 5, key => 'D', value => $locale->text('Delete') },
  531. );
  532. if ( $transdate > $closedto ) {
  533. if ( !$form->{id} ) {
  534. delete $button{'delete'};
  535. }
  536. delete $button{'print_and_post'}
  537. unless ${LedgerSMB::Sysconfig::latex};
  538. }
  539. else {
  540. for ( 'print', 'post', 'print_and_post', 'delete' ) {
  541. delete $button{$_};
  542. }
  543. }
  544. for ( sort { $button{$a}->{ndx} <=> $button{$b}->{ndx} } keys %button )
  545. {
  546. $form->print_button( \%button, $_ );
  547. }
  548. if ( $form->{partsgroup} ) {
  549. $form->{partsgroup} =~ s/\r//g;
  550. $form->{partsgroup} = $form->quote( $form->{partsgroup} );
  551. $spc = ( $form->{path} =~ /lynx/ ) ? "." : " ";
  552. print qq|
  553. <input type="hidden" name="nextsub" value="lookup_partsgroup">
  554. <input type="hidden" name="partsgroup" value="$form->{partsgroup}">|;
  555. foreach $item ( split /\n/, $form->{partsgroup} ) {
  556. ( $partsgroup, $translation ) = split /--/, $item;
  557. $item = ($translation) ? $translation : $partsgroup;
  558. print
  559. qq| <button class="submit" type="submit" name="action" value="$spc$item">$spc$item</button>\n|
  560. if $item;
  561. }
  562. }
  563. }
  564. if ( $form->{lynx} ) {
  565. require "bin/menu.pl";
  566. &menubar;
  567. }
  568. $form->hide_form(qw(rowcount callback path login sessionid));
  569. print qq|</form>|;
  570. if ( !$form->{dontdisplayend} ) {
  571. print qq|
  572. </body>
  573. </html>
  574. |;
  575. }
  576. }
  577. sub post {
  578. $form->isblank( "customer", $locale->text('Customer missing!') );
  579. # if oldcustomer ne customer redo form
  580. $customer = $form->{customer};
  581. $customer =~ s/--.*//g;
  582. $customer .= "--$form->{customer_id}";
  583. if ( $customer ne $form->{oldcustomer} ) {
  584. &update;
  585. exit;
  586. }
  587. &validate_items;
  588. $form->isblank( "exchangerate", $locale->text('Exchange rate missing!') )
  589. if ( $form->{currency} ne $form->{defaultcurrency} );
  590. $paid = 0;
  591. for ( 1 .. $form->{paidaccounts} ) {
  592. $paid += $form->parse_amount( \%myconfig, $form->{"paid_$_"} );
  593. }
  594. delete $form->{datepaid} unless $paid;
  595. $total = $form->parse_amount( \%myconfig, $form->{invtotal} );
  596. # deduct change from first payment
  597. #$form->{"paid_1"} = $form->{invtotal} if $paid > $total;
  598. $form->{paid} = $paid;
  599. if ( $paid > $total ) {
  600. ++$form->{paidaccounts};
  601. my $pa = $form->{paidaccounts};
  602. $form->{"paid_$pa"} = $total - $paid;
  603. $form->{"memo_$pa"} = 'cash';
  604. $form->{"exchangerate_$pa"} = 0;
  605. $form->{"AR_paid_$pa"} = $form->{AR_paid_1};
  606. }
  607. ( $form->{AR} ) = split /--/, $form->{AR};
  608. if ( IS->post_invoice( \%myconfig, \%$form ) ) {
  609. $form->redirect( $locale->text('Posted!') );
  610. }
  611. else {
  612. $form->error( $locale->text('Cannot post transaction!') );
  613. }
  614. }
  615. sub display_row {
  616. my $numrows = shift;
  617. @column_index =
  618. qw(partnumber description partsgroup qty unit sellprice discount linetotal);
  619. $form->{invsubtotal} = 0;
  620. for ( split / /, $form->{taxaccounts} ) { $form->{"${_}_base"} = 0; }
  621. $column_data{partnumber} =
  622. qq|<th class="listheading" nowrap>| . $locale->text('Number') . qq|</th>|;
  623. $column_data{description} =
  624. qq|<th class="listheading" nowrap>|
  625. . $locale->text('Description')
  626. . qq|</th>|;
  627. $column_data{qty} =
  628. qq|<th class="listheading" nowrap>| . $locale->text('Qty') . qq|</th>|;
  629. $column_data{unit} =
  630. qq|<th class="listheading" nowrap>| . $locale->text('Unit') . qq|</th>|;
  631. $column_data{sellprice} =
  632. qq|<th class="listheading" nowrap>| . $locale->text('Price') . qq|</th>|;
  633. $column_data{linetotal} =
  634. qq|<th class="listheading" nowrap>| . $locale->text('Extended') . qq|</th>|;
  635. $column_data{discount} = qq|<th class="listheading" nowrap>%</th>|;
  636. print qq|
  637. <tr>
  638. <td>
  639. <table width="100%">
  640. <tr class="listheading">|;
  641. for (@column_index) { print "\n$column_data{$_}"; }
  642. print qq|
  643. </tr>
  644. |;
  645. $exchangerate = $form->parse_amount( \%myconfig, $form->{exchangerate} );
  646. $exchangerate = ($exchangerate) ? $exchangerate : 1;
  647. for $i ( 1 .. $numrows ) {
  648. # undo formatting
  649. for (qw(qty discount sellprice)) {
  650. $form->{"${_}_$i"} =
  651. $form->parse_amount( \%myconfig, $form->{"${_}_$i"} );
  652. }
  653. ($dec) = ( $form->{"sellprice_$i"} =~ /\.(\d+)/ );
  654. $dec = length $dec;
  655. $decimalplaces = ( $dec > 2 ) ? $dec : 2;
  656. if ( ( $form->{"qty_$i"} != $form->{"oldqty_$i"} )
  657. || ( $form->{currency} ne $form->{oldcurrency} ) )
  658. {
  659. # check for a pricematrix
  660. @a = split / /, $form->{"pricematrix_$i"};
  661. if ( scalar @a ) {
  662. foreach $item (@a) {
  663. ( $q, $p ) = split /:/, $item;
  664. if ( ( $p * 1 ) && ( $form->{"qty_$i"} >= ( $q * 1 ) ) ) {
  665. ($dec) = ( $p =~ /\.(\d+)/ );
  666. $dec = length $dec;
  667. $decimalplaces = ( $dec > 2 ) ? $dec : 2;
  668. $form->{"sellprice_$i"} =
  669. $form->round_amount( $p / $exchangerate,
  670. $decimalplaces );
  671. }
  672. }
  673. }
  674. }
  675. if ( $i < $numrows ) {
  676. $column_data{discount} =
  677. qq|<td align="right"><input name="discount_$i" size="3" value="|
  678. . $form->format_amount( \%myconfig, $form->{"discount_$i"} )
  679. . qq|"></td>|;
  680. }
  681. else {
  682. $column_data{discount} = qq|<td></td>|;
  683. }
  684. $discount =
  685. $form->round_amount(
  686. $form->{"sellprice_$i"} * $form->{"discount_$i"} / 100,
  687. $decimalplaces );
  688. $linetotal = $form->round_amount( $form->{"sellprice_$i"} - $discount,
  689. $decimalplaces );
  690. $linetotal = $form->round_amount( $linetotal * $form->{"qty_$i"}, 2 );
  691. for (qw(partnumber sku description partsgroup unit)) {
  692. $form->{"${_}_$i"} = $form->quote( $form->{"${_}_$i"} );
  693. }
  694. $column_data{partnumber} =
  695. qq|<td><input name="partnumber_$i" size=20 value="$form->{"partnumber_$i"}" accesskey="$i" title="[Alt-$i]"></td>|;
  696. if (
  697. ( $rows = $form->numtextrows( $form->{"description_$i"}, 40, 6 ) ) >
  698. 1 )
  699. {
  700. $column_data{description} =
  701. qq|<td><textarea name="description_$i" rows=$rows cols=46 wrap=soft>$form->{"description_$i"}</textarea></td>|;
  702. }
  703. else {
  704. $column_data{description} =
  705. qq|<td><input name="description_$i" size=48 value="$form->{"description_$i"}"></td>|;
  706. }
  707. $column_data{qty} =
  708. qq|<td align="right"><input name="qty_$i" size="5" value="|
  709. . $form->format_amount( \%myconfig, $form->{"qty_$i"} )
  710. . qq|"></td>|;
  711. $column_data{unit} = qq|<td>$form->{"unit_$i"}</td>|;
  712. $column_data{sellprice} =
  713. qq|<td align="right"><input name="sellprice_$i" size="9" value="|
  714. . $form->format_amount( \%myconfig, $form->{"sellprice_$i"},
  715. $decimalplaces )
  716. . qq|"></td>|;
  717. $column_data{linetotal} =
  718. qq|<td align="right">|
  719. . $form->format_amount( \%myconfig, $linetotal, 2 )
  720. . qq|</td>|;
  721. print qq|
  722. <tr valign="top">|;
  723. for (@column_index) { print "\n$column_data{$_}"; }
  724. print qq|
  725. </tr>
  726. |;
  727. $form->{"oldqty_$i"} = $form->{"qty_$i"};
  728. for (
  729. qw(id listprice lastcost taxaccounts pricematrix oldqty sku partsgroup unit inventory_accno_id income_accno_id expense_accno_id)
  730. )
  731. {
  732. $form->hide_form("${_}_$i");
  733. }
  734. for ( split / /, $form->{"taxaccounts_$i"} ) {
  735. $form->{"${_}_base"} += $linetotal;
  736. }
  737. $form->{invsubtotal} += $linetotal;
  738. }
  739. print qq|
  740. </table>
  741. </td>
  742. </tr>
  743. <input type="hidden" name="oldcurrency" value="$form->{currency}">
  744. |;
  745. }
  746. sub print {
  747. open_drawer();
  748. sleep 1;
  749. if ( !$form->{invnumber} ) {
  750. $form->{invnumber} = $form->update_defaults( \%myconfig, 'sinumber' );
  751. }
  752. $rc = $form->{'rowcount'};
  753. $pc = $form->{'paidaccounts'};
  754. if ( $form->{"partnumber_$rc"}
  755. || $form->{"description_$rc"}
  756. || $form->{"paid_$pc"} )
  757. {
  758. &update;
  759. exit;
  760. }
  761. for $i ( 1 .. $rc - 1 ) {
  762. if ( $form->{"qty_$i"} != $form->{"oldqty_$i"} ) {
  763. &update;
  764. exit;
  765. }
  766. }
  767. if ( !$form->{invnumber} ) {
  768. $form->{invnumber} = $form->update_defaults( \%myconfig, "sinumber" );
  769. if ( $form->{media} eq 'screen' ) {
  770. &update;
  771. exit;
  772. }
  773. }
  774. $old_form = new Form;
  775. for ( keys %$form ) { $old_form->{$_} = $form->{$_}; }
  776. for (qw(employee department)) { $form->{$_} =~ s/--.*//g; }
  777. $form->{invdate} = $form->{transdate};
  778. my @lt = localtime();
  779. $form->{dateprinted} = $lt[2] . ":" . $lt[1] . ":" . $lt[0];
  780. &print_form($old_form);
  781. }
  782. sub print_form {
  783. my $old_form = shift;
  784. &open_drawer;
  785. # if oldcustomer ne customer redo form
  786. $customer = $form->{customer};
  787. $customer =~ s/--.*//g;
  788. $customer .= "--$form->{customer_id}";
  789. if ( $customer ne $form->{oldcustomer} ) {
  790. &update;
  791. exit;
  792. }
  793. &validate_items;
  794. &{"$form->{vc}_details"};
  795. @a = ();
  796. for ( 1 .. $form->{rowcount} ) {
  797. push @a, ( "partnumber_$_", "description_$_" );
  798. }
  799. for ( split / /, $form->{taxaccounts} ) { push @a, "${_}_description"; }
  800. $form->format_string(@a);
  801. # format payment dates
  802. for ( 1 .. $form->{paidaccounts} ) {
  803. $form->{"datepaid_$_"} =
  804. $locale->date( \%myconfig, $form->{"datepaid_$_"} );
  805. }
  806. IS->invoice_details( \%myconfig, \%$form );
  807. if ( $form->parse_amount( \%myconfig, $form->{total} ) <= 0 ) {
  808. $form->{total} = 0;
  809. }
  810. else {
  811. $form->{change} = 0;
  812. }
  813. for (qw(company address tel fax businessnumber)) {
  814. $form->{$_} = $myconfig{$_};
  815. }
  816. $form->{username} = $myconfig{name};
  817. $form->{address} =~ s/\\n/\n/g;
  818. push @a, qw(company address tel fax businessnumber username);
  819. $form->format_string(@a);
  820. $form->{templates} = "$myconfig{templates}";
  821. $form->{IN} = "$form->{type}.$form->{format}";
  822. if ( $form->{format} =~ /(postscript|pdf)/ ) {
  823. $form->{IN} =~ s/$&$/tex/;
  824. }
  825. if ( $form->{media} ne 'screen' ) {
  826. $form->{OUT} = ${LedgerSMB::Sysconfig::printer}{ $form->{media} };
  827. $form->{printmode} = '|-';
  828. }
  829. $form->{discount} =
  830. $form->format_amount( \%myconfig, $form->{discount} * 100 );
  831. $form->{rowcount}--;
  832. $form->{pre} = "<body bgcolor=#ffffff>\n<pre>";
  833. delete $form->{stylesheet};
  834. $form->{cd_open} = $pos_config{rp_cash_drawer_open};
  835. $form->parse_template( \%myconfig, ${LedgerSMB::Sysconfig::userspath} );
  836. if ( $form->{printed} !~ /$form->{formname}/ ) {
  837. $form->{printed} .= " $form->{formname}";
  838. $form->{printed} =~ s/^ //;
  839. $form->update_status( \%myconfig );
  840. }
  841. $old_form->{printed} = $form->{printed};
  842. # if we got back here restore the previous form
  843. if ( $form->{media} ne 'screen' ) {
  844. # restore and display form
  845. for ( keys %$old_form ) { $form->{$_} = $old_form->{$_}; }
  846. $form->{exchangerate} =
  847. $form->parse_amount( \%myconfig, $form->{exchangerate} );
  848. for $i ( 1 .. $form->{paidaccounts} ) {
  849. for (qw(paid exchangerate)) {
  850. $form->{"${_}_$i"} =
  851. $form->parse_amount( \%myconfig, $form->{"${_}_$i"} );
  852. }
  853. }
  854. delete $form->{pre};
  855. if ( !$form->{printandpost} ) {
  856. $form->{rowcount}--;
  857. #&display_form;
  858. }
  859. }
  860. }
  861. sub print_and_post {
  862. $form->{media} = 'Printer';
  863. $form->error( $locale->text('Select a Printer!') )
  864. if ( $form->{media} eq 'screen' );
  865. $form->{printandpost} = 1;
  866. &print;
  867. &post;
  868. }
  869. sub lookup_partsgroup {
  870. $form->{my_partsgroup} =~ s/\r//;
  871. $form->{action} = $form->{my_partsgroup};
  872. if ( $form->{language_code} ) {
  873. # get english
  874. foreach $item ( split /\n/, $form->{partsgroup} ) {
  875. if ( $item =~ /$form->{action}/ ) {
  876. ( $partsgroup, $translation ) = split /--/, $item;
  877. $form->{action} = $partsgroup;
  878. last;
  879. }
  880. }
  881. }
  882. $form->{"partsgroup_$form->{rowcount}"} = $form->{action};
  883. &update;
  884. }
  885. sub print_options {
  886. $form->{PD}{ $form->{type} } = "checked";
  887. print qq|
  888. <input type="hidden" name="format" value="$form->{format}">
  889. <input type="hidden" name="formname" value="$form->{type}">
  890. <table width="100%">
  891. <tr>
  892. |;
  893. $media = qq|
  894. <td><input class="radio" type="radio" name="media" value="screen"></td>
  895. <td>| . $locale->text('Screen') . qq|</td>|;
  896. if ( %{LedgerSMB::Sysconfig::printer} ) {
  897. for ( keys %{LedgerSMB::Sysconfig::printer} ) {
  898. $media .= qq|
  899. <td><input class="radio" type="radio" name="media" value="$_"></td>
  900. <td nowrap>$_</td>
  901. |;
  902. }
  903. }
  904. $media =~ s/(value="\Q$form->{media}\E")/$1 checked/;
  905. print qq|
  906. $media
  907. <td width="99%">&nbsp;</td>|;
  908. if ( $form->{printed} =~ /$form->{type}/ ) {
  909. print qq|
  910. <th>\|| . $locale->text('Printed') . qq|\|</th>|;
  911. }
  912. print qq|
  913. </tr>
  914. </table>
  915. |;
  916. }
  917. sub receipts {
  918. $form->{title} = $locale->text('Receipts');
  919. $form->{db} = 'ar';
  920. RP->paymentaccounts( \%myconfig, \%$form );
  921. $paymentaccounts = "";
  922. for ( @{ $form->{PR} } ) { $paymentaccounts .= "$_->{accno} "; }
  923. if ( @{ $form->{all_years} } ) {
  924. # accounting years
  925. $form->{selectaccountingyear} = "<option>\n";
  926. for ( @{ $form->{all_years} } ) {
  927. $form->{selectaccountingyear} .= qq|<option>$_\n|;
  928. }
  929. $form->{selectaccountingmonth} = "<option>\n";
  930. for ( sort keys %{ $form->{all_month} } ) {
  931. $form->{selectaccountingmonth} .=
  932. qq|<option value=$_>|
  933. . $locale->text( $form->{all_month}{$_} ) . qq|\n|;
  934. }
  935. $selectfrom = qq|
  936. <tr>
  937. <th align="right">| . $locale->text('Period') . qq|</th>
  938. <td colspan="3">
  939. <select name="month">$form->{selectaccountingmonth}</select>
  940. <select name="year">$form->{selectaccountingyear}</select>
  941. <input name="interval" class="radio" type="radio" value="0" checked>&nbsp;|
  942. . $locale->text('Current') . qq|
  943. <input name="interval" class="radio" type="radio" value="1">&nbsp;|
  944. . $locale->text('Month') . qq|
  945. <input name="interval" class="radio" type="radio" value="3">&nbsp;|
  946. . $locale->text('Quarter') . qq|
  947. <input name="interval" class="radio" type="radio" value="12">&nbsp;|
  948. . $locale->text('Year') . qq|
  949. </td>
  950. </tr>
  951. |;
  952. }
  953. $form->header;
  954. print qq|
  955. <body>
  956. <form method="post" action="$form->{script}">
  957. <input type="hidden" name="title value="$form->{title}">
  958. <input type="hidden" name="paymentaccounts" value="$paymentaccounts">
  959. <input type="hidden" name="till" value="1">
  960. <input type="hidden" name="subtotal" value="1">
  961. <table width="100%">
  962. <tr>
  963. <th class="listtop">$form->{title}</th>
  964. </tr>
  965. <tr height="5"></tr>
  966. <tr>
  967. <td>
  968. <table>
  969. <input type="hidden" name="nextsub" value="list_payments">
  970. <tr>
  971. <th align="right">| . $locale->text('From') . qq|</th>
  972. <td><input name="fromdate" size="11" title="$myconfig{dateformat}" value="$form->{fromdate}"></td>
  973. <th align="right">| . $locale->text('To') . qq|</th>
  974. <td><input name="todate" size="11" title="$myconfig{dateformat}"></td>
  975. </tr>
  976. $selectfrom
  977. <input type="hidden" name="sort" value="transdate">
  978. <input type="hidden" name="db" value="$form->{db}">
  979. </table>
  980. </td>
  981. </tr>
  982. <tr>
  983. <td><hr size="3" noshade></td>
  984. </tr>
  985. </table>
  986. <br>
  987. <input type="hidden" name="path" value="$form->{path}">
  988. <input type="hidden" name="login" value="$form->{login}">
  989. <input type="hidden" name="sessionid" value="$form->{sessionid}">
  990. <button type="submit" class="submit" name="action" value="continue">|
  991. . $locale->text('Continue')
  992. . qq|</button>
  993. |;
  994. if ( $form->{lynx} ) {
  995. require "bin/menu.pl";
  996. &menubar;
  997. }
  998. print qq|
  999. </form>
  1000. </body>
  1001. </html>
  1002. |;
  1003. }