summaryrefslogtreecommitdiff
path: root/bin/jc.pl
blob: 1815388542af8209c721fdca6b63b09f833bf0cd (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) 2005
  17. #
  18. # Author: DWS Systems Inc.
  19. # Web: http://www.sql-ledger.org
  20. #
  21. #
  22. #
  23. # This program is free software; you can redistribute it and/or modify
  24. # it under the terms of the GNU General Public License as published by
  25. # the Free Software Foundation; either version 2 of the License, or
  26. # (at your option) any later version.
  27. #
  28. # This program is distributed in the hope that it will be useful,
  29. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. # GNU General Public License for more details.
  32. # You should have received a copy of the GNU General Public License
  33. # along with this program; if not, write to the Free Software
  34. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  35. #======================================================================
  36. #
  37. # Job Costing module
  38. #
  39. #======================================================================
  40. use Error qw(:try);
  41. use LedgerSMB::Template;
  42. use LedgerSMB::JC;
  43. 1;
  44. # end of main
  45. sub add {
  46. if ($form->{type} eq 'timecard') {
  47. $form->{title} = $locale->text('Add Time Card');
  48. }
  49. if ($form->{type} eq 'storescard') {
  50. $form->{title} = $locale->text('Add Stores Card');
  51. }
  52. $form->{callback} = "$form->{script}?action=add&type=$form->{type}&login=$form->{login}&path=$form->{path}&sessionid=$form->{sessionid}&project=$form->{project}" unless $form->{callback};
  53. &{ "prepare_$form->{type}" };
  54. $form->{orphaned} = 1;
  55. &display_form;
  56. }
  57. sub edit {
  58. if ($form->{type} eq 'timecard') {
  59. $form->{title} = $locale->text('Edit Time Card');
  60. }
  61. if ($form->{type} eq 'storescard') {
  62. $form->{title} = $locale->text('Add Stores Card');
  63. }
  64. &{ "prepare_$form->{type}" };
  65. &display_form;
  66. }
  67. sub jcitems_links {
  68. if (@{ $form->{all_project} }) {
  69. $form->{selectprojectnumber} = "<option>\n";
  70. foreach $ref (@{ $form->{all_project} }) {
  71. $form->{selectprojectnumber} .= qq|<option value="$ref->{projectnumber}--$ref->{id}">$ref->{description} ($ref->{description})</option>\n|;
  72. if ($form->{projectnumber} eq "$ref->{projectnumber}--$ref->{id}") {
  73. $form->{projectdescription} = $ref->{description};
  74. }
  75. }
  76. } else {
  77. if ($form->{project} eq 'job') {
  78. $form->error($locale->text('No open Jobs!'));
  79. } else {
  80. $form->error($locale->text('No open Projects!'));
  81. }
  82. }
  83. if (@{ $form->{all_parts} }) {
  84. $form->{selectpartnumber} = "<option>\n";
  85. foreach $ref (@{ $form->{all_parts} }) {
  86. $form->{selectpartnumber} .= qq|<option value="$ref->{partnumber}--$ref->{id}">$ref->{partnumber}\n|;
  87. if ($form->{partnumber} eq "$ref->{partnumber}--$ref->{id}") {
  88. if ($form->{partnumber} ne $form->{oldpartnumber}) {
  89. for (qw(description unit sellprice pricematrix)) { $form->{$_} = $ref->{$_} }
  90. }
  91. }
  92. }
  93. } else {
  94. if ($form->{type} eq 'timecard') {
  95. if ($form->{project} eq 'job') {
  96. $form->error($locale->text('No Labor codes on file!'));
  97. } else {
  98. $form->error($locale->text('No Services on file!'));
  99. }
  100. } else {
  101. $form->error($locale->text('No Parts on file!'));
  102. }
  103. }
  104. # employees
  105. if (@{ $form->{all_employee} }) {
  106. $form->{selectemployee} = "<option>\n";
  107. for (@{ $form->{all_employee} }) { $form->{selectemployee} .= qq|<option value="$_->{name}--$_->{id}">$_->{name}\n| }
  108. } else {
  109. $form->error($locale->text('No Employees on file!'));
  110. }
  111. }
  112. sub search {
  113. # accounting years
  114. $form->all_years(\%myconfig);
  115. if (@{ $form->{all_years} }) {
  116. $form->{selectaccountingyear} = "<option>\n";
  117. for (@{ $form->{all_years} }) { $form->{selectaccountingyear} .= qq|<option>$_\n| }
  118. $form->{selectaccountingmonth} = "<option>\n";
  119. for (sort keys %{ $form->{all_month} }) { $form->{selectaccountingmonth} .= qq|<option value=$_>|.$locale->text($form->{all_month}{$_}).qq|\n| }
  120. $selectfrom = qq|
  121. <tr>
  122. <th align=right>|.$locale->text('Period').qq|</th>
  123. <td colspan=3>
  124. <select name=month>$form->{selectaccountingmonth}</select>
  125. <select name=year>$form->{selectaccountingyear}</select>
  126. <input name=interval class=radio type=radio value=0 checked>&nbsp;|.$locale->text('Current').qq|
  127. <input name=interval class=radio type=radio value=1>&nbsp;|.$locale->text('Month').qq|
  128. <input name=interval class=radio type=radio value=3>&nbsp;|.$locale->text('Quarter').qq|
  129. <input name=interval class=radio type=radio value=12>&nbsp;|.$locale->text('Year').qq|
  130. </td>
  131. </tr>
  132. |;
  133. }
  134. $fromto = qq|
  135. <tr>
  136. <th align=right nowrap>|.$locale->text('Startdate').qq|</th>
  137. <td>|.$locale->text('From').qq| <input name=startdatefrom size=11 title="$myconfig{dateformat}">
  138. |.$locale->text('To').qq| <input name=startdateto size=11 title="$myconfig{dateformat}"></td>
  139. </tr>
  140. $selectfrom
  141. |;
  142. if ($form->{type} eq 'timecard') {
  143. $form->{title} = $locale->text('Time Cards');
  144. JC->jcitems_links(\%myconfig, \%$form);
  145. }
  146. if ($form->{type} eq 'storescard') {
  147. $form->{title} = $locale->text('Stores Cards');
  148. JC->jcitems_links(\%myconfig, \%$form);
  149. }
  150. if (@{ $form->{all_project} }) {
  151. $form->{selectprojectnumber} = "<option>\n";
  152. for (@{ $form->{all_project} }) { $form->{selectprojectnumber} .= qq|<option value="$_->{projectnumber}--$_->{id}">$_->{projectnumber}\n| }
  153. }
  154. if (@{ $form->{all_parts} }) {
  155. $form->{selectpartnumber} = "<option>\n";
  156. foreach $ref (@{ $form->{all_parts} }) {
  157. $form->{selectpartnumber} .= qq|<option value="$ref->{partnumber}--$ref->{id}">$ref->{partnumber}\n|;
  158. }
  159. }
  160. if ($form->{project} eq 'job') {
  161. $joblabel = $locale->text('Job Number');
  162. $laborlabel = $locale->text('Labor Code');
  163. } elsif ($form->{project} eq 'project') {
  164. $joblabel = $locale->text('Project Number');
  165. $laborlabel = $locale->text('Service Code');
  166. } else {
  167. $joblabel = $locale->text('Project/Job Number');
  168. $laborlabel = $locale->text('Service/Labor Code');
  169. }
  170. if ($form->{selectprojectnumber}) {
  171. $jobnumber = qq|
  172. <tr>
  173. <th align=right nowrap>$joblabel</th>
  174. <td colspan=3><select name=projectnumber>$form->{selectprojectnumber}</select></td>
  175. </tr>
  176. |;
  177. }
  178. if ($form->{type} eq 'timecard') {
  179. # employees
  180. if (@{ $form->{all_employee} }) {
  181. $form->{selectemployee} = "<option>\n";
  182. for (@{ $form->{all_employee} }) { $form->{selectemployee} .= qq|<option value="$_->{name}--$_->{id}">$_->{name}\n| }
  183. } else {
  184. $form->error($locale->text('No Employees on file!'));
  185. }
  186. if ($form->{selectpartnumber}) {
  187. $partnumber = qq|
  188. <tr>
  189. <th align=right nowrap>$laborlabel</th>
  190. <td colspan=3><select name=partnumber>$form->{selectpartnumber}</select></td>
  191. </tr>
  192. |;
  193. }
  194. $employee = qq|
  195. <tr>
  196. <th align=right nowrap>|.$locale->text('Employee').qq|</th>
  197. <td colspan=3><select name=employee>$form->{selectemployee}</select></td>
  198. </tr>
  199. |;
  200. $l_time = qq|<td nowrap><input name=l_time class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Time').qq|</td>|;
  201. }
  202. $form->header;
  203. print qq|
  204. <body>
  205. <form method=post action=$form->{script}>
  206. <table width=100%>
  207. <tr>
  208. <th class=listtop>$form->{title}</th>
  209. </tr>
  210. <tr height="5"></tr>
  211. <tr valign=top>
  212. <td>
  213. <table>
  214. $jobnumber
  215. $partnumber
  216. $employee
  217. $fromto
  218. <tr>
  219. <th align=right nowrap>|.$locale->text('Include in Report').qq|</th>
  220. <td>
  221. <table>
  222. <tr>
  223. <td nowrap><input name=open class=checkbox type=checkbox value=Y checked> |.$locale->text('Open').qq|</td>
  224. <td nowrap><input name=closed class=checkbox type=checkbox value=Y> |.$locale->text('Closed').qq|</td>
  225. </tr>
  226. <tr>
  227. $l_time
  228. <td nowrap><input name=l_allocated class=checkbox type=checkbox value=Y> |.$locale->text('Allocated').qq|</td>
  229. </tr>
  230. <tr>
  231. <td><input name=l_subtotal class=checkbox type=checkbox value=Y>&nbsp;|.$locale->text('Subtotal').qq|</td>
  232. </tr>
  233. </table>
  234. </td>
  235. </tr>
  236. </table>
  237. </td>
  238. </tr>
  239. <tr>
  240. <td><hr size=3 noshade></td>
  241. </tr>
  242. </table>
  243. <input type=hidden name=nextsub value="list_$form->{type}">
  244. <input type=hidden name=sort value="transdate">
  245. |;
  246. $form->hide_form(qw(db path login sessionid project type));
  247. print qq|
  248. <br>
  249. <button type="submit" class="submit" name="action" value="continue">|.$locale->text('Continue').qq|</button>
  250. </form>
  251. |;
  252. if ($form->{lynx}) {
  253. require "bin/menu.pl";
  254. &menubar;
  255. }
  256. print qq|
  257. </body>
  258. </html>
  259. |;
  260. }
  261. sub display_form {
  262. &{ "$form->{type}_header" };
  263. &{ "$form->{type}_footer" };
  264. }
  265. sub form_header {
  266. &{ "$form->{type}_header" };
  267. }
  268. sub form_footer {
  269. &{ "form->{type}_footer" };
  270. }
  271. sub prepare_timecard {
  272. $form->{formname} = "timecard";
  273. $form->{format} = "postscript" if $myconfig{printer};
  274. $form->{media} = $myconfig{printer};
  275. JC->get_jcitems(\%myconfig, \%$form);
  276. $form->{selectformname} = qq|<option value="timecard">|.$locale->text('Time Card');
  277. foreach $item (qw(in out)) {
  278. ($form->{"${item}hour"}, $form->{"${item}min"}, $form->{"${item}sec"}) = split /:/, $form->{"checked$item"};
  279. for (qw(hour min sec)) {
  280. if (($form->{"$item$_"} *= 1) > 0) {
  281. $form->{"$item$_"} = substr(qq|0$form->{"$item$_"}|,-2);
  282. } else {
  283. $form->{"$item$_"} ||= "";
  284. }
  285. }
  286. }
  287. $form->{checkedin} = $form->{inhour} * 3600 + $form->{inmin} * 60 + $form->{insec};
  288. $form->{checkedout} = $form->{outhour} * 3600 + $form->{outmin} * 60 + $form->{outsec};
  289. if ($form->{checkedin} > $form->{checkedout}) {
  290. $form->{checkedout} = 86400 - ($form->{checkedin} - $form->{checkedout});
  291. $form->{checkedin} = 0;
  292. }
  293. $form->{clocked} = ($form->{checkedout} - $form->{checkedin}) / 3600;
  294. if ($form->{clocked}) {
  295. $form->{oldnoncharge} = $form->{clocked} - $form->{qty};
  296. }
  297. $form->{oldqty} = $form->{qty};
  298. $form->{noncharge} = $form->format_amount(\%myconfig, $form->{clocked} - $form->{qty}, 4) if $form->{checkedin} != $form->{checkedout};
  299. $form->{clocked} = $form->format_amount(\%myconfig, $form->{clocked}, 4);
  300. $form->{amount} = $form->{sellprice} * $form->{qty};
  301. for (qw(sellprice amount)) { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 2) }
  302. $form->{qty} = $form->format_amount(\%myconfig, $form->{qty}, 4);
  303. $form->{allocated} = $form->format_amount(\%myconfig, $form->{allocated});
  304. $form->{employee} .= "--$form->{employee_id}";
  305. $form->{projectnumber} .= "--$form->{project_id}";
  306. $form->{partnumber} .= "--$form->{parts_id}";
  307. $form->{oldpartnumber} = $form->{partnumber};
  308. if (@{ $form->{all_language} }) {
  309. $form->{selectlanguage} = "<option>\n";
  310. for (@{ $form->{all_language} }) { $form->{selectlanguage} .= qq|<option value="$_->{code}">$_->{description}\n| }
  311. }
  312. &jcitems_links;
  313. $form->{locked} = ($form->{revtrans}) ? '1' : ($form->datetonum(\%myconfig, $form->{transdate}) <= $form->datetonum(\%myconfig, $form->{closedto}));
  314. $form->{readonly} = 1 if $myconfig{acs} =~ /Production--Add Time Card/;
  315. if ($form->{income_accno_id}) {
  316. $form->{locked} = 1 if $form->{production} == $form->{completed};
  317. }
  318. }
  319. sub timecard_header {
  320. # set option selected
  321. for (qw(employee projectnumber partnumber)) {
  322. $form->{"select$_"} =~ s/ selected//;
  323. $form->{"select$_"} =~ s/(<option value="\Q$form->{$_}\E")/$1 selected/;
  324. }
  325. $rows = $form->numtextrows($form->{description}, 50, 8);
  326. for (qw(transdate checkedin checkedout partnumber)) { $form->{"old$_"} = $form->{$_} }
  327. for (qw(partnumber description)) { $form->{$_} = $form->quote($form->{$_}) }
  328. if ($rows > 1) {
  329. $description = qq|<textarea name=description rows=$rows cols=46 wrap=soft>$form->{description}</textarea>|;
  330. } else {
  331. $description = qq|<input name=description size=48 value="$form->{description}">|;
  332. }
  333. if ($form->{project} eq 'job') {
  334. $projectlabel = $locale->text('Job Number');
  335. $laborlabel = $locale->text('Labor Code');
  336. $rate = qq|<input type=hidden name=sellprice value=$form->{sellprice}>|;
  337. } else {
  338. if ($form->{project} eq 'project') {
  339. $projectlabel = $locale->text('Project Number');
  340. $laborlabel = $locale->text('Service Code');
  341. } else {
  342. $projectlabel = $locale->text('Project/Job Number');
  343. $laborlabel = $locale->text('Service/Labor Code');
  344. }
  345. if ($myconfig{role} ne 'user') {
  346. $rate = qq|
  347. <tr>
  348. <th align=right nowrap>|.$locale->text('Chargeout Rate').qq|</th>
  349. <td><input name=sellprice value=$form->{sellprice}></td>
  350. <th align=right nowrap>|.$locale->text('Total').qq|</th>
  351. <td>$form->{amount}</td>
  352. </tr>
  353. <tr>
  354. <th align=right nowrap>|.$locale->text('Allocated').qq|</th>
  355. <td><input name=allocated value=$form->{allocated}></td>
  356. </tr>
  357. |;
  358. } else {
  359. $rate = qq|
  360. <tr>
  361. <th align=right nowrap>|.$locale->text('Chargeout Rate').qq|</th>
  362. <td>$form->{sellprice}</td>
  363. <th align=right nowrap>|.$locale->text('Total').qq|</th>
  364. <td>$form->{amount}</td>
  365. </tr>
  366. <tr>
  367. <th align=right nowrap>|.$locale->text('Allocated').qq|</th>
  368. <td>$form->{allocated}</td>
  369. </tr>
  370. <input type=hidden name=sellprice value=$form->{sellprice}>
  371. <input type=hidden name=allocated value=$form->{allocated}>
  372. |;
  373. }
  374. }
  375. if ($myconfig{role} eq 'user') {
  376. $charge = qq|<input type=hidden name=qty value=$form->{qty}>$form->{qty}|;
  377. } else {
  378. $charge = qq|<input name=qty value=$form->{qty}>|;
  379. }
  380. if (($rows = $form->numtextrows($form->{notes}, 40, 6)) < 2) {
  381. $rows = 2;
  382. }
  383. $notes = qq|<tr>
  384. <th align=right>|.$locale->text('Notes').qq|</th>
  385. <td colspan=3><textarea name="notes" rows=$rows cols=46 wrap=soft>$form->{notes}</textarea>
  386. </td>
  387. </tr>
  388. |;
  389. ##################
  390. ($null, $form->{oldproject_id}) = split /--/, $form->{projectnumber};
  391. $form->header;
  392. print qq|
  393. <body>
  394. <form method=post action="$form->{script}">
  395. |;
  396. $form->hide_form(qw(id type media format printed queued title closedto locked oldtransdate oldcheckedin oldcheckedout oldpartnumber project oldqty oldnoncharge pricematrix oldproject_id));
  397. print qq|
  398. <table width=100%>
  399. <tr class=listtop>
  400. <th class=listtop>$form->{title}</th>
  401. </tr>
  402. <tr height="5"></tr>
  403. <tr>
  404. <td>
  405. <table>
  406. <tr>
  407. <td>
  408. <table>
  409. <tr>
  410. <th align=right nowrap>|.$locale->text('Employee').qq|</th>
  411. <td><select name=employee>$form->{selectemployee}</select></td>
  412. </tr>
  413. <tr>
  414. <th align=right nowrap>$projectlabel</th>
  415. <td><select name=projectnumber>$form->{selectprojectnumber}</select>
  416. </td>
  417. <td></td>
  418. <td>$form->{projectdescription}</td>
  419. <input type=hidden name=projectdescription value="|.$form->quote($form->{projectdescription}).qq|">
  420. </tr>
  421. <tr>
  422. <th align=right nowrap>|.$locale->text('Date worked').qq|</th>
  423. <td><input name=transdate size=11 title="$myconfig{dateformat}" value=$form->{transdate}></td>
  424. </tr>
  425. <tr>
  426. <th align=right nowrap>$laborlabel</th>
  427. <td><select name=partnumber>$form->{selectpartnumber}</select></td>
  428. </tr>
  429. <tr valign=top>
  430. <th align=right nowrap>|.$locale->text('Description').qq|</th>
  431. <td colspan=3>$description</td>
  432. </tr>
  433. <tr>
  434. <th align=right nowrap>|.$locale->text('Time In').qq|</th>
  435. <td>
  436. <table>
  437. <tr>
  438. <td><input name=inhour title="hh" size=3 maxlength=2 value=$form->{inhour}></td>
  439. <td><input name=inmin title="mm" size=3 maxlength=2 value=$form->{inmin}></td>
  440. <td><input name=insec title="ss" size=3 maxlength=2 value=$form->{insec}></td>
  441. </tr>
  442. </table>
  443. </td>
  444. <th align=right nowrap>|.$locale->text('Time Out').qq|</th>
  445. <td>
  446. <table>
  447. <tr>
  448. <td><input name=outhour title="hh" size=3 maxlength=2 value=$form->{outhour}></td>
  449. <td><input name=outmin title="mm" size=3 maxlength=2 value=$form->{outmin}></td>
  450. <td><input name=outsec title="ss" size=3 maxlength=2 value=$form->{outsec}></td>
  451. </tr>
  452. </table>
  453. </td>
  454. </tr>
  455. <tr>
  456. <th align=right nowrap>|.$locale->text('Clocked').qq|</th>
  457. <td>$form->{clocked}</td>
  458. </tr>
  459. <tr>
  460. <th align=right nowrap>|.$locale->text('Non-chargeable').qq|</th>
  461. <td><input name=noncharge value=$form->{noncharge}></td>
  462. </tr>
  463. <tr>
  464. <th align=right nowrap>|.$locale->text('Chargeable').qq|</th>
  465. <td>$charge</td>
  466. </tr>
  467. $rate
  468. $notes
  469. </table>
  470. </td>
  471. </tr>
  472. |;
  473. }
  474. sub timecard_footer {
  475. print qq|
  476. </table>
  477. </td>
  478. </tr>
  479. <tr>
  480. <td><hr size=3 noshade></td>
  481. </tr>
  482. <tr>
  483. <td>
  484. |;
  485. &print_options;
  486. print qq|
  487. </td>
  488. </tr>
  489. </table>
  490. <br>
  491. |;
  492. $transdate = $form->datetonum(\%myconfig, $form->{transdate});
  493. $closedto = $form->datetonum(\%myconfig, $form->{closedto});
  494. if (! $form->{readonly}) {
  495. # type=submit $locale->text('Update')
  496. # type=submit $locale->text('Print')
  497. # type=submit $locale->text('Save')
  498. # type=submit $locale->text('Print and Save')
  499. # type=submit $locale->text('Save as new')
  500. # type=submit $locale->text('Print and Save as new')
  501. # type=submit $locale->text('Delete')
  502. %button = ('update' => { ndx => 1, key => 'U', value => $locale->text('Update') },
  503. 'print' => { ndx => 2, key => 'P', value => $locale->text('Print') },
  504. 'save' => { ndx => 3, key => 'S', value => $locale->text('Save') },
  505. 'print_and_save' => { ndx => 6, key => 'R', value => $locale->text('Print and Save') },
  506. 'save_as_new' => { ndx => 7, key => 'N', value => $locale->text('Save as new') },
  507. 'print_and_save_as_new' => { ndx => 8, key => 'W', value => $locale->text('Print and Save as new') },
  508. 'delete' => { ndx => 16, key => 'D', value => $locale->text('Delete') },
  509. );
  510. %a = ();
  511. if ($form->{id}) {
  512. if (!$form->{locked}) {
  513. for ('update', 'print', 'save', 'save_as_new') { $a{$_} = 1 }
  514. if (${LedgerSMB::Sysconfig::latex}) {
  515. for ('print_and_save', 'print_and_save_as_new') { $a{$_} = 1 }
  516. }
  517. if ($form->{orphaned}) {
  518. $a{'delete'} = 1;
  519. }
  520. }
  521. } else {
  522. if ($transdate > $closedto) {
  523. for ('update', 'print', 'save') { $a{$_} = 1 }
  524. if (${LedgerSMB::Sysconfig::latex}) {
  525. $a{'print_and_save'} = 1;
  526. }
  527. }
  528. }
  529. }
  530. for (keys %button) { delete $button{$_} if ! $a{$_} }
  531. for (sort { $button{$a}->{ndx} <=> $button{$b}->{ndx} } keys %button) { $form->print_button(\%button, $_) }
  532. if ($form->{lynx}) {
  533. require "bin/menu.pl";
  534. &menubar;
  535. }
  536. $form->hide_form(qw(callback path login sessionid));
  537. print qq|
  538. </form>
  539. </body>
  540. </html>
  541. |;
  542. }
  543. sub prepare_storescard {
  544. $form->{formname} = "storescard";
  545. $form->{format} = "postscript" if $myconfig{printer};
  546. $form->{media} = $myconfig{printer};
  547. JC->get_jcitems(\%myconfig, \%$form);
  548. $form->{selectformname} = qq|<option value="storescard">|.$locale->text('Stores Card');
  549. $form->{amount} = $form->{sellprice} * $form->{qty};
  550. for (qw(sellprice amount)) { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 2) }
  551. $form->{qty} = $form->format_amount(\%myconfig, $form->{qty}, 4);
  552. $form->{employee} .= "--$form->{employee_id}";
  553. $form->{projectnumber} .= "--$form->{project_id}";
  554. $form->{partnumber} .= "--$form->{parts_id}";
  555. $form->{oldpartnumber} = $form->{partnumber};
  556. if (@{ $form->{all_language} }) {
  557. $form->{selectlanguage} = "<option>\n";
  558. for (@{ $form->{all_language} }) { $form->{selectlanguage} .= qq|<option value="$_->{code}">$_->{description}\n| }
  559. }
  560. &jcitems_links;
  561. $form->{locked} = ($form->{revtrans}) ? '1' : ($form->datetonum(\%myconfig, $form->{transdate}) <= $form->datetonum(\%myconfig, $form->{closedto}));
  562. $form->{readonly} = 1 if $myconfig{acs} =~ /Production--Add Time Card/;
  563. if ($form->{income_accno_id}) {
  564. $form->{locked} = 1 if $form->{production} == $form->{completed};
  565. }
  566. }
  567. sub storescard_header {
  568. # set option selected
  569. for (qw(employee projectnumber partnumber)) {
  570. $form->{"select$_"} =~ s/ selected//;
  571. $form->{"select$_"} =~ s/(<option value="\Q$form->{$_}\E")/$1 selected/;
  572. }
  573. $rows = $form->numtextrows($form->{description}, 50, 8);
  574. for (qw(transdate partnumber)) { $form->{"old$_"} = $form->{$_} }
  575. for (qw(partnumber description)) { $form->{$_} = $form->quote($form->{$_}) }
  576. if ($rows > 1) {
  577. $description = qq|<textarea name=description rows=$rows cols=46 wrap=soft>$form->{description}</textarea>|;
  578. } else {
  579. $description = qq|<input name=description size=48 value="$form->{description}">|;
  580. }
  581. $form->header;
  582. print qq|
  583. <body>
  584. <form method=post action="$form->{script}">
  585. |;
  586. $form->hide_form(qw(id type media format printed queued title closedto locked oldtransdate oldpartnumber project));
  587. print qq|
  588. <table width=100%>
  589. <tr class=listtop>
  590. <th class=listtop>$form->{title}</th>
  591. </tr>
  592. <tr height="5"></tr>
  593. <tr>
  594. <td>
  595. <table>
  596. <tr>
  597. <td>
  598. <table>
  599. <tr>
  600. <th align=right nowrap>|.$locale->text('Job Number').qq|</th>
  601. <td><select name=projectnumber>$form->{selectprojectnumber}</select>
  602. </td>
  603. <td>$form->{projectdescription}</td>
  604. <input type=hidden name=projectdescription value="|.$form->quote($form->{projectdescription}).qq|">
  605. </tr>
  606. <tr>
  607. <th align=right nowrap>|.$locale->text('Date').qq|</th>
  608. <td><input name=transdate size=11 title="$myconfig{dateformat}" value=$form->{transdate}></td>
  609. </tr>
  610. <tr>
  611. <th align=right nowrap>|.$locale->text('Part Number').qq|</th>
  612. <td><select name=partnumber>$form->{selectpartnumber}</td>
  613. </tr>
  614. <tr valign=top>
  615. <th align=right nowrap>|.$locale->text('Description').qq|</th>
  616. <td>$description</td>
  617. </tr>
  618. <tr>
  619. <th align=right nowrap>|.$locale->text('Qty').qq|</th>
  620. <td><input name=qty size=6 value=$form->{qty}>
  621. <b>|.$locale->text('Cost').qq|</b>
  622. <input name=sellprice size=10 value=$form->{sellprice}></td>
  623. </tr>
  624. <tr>
  625. <th align=right nowrap>|.$locale->text('Total').qq|</th>
  626. <td>$form->{amount}</td>
  627. </tr>
  628. </table>
  629. </td>
  630. </tr>
  631. |;
  632. }
  633. sub storescard_footer {
  634. print qq|
  635. </table>
  636. </td>
  637. </tr>
  638. <tr>
  639. <td><hr size=3 noshade></td>
  640. </tr>
  641. <tr>
  642. <td>
  643. |;
  644. &print_options;
  645. print qq|
  646. </td>
  647. </tr>
  648. </table>
  649. <br>
  650. |;
  651. $transdate = $form->datetonum(\%myconfig, $form->{transdate});
  652. $closedto = $form->datetonum(\%myconfig, $form->{closedto});
  653. # type=submit $locale->text('Update')
  654. # type=submit $locale->text('Print')
  655. # type=submit $locale->text('Save')
  656. # type=submit $locale->text('Print and Save')
  657. # type=submit $locale->text('Save as new')
  658. # type=submit $locale->text('Print and Save as new')
  659. # type=submit $locale->text('Delete')
  660. if (! $form->{readonly}) {
  661. %button = ('update' => { ndx => 1, key => 'U', value => $locale->text('Update') },
  662. 'print' => { ndx => 2, key => 'P', value => $locale->text('Print') },
  663. 'save' => { ndx => 3, key => 'S', value => $locale->text('Save') },
  664. 'print_and_save' => { ndx => 6, key => 'R', value => $locale->text('Print and Save') },
  665. 'save_as_new' => { ndx => 7, key => 'N', value => $locale->text('Save as new') },
  666. 'print_and_save_as_new' => { ndx => 8, key => 'W', value => $locale->text('Print and Save as new') },
  667. 'delete' => { ndx => 16, key => 'D', value => $locale->text('Delete') },
  668. );
  669. %a = ();
  670. if ($form->{id}) {
  671. if (!$form->{locked}) {
  672. for ('update', 'print', 'save', 'save_as_new') { $a{$_} = 1 }
  673. if (${LedgerSMB::Sysconfig::latex}) {
  674. for ('print_and_save', 'print_and_save_as_new') { $a{$_} = 1 }
  675. }
  676. if ($form->{orphaned}) {
  677. $a{'delete'} = 1;
  678. }
  679. }
  680. } else {
  681. if ($transdate > $closedto) {
  682. for ('update', 'print', 'save') { $a{$_} = 1 }
  683. if (${LedgerSMB::Sysconfig::latex}) {
  684. $a{'print_and_save'} = 1;
  685. }
  686. }
  687. }
  688. for (keys %button) { delete $button{$_} if ! $a{$_} }
  689. for (sort { $button{$a}->{ndx} <=> $button{$b}->{ndx} } keys %button) { $form->print_button(\%button, $_) }
  690. }
  691. if ($form->{lynx}) {
  692. require "bin/menu.pl";
  693. &menubar;
  694. }
  695. $form->hide_form(qw(callback path login sessionid));
  696. print qq|
  697. </form>
  698. </body>
  699. </html>
  700. |;
  701. }
  702. sub update {
  703. ($null, $form->{project_id}) = split /--/, $form->{projectnumber};
  704. # check labor/part
  705. JC->jcitems_links(\%myconfig, \%$form);
  706. &jcitems_links;
  707. $checkmatrix = 1 if $form->{oldproject_id} != $form->{project_id};
  708. if ($form->{type} eq 'timecard') {
  709. # time clocked
  710. %hour = ( in => 0, out => 0 );
  711. for $t (qw(in out)) {
  712. if ($form->{"${t}sec"} > 60) {
  713. $form->{"${t}sec"} -= 60;
  714. $form->{"${t}min"}++;
  715. }
  716. if ($form->{"${t}min"} > 60) {
  717. $form->{"${t}min"} -= 60;
  718. $form->{"${t}hour"}++;
  719. }
  720. $hour{$t} = $form->{"${t}hour"};
  721. }
  722. $form->{checkedin} = $hour{in} * 3600 + $form->{inmin} * 60 + $form->{insec};
  723. $form->{checkedout} = $hour{out} * 3600 + $form->{outmin} * 60 + $form->{outsec};
  724. if ($form->{checkedin} > $form->{checkedout}) {
  725. $form->{checkedout} = 86400 - ($form->{checkedin} - $form->{checkedout});
  726. $form->{checkedin} = 0;
  727. }
  728. $form->{clocked} = ($form->{checkedout} - $form->{checkedin}) / 3600;
  729. for (qw(sellprice qty noncharge allocated)) { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
  730. $checkmatrix = 1 if $form->{oldqty} != $form->{qty};
  731. if (($form->{oldcheckedin} != $form->{checkedin}) || ($form->{oldcheckedout} != $form->{checkedout})) {
  732. $checkmatrix = 1;
  733. $form->{oldqty} = $form->{qty} = $form->{clocked} - $form->{noncharge};
  734. $form->{oldnoncharge} = $form->{noncharge};
  735. }
  736. if (($form->{qty} != $form->{oldqty}) && $form->{clocked}) {
  737. $form->{oldnoncharge} = $form->{noncharge} = $form->{clocked} - $form->{qty};
  738. $checkmatrix = 1;
  739. }
  740. if (($form->{oldnoncharge} != $form->{noncharge}) && $form->{clocked}) {
  741. $form->{oldqty} = $form->{qty} = $form->{clocked} - $form->{noncharge};
  742. $checkmatrix = 1;
  743. }
  744. if ($checkmatrix) {
  745. @a = split / /, $form->{pricematrix};
  746. if (scalar @a > 2) {
  747. for (@a) {
  748. ($q, $p) = split /:/, $_;
  749. if (($p * 1) && ($form->{qty} >= ($q * 1))) {
  750. $form->{sellprice} = $p;
  751. }
  752. }
  753. }
  754. }
  755. $form->{amount} = $form->{sellprice} * $form->{qty};
  756. $form->{clocked} = $form->format_amount(\%myconfig, $form->{clocked}, 4);
  757. for (qw(sellprice amount)) { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 2) }
  758. for (qw(qty noncharge)) {
  759. $form->{"old$_"} = $form->{$_};
  760. $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 4);
  761. }
  762. } else {
  763. for (qw(sellprice qty allocated)) { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
  764. if ($form->{oldqty} != $form->{qty}) {
  765. @a = split / /, $form->{pricematrix};
  766. if (scalar @a > 2) {
  767. for (@a) {
  768. ($q, $p) = split /:/, $_;
  769. if (($p * 1) && ($form->{qty} >= ($q * 1))) {
  770. $form->{sellprice} = $p;
  771. }
  772. }
  773. }
  774. }
  775. $form->{amount} = $form->{sellprice} * $form->{qty};
  776. for (qw(sellprice amount)) { $form->{$_} = $form->format_amount(\%myconfig, $form->{$_}, 2) }
  777. }
  778. $form->{allocated} = $form->format_amount(\%myconfig, $form->{allocated});
  779. &display_form;
  780. }
  781. sub save {
  782. $form->isblank("transdate", $locale->text('Date missing!'));
  783. if ($form->{project} eq 'project') {
  784. $form->isblank("projectnumber", $locale->text('Project Number missing!'));
  785. $form->isblank("partnumber", $locale->text('Service Code missing!'));
  786. } else {
  787. $form->isblank("projectnumber", $locale->text('Job Number missing!'));
  788. $form->isblank("partnumber", $locale->text('Labor Code missing!'));
  789. }
  790. $closedto = $form->datetonum(\%myconfig, $form->{closedto});
  791. $transdate = $form->datetonum(\%myconfig, $form->{transdate});
  792. $msg = ($form->{type} eq 'timecard') ? $locale->text('Cannot save time card for a closed period!') : $locale->text('Cannot save stores card for a closed period!');
  793. $form->error($msg) if ($transdate <= $closedto);
  794. if (! $form->{resave}) {
  795. if ($form->{id}) {
  796. &resave;
  797. exit;
  798. }
  799. }
  800. $rc = JC->save(\%myconfig, \%$form);
  801. if ($form->{type} eq 'timecard') {
  802. $form->error($locale->text('Cannot change time card for a completed job!')) if ($rc == -1);
  803. $form->error($locale->text('Cannot add time card for a completed job!')) if ($rc == -2);
  804. if ($rc) {
  805. $form->redirect($locale->text('Time Card saved!'));
  806. } else {
  807. $form->error($locale->text('Cannot save time card!'));
  808. }
  809. } else {
  810. $form->error($locale->text('Cannot change stores card for a completed job!')) if ($rc == -1);
  811. $form->error($locale->text('Cannot add stores card for a completed job!')) if ($rc == -2);
  812. if ($rc) {
  813. $form->redirect($locale->text('Stores Card saved!'));
  814. } else {
  815. $form->error($locale->text('Cannot save stores card!'));
  816. }
  817. }
  818. }
  819. sub save_as_new {
  820. delete $form->{id};
  821. &save;
  822. }
  823. sub print_and_save_as_new {
  824. delete $form->{id};
  825. &print_and_save;
  826. }
  827. sub resave {
  828. if ($form->{print_and_save}) {
  829. $form->{nextsub} = "print_and_save";
  830. $msg = $locale->text('You are printing and saving an existing transaction!');
  831. } else {
  832. $form->{nextsub} = "save";
  833. $msg = $locale->text('You are saving an existing transaction!');
  834. }
  835. $form->{resave} = 1;
  836. $form->header;
  837. print qq|
  838. <body>
  839. <form method=post action=$form->{script}>
  840. |;
  841. delete $form->{action};
  842. $form->hide_form;
  843. print qq|
  844. <h2 class=confirm>|.$locale->text('Warning!').qq|</h2>
  845. <h4>$msg</h4>
  846. <button name="action" class="submit" type="submit" value="continue">|.$locale->text('Continue').qq|</button>
  847. </form>
  848. </body>
  849. </html>
  850. |;
  851. }
  852. sub print_and_save {
  853. $form->error($locale->text('Select postscript or PDF!')) if $form->{format} !~ /(postscript|pdf)/;
  854. $form->error($locale->text('Select a Printer!')) if $form->{media} eq 'screen';
  855. if (! $form->{resave}) {
  856. if ($form->{id}) {
  857. $form->{print_and_save} = 1;
  858. &resave;
  859. exit;
  860. }
  861. }
  862. $old_form = new Form;
  863. $form->{display_form} = "save";
  864. for (keys %$form) { $old_form->{$_} = $form->{$_} }
  865. &{ "print_$form->{formname}" }($old_form);
  866. }
  867. sub delete_timecard {
  868. $form->header;
  869. $employee = $form->{employee};
  870. $employee =~ s/--.*//g;
  871. $projectnumber = $form->{projectnumber};
  872. $projectnumber =~ s/--.*//g;
  873. print qq|
  874. <body>
  875. <form method=post action=$form->{script}>
  876. |;
  877. delete $form->{action};
  878. $form->hide_form;
  879. print qq|
  880. <h2 class=confirm>|.$locale->text('Confirm!').qq|</h2>
  881. <h4>|.$locale->text('Are you sure you want to delete time card for').qq|
  882. <p>$form->{transdate}
  883. <br>$employee
  884. <br>$projectnumber
  885. </h4>
  886. <p>
  887. <button name="action" class="submit" type="submit" value="yes">|.$locale->text('Yes').qq|</button>
  888. </form>
  889. |;
  890. }
  891. sub delete { &{ "delete_$form->{type}" } };
  892. sub yes { &{ "yes_delete_$form->{type}" } };
  893. sub yes_delete_timecard {
  894. if (JC->delete_timecard(\%myconfig, \%$form)) {
  895. $form->redirect($locale->text('Time Card deleted!'));
  896. } else {
  897. $form->error($locale->text('Cannot delete time card!'));
  898. }
  899. }
  900. sub list_timecard {
  901. $form->{type} = "timecard";
  902. JC->jcitems(\%myconfig, \%$form);
  903. $form->{title} = $locale->text('Time Cards');
  904. @a = qw(type direction oldsort path login sessionid project l_subtotal open closed l_time l_allocated);
  905. $href = "$form->{script}?action=list_timecard";
  906. for (@a) { $href .= "&$_=$form->{$_}" }
  907. $href .= "&title=".$form->escape($form->{title});
  908. $form->sort_order();
  909. $callback = "$form->{script}?action=list_timecard";
  910. for (@a) { $callback .= "&$_=$form->{$_}" }
  911. $callback .= "&title=".$form->escape($form->{title},1);
  912. @column_index = (qw(transdate projectnumber projectdescription id partnumber description));
  913. push @column_index, (qw(allocated)) if $form->{l_allocated};
  914. push @column_index, (qw(1 2 3 4 5 6 7));
  915. @column_index = $form->sort_columns(@column_index);
  916. if ($form->{project} eq 'job') {
  917. $joblabel = $locale->text('Job Number');
  918. $laborlabel = $locale->text('Labor Code');
  919. $desclabel = $locale->text('Job Name');
  920. } elsif ($form->{project} eq 'project') {
  921. $joblabel = $locale->text('Project Number');
  922. $laborlabel = $locale->text('Service Code');
  923. $desclabel = $locale->text('Project Name');
  924. } else {
  925. $joblabel = $locale->text('Project/Job Number');
  926. $laborlabel = $locale->text('Service/Labor Code');
  927. $desclabel = $locale->text('Project/Job Name');
  928. }
  929. if ($form->{projectnumber}) {
  930. $callback .= "&projectnumber=".$form->escape($form->{projectnumber},1);
  931. $href .= "&projectnumber=".$form->escape($form->{projectnumber});
  932. ($var) = split /--/, $form->{projectnumber};
  933. $option .= "\n<br>" if ($option);
  934. $option .= "$joblabel : $var";
  935. @column_index = grep !/projectnumber/, @column_index;
  936. }
  937. if ($form->{partnumber}) {
  938. $callback .= "&partnumber=".$form->escape($form->{partnumber},1);
  939. $href .= "&partnumber=".$form->escape($form->{partnumber});
  940. ($var) = split /--/, $form->{partnumber};
  941. $option .= "\n<br>" if ($option);
  942. $option .= "$laborlabel : $var";
  943. @column_index = grep !/partnumber/, @column_index;
  944. }
  945. if ($form->{employee}) {
  946. $callback .= "&employee=".$form->escape($form->{employee},1);
  947. $href .= "&employee=".$form->escape($form->{employee});
  948. }
  949. if ($form->{startdatefrom}) {
  950. $callback .= "&startdatefrom=$form->{startdatefrom}";
  951. $href .= "&startdatefrom=$form->{startdatefrom}";
  952. $option .= "\n<br>" if ($option);
  953. $option .= $locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{startdatefrom}, 1);
  954. }
  955. if ($form->{startdateto}) {
  956. $callback .= "&startdateto=$form->{startdateto}";
  957. $href .= "&startdateto=$form->{startdateto}";
  958. $option .= "\n<br>" if ($option);
  959. $option .= $locale->text('To')."&nbsp;".$locale->date(\%myconfig, $form->{startdateto}, 1);
  960. }
  961. if ($form->{open}) {
  962. $callback .= "&open=$form->{open}";
  963. $href .= "&open=$form->{open}";
  964. $option .= "\n<br>" if ($option);
  965. $option .= $locale->text('Open');
  966. }
  967. if ($form->{closed}) {
  968. $callback .= "&closed=$form->{closed}";
  969. $href .= "&closed=$form->{closed}";
  970. $option .= "\n<br>" if ($option);
  971. $option .= $locale->text('Closed');
  972. }
  973. %weekday = ( 1 => $locale->text('Sunday'),
  974. 2 => $locale->text('Monday'),
  975. 3 => $locale->text('Tuesday'),
  976. 4 => $locale->text('Wednesday'),
  977. 5 => $locale->text('Thursday'),
  978. 6 => $locale->text('Friday'),
  979. 7 => $locale->text('Saturday'),
  980. );
  981. for (keys %weekday) { $column_header{$_} = "<th class=listheading width=25>".substr($weekday{$_},0,3)."</th>" }
  982. $column_header{id} = "<th><a class=listheading href=$href&sort=id>".$locale->text('ID')."</a></th>";
  983. $column_header{transdate} = "<th><a class=listheading href=$href&sort=transdate>".$locale->text('Date')."</a></th>";
  984. $column_header{description} = "<th><a class=listheading href=$href&sort=description>" . $locale->text('Description') . "</th>";
  985. $column_header{projectnumber} = "<th><a class=listheading href=$href&sort=projectnumber>$joblabel</a></th>";
  986. $column_header{partnumber} = "<th><a class=listheading href=$href&sort=partnumber>$laborlabel</a></th>";
  987. $column_header{projectdescription} = "<th><a class=listheading href=$href&sort=projectdescription>$desclabel</a></th>";
  988. $column_header{allocated} = "<th class=listheading></th>";
  989. $form->header;
  990. if (@{ $form->{transactions} }) {
  991. $sameitem = $form->{transactions}->[0]->{$form->{sort}};
  992. $sameemployeenumber = $form->{transactions}->[0]->{employeenumber};
  993. $employee = $form->{transactions}->[0]->{employee};
  994. $sameweek = $form->{transactions}->[0]->{workweek};
  995. }
  996. print qq|
  997. <body>
  998. <table width=100%>
  999. <tr>
  1000. <th class=listtop>$form->{title}</th>
  1001. </tr>
  1002. <tr height="5"></tr>
  1003. <tr>
  1004. <td>$option</td>
  1005. </tr>
  1006. <tr>
  1007. <td>
  1008. <table width=100%>
  1009. <tr>
  1010. <th colspan=2 align=left>
  1011. $employee
  1012. </th>
  1013. <th align=left>
  1014. $sameemployeenumber
  1015. </th>
  1016. <tr class=listheading>
  1017. |;
  1018. for (@column_index) { print "\n$column_header{$_}" }
  1019. print qq|
  1020. </tr>
  1021. |;
  1022. # add sort and escape callback, this one we use for the add sub
  1023. $form->{callback} = $callback .= "&sort=$form->{sort}";
  1024. # escape callback for href
  1025. $callback = $form->escape($callback);
  1026. # flip direction
  1027. $direction = ($form->{direction} eq 'ASC') ? "ASC" : "DESC";
  1028. $href =~ s/&direction=(\w+)&/&direction=$direction&/;
  1029. %total = ();
  1030. foreach $ref (@{ $form->{transactions} }) {
  1031. if ($sameemployeenumber ne $ref->{employeenumber}) {
  1032. $sameemployeenumber = $ref->{employeenumber};
  1033. $sameweek = $ref->{workweek};
  1034. if ($form->{l_subtotal}) {
  1035. print qq|
  1036. <tr class=listsubtotal>
  1037. |;
  1038. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1039. $weektotal = 0;
  1040. for (keys %weekday) {
  1041. $column_data{$_} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotal{$_}, "", "&nbsp;")."</th>";
  1042. $weektotal += $subtotal{$_};
  1043. $subtotal{$_} = 0;
  1044. }
  1045. $column_data{$form->{sort}} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $weektotal, "", "&nbsp;")."</th>";
  1046. for (@column_index) { print "\n$column_data{$_}" }
  1047. }
  1048. # print total
  1049. print qq|
  1050. <tr class=listtotal>
  1051. |;
  1052. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1053. $total = 0;
  1054. for (keys %weekday) {
  1055. $column_data{$_} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $total{$_}, "", "&nbsp;")."</th>";
  1056. $total += $total{$_};
  1057. $total{$_} = 0;
  1058. }
  1059. $column_data{$form->{sort}} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $total, "", "&nbsp;")."</th>";
  1060. for (@column_index) { print "\n$column_data{$_}" }
  1061. print qq|
  1062. <tr height=30 valign=bottom>
  1063. <th colspan=2 align=left>
  1064. $ref->{employee}
  1065. </th>
  1066. <th align=left>
  1067. $ref->{employeenumber}
  1068. </th>
  1069. <tr class=listheading>
  1070. |;
  1071. for (@column_index) { print "\n$column_header{$_}" }
  1072. print qq|
  1073. </tr>
  1074. |;
  1075. }
  1076. if ($form->{l_subtotal}) {
  1077. if ($ref->{workweek} != $sameweek) {
  1078. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1079. $weektotal = 0;
  1080. for (keys %weekday) {
  1081. $column_data{$_} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotal{$_}, "", "&nbsp;")."</th>";
  1082. $weektotal += $subtotal{$_};
  1083. $subtotal{$_} = 0
  1084. }
  1085. $column_data{$form->{sort}} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $weektotal, "", "&nbsp;")."</th>";
  1086. $sameweek = $ref->{workweek};
  1087. print qq|
  1088. <tr class=listsubtotal>
  1089. |;
  1090. for (@column_index) { print "\n$column_data{$_}" }
  1091. print qq|
  1092. </tr>
  1093. |;
  1094. }
  1095. }
  1096. for (@column_index) { $column_data{$_} = "<td>$ref->{$_}&nbsp;</td>" }
  1097. for (keys %weekday) { $column_data{$_} = "<td>&nbsp;</td>" }
  1098. $column_data{allocated} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{allocated}, "", "&nbsp;")."</td>";
  1099. $column_data{$ref->{weekday}} = "<td align=right>".$form->format_amount(\%myconfig, $ref->{qty}, "", "&nbsp;");
  1100. if ($form->{l_time}) {
  1101. $column_data{$ref->{weekday}} .= "<br>$ref->{checkedin}<br>$ref->{checkedout}";
  1102. }
  1103. $column_data{$ref->{weekday}} .= "</td>";
  1104. $column_data{id} = "<td><a href=$form->{script}?action=edit&id=$ref->{id}&type=$form->{type}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&project=$form->{project}&callback=$callback>$ref->{id}</a></td>";
  1105. $subtotal{$ref->{weekday}} += $ref->{qty};
  1106. $total{$ref->{weekday}} += $ref->{qty};
  1107. $j++; $j %= 2;
  1108. print qq|
  1109. <tr class=listrow$j>
  1110. |;
  1111. for (@column_index) { print "\n$column_data{$_}" }
  1112. print qq|
  1113. </tr>
  1114. |;
  1115. }
  1116. # print last subtotal
  1117. if ($form->{l_subtotal}) {
  1118. print qq|
  1119. <tr class=listsubtotal>
  1120. |;
  1121. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1122. $weektotal = 0;
  1123. for (keys %weekday) {
  1124. $column_data{$_} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $subtotal{$_}, "", "&nbsp;")."</th>";
  1125. $weektotal += $subtotal{$_};
  1126. }
  1127. $column_data{$form->{sort}} = "<th class=listsubtotal align=right>".$form->format_amount(\%myconfig, $weektotal, "", "&nbsp;")."</th>";
  1128. for (@column_index) { print "\n$column_data{$_}" }
  1129. }
  1130. # print last total
  1131. print qq|
  1132. <tr class=listtotal>
  1133. |;
  1134. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1135. $total = 0;
  1136. for (keys %weekday) {
  1137. $column_data{$_} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $total{$_}, "", "&nbsp;")."</th>";
  1138. $total += $total{$_};
  1139. $total{$_} = 0;
  1140. }
  1141. $column_data{$form->{sort}} = "<th class=listtotal align=right>".$form->format_amount(\%myconfig, $total, "", "&nbsp;")."</th>";
  1142. for (@column_index) { print "\n$column_data{$_}" }
  1143. if ($form->{project} eq 'job') {
  1144. if ($myconfig{acs} !~ /Production--Production/) {
  1145. $i = 1;
  1146. $button{'Production--Add Time Card'}{code} = qq|<button class="submit" type="submit" name="action" value="add_time_card">|.$locale->text('Add Time Card').qq|</button> |;
  1147. $button{'Production--Add Time Card'}{order} = $i++;
  1148. }
  1149. } elsif ($form->{project} eq 'project') {
  1150. if ($myconfig{acs} !~ /Projects--Projects/) {
  1151. $i = 1;
  1152. $button{'Projects--Add Time Card'}{code} = qq|<button class="submit" type="submit" name="action" value="add_time_card">|.$locale->text('Add Time Card').qq|</button> |;
  1153. $button{'Projects--Add Time Card'}{order} = $i++;
  1154. }
  1155. } else {
  1156. if ($myconfig{acs} !~ /Time Cards--Time Cards/) {
  1157. $i = 1;
  1158. $button{'Time Cards--Add Time Card'}{code} = qq|<button class="submit" type="submit" name="action" value="add_time_card">|.$locale->text('Add Time Card').qq|</button> |;
  1159. $button{'Time Cards--Add Time Card'}{order} = $i++;
  1160. }
  1161. }
  1162. for (split /;/, $myconfig{acs}) { delete $button{$_} }
  1163. print qq|
  1164. </tr>
  1165. </table>
  1166. </td>
  1167. </tr>
  1168. <tr>
  1169. <td><hr size=3 noshade></td>
  1170. </tr>
  1171. </table>
  1172. <br>
  1173. <form method=post action=$form->{script}>
  1174. |;
  1175. $form->hide_form(qw(callback path login sessionid project));
  1176. foreach $item (sort { $a->{order} <=> $b->{order} } %button) {
  1177. print $item->{code};
  1178. }
  1179. if ($form->{lynx}) {
  1180. require "bin/menu.pl";
  1181. &menubar;
  1182. }
  1183. print qq|
  1184. </form>
  1185. </body>
  1186. </html>
  1187. |;
  1188. }
  1189. sub list_storescard {
  1190. $form->{type} = "storescard";
  1191. JC->jcitems(\%myconfig, \%$form);
  1192. $form->{title} = $locale->text('Stores Cards');
  1193. $href = "$form->{script}?action=list_storescard";
  1194. for (qw(type direction oldsort path login sessionid project)) { $href .= "&$_=$form->{$_}" }
  1195. $href .= "&title=".$form->escape($form->{title});
  1196. $form->sort_order();
  1197. $callback = "$form->{script}?action=list_storescard";
  1198. for (qw(type direction oldsort path login sessionid project)) { $callback .= "&$_=$form->{$_}" }
  1199. $callback .= "&title=".$form->escape($form->{title},1);
  1200. @column_index = $form->sort_columns(qw(transdate projectnumber projectdescription id partnumber description qty amount));
  1201. if ($form->{projectnumber}) {
  1202. $callback .= "&projectnumber=".$form->escape($form->{projectnumber},1);
  1203. $href .= "&projectnumber=".$form->escape($form->{projectnumber});
  1204. ($var) = split /--/, $form->{projectnumber};
  1205. $option .= "\n<br>" if ($option);
  1206. $option .= "$joblabel : $var";
  1207. @column_index = grep !/projectnumber/, @column_index;
  1208. }
  1209. if ($form->{partnumber}) {
  1210. $callback .= "&partnumber=".$form->escape($form->{partnumber},1);
  1211. $href .= "&partnumber=".$form->escape($form->{partnumber});
  1212. ($var) = split /--/, $form->{partnumber};
  1213. $option .= "\n<br>" if ($option);
  1214. $option .= "$laborlabel : $var";
  1215. @column_index = grep !/partnumber/, @column_index;
  1216. }
  1217. if ($form->{startdatefrom}) {
  1218. $callback .= "&startdatefrom=$form->{startdatefrom}";
  1219. $href .= "&startdatefrom=$form->{startdatefrom}";
  1220. $option .= "\n<br>" if ($option);
  1221. $option .= $locale->text('From')."&nbsp;".$locale->date(\%myconfig, $form->{startdatefrom}, 1);
  1222. }
  1223. if ($form->{startdateto}) {
  1224. $callback .= "&startdateto=$form->{startdateto}";
  1225. $href .= "&startdateto=$form->{startdateto}";
  1226. $option .= "\n<br>" if ($option);
  1227. $option .= $locale->text('To')."&nbsp;".$locale->date(\%myconfig, $form->{startdateto}, 1);
  1228. }
  1229. $column_header{id} = "<th><a class=listheading href=$href&sort=id>" . $locale->text('ID') . "</a></th>";
  1230. $column_header{transdate} = "<th><a class=listheading href=$href&sort=transdate>".$locale->text('Date')."</a></th>";
  1231. $column_header{projectnumber} = "<th><a class=listheading href=$href&sort=projectnumber>" . $locale->text('Job Number') . "</a></th>";
  1232. $column_header{projectdescription} = "<th><a class=listheading href=$href&sort=projectdescription>" . $locale->text('Job Description') . "</a></th>";
  1233. $column_header{partnumber} = "<th><a class=listheading href=$href&sort=partnumber>" . $locale->text('Part Number') . "</a></th>";
  1234. $column_header{description} = "<th><a class=listheading href=$href&sort=description>" . $locale->text('Description') . "</a></th>";
  1235. $column_header{qty} = "<th class=listheading>" . $locale->text('Qty') . "</th>";
  1236. $column_header{amount} = "<th class=listheading>" . $locale->text('Amount') . "</th>";
  1237. $form->header;
  1238. if (@{ $form->{transactions} }) {
  1239. $sameitem = $form->{transactions}->[0]->{$form->{sort}};
  1240. }
  1241. print qq|
  1242. <body>
  1243. <table width=100%>
  1244. <tr>
  1245. <th class=listtop>$form->{title}</th>
  1246. </tr>
  1247. <tr height="5"></tr>
  1248. <tr>
  1249. <td>$option</td>
  1250. </tr>
  1251. <tr>
  1252. <td>
  1253. <table width=100%>
  1254. <tr class=listheading>
  1255. |;
  1256. for (@column_index) { print "\n$column_header{$_}" }
  1257. print qq|
  1258. </tr>
  1259. |;
  1260. # add sort and escape callback, this one we use for the add sub
  1261. $form->{callback} = $callback .= "&sort=$form->{sort}";
  1262. # escape callback for href
  1263. $callback = $form->escape($callback);
  1264. # flip direction
  1265. $direction = ($form->{direction} eq 'ASC') ? "ASC" : "DESC";
  1266. $href =~ s/&direction=(\w+)&/&direction=$direction&/;
  1267. $total = 0;
  1268. foreach $ref (@{ $form->{transactions} }) {
  1269. for (@column_index) { $column_data{$_} = "<td>$ref->{$_}&nbsp;</td>" }
  1270. $column_data{qty} = qq|<td align=right>|.$form->format_amount(\%myconfig, $ref->{qty}, "", "&nbsp;")."</td>";
  1271. $column_data{amount} = qq|<td align=right>|.$form->format_amount(\%myconfig, $ref->{qty} * $ref->{sellprice}, 2)."</td>";
  1272. $column_data{id} = "<td><a href=$form->{script}?action=edit&id=$ref->{id}&type=$form->{type}&path=$form->{path}&login=$form->{login}&sessionid=$form->{sessionid}&project=$form->{project}&callback=$callback>$ref->{id}</a></td>";
  1273. $total += ($ref->{qty} * $ref->{sellprice});
  1274. $j++; $j %= 2;
  1275. print qq|
  1276. <tr class=listrow$j>
  1277. |;
  1278. for (@column_index) { print "\n$column_data{$_}" }
  1279. print qq|
  1280. </tr>
  1281. |;
  1282. }
  1283. # print total
  1284. print qq|
  1285. <tr class=listtotal>
  1286. |;
  1287. for (@column_index) { $column_data{$_} = "<td>&nbsp;</td>" }
  1288. $column_data{amount} = qq|<th align=right>|.$form->format_amount(\%myconfig, $total, 2)."</th";
  1289. for (@column_index) { print "\n$column_data{$_}" }
  1290. if ($form->{project} eq 'job') {
  1291. if ($myconfig{acs} !~ /Production--Production/) {
  1292. $i = 1;
  1293. $button{'Production--Add Stores Card'}{code} = qq|<button class="submit" type="submit" name="action" value="add_stores_card">|.$locale->text('Add Stores Card').qq|</button> |;
  1294. $button{'Production--Add Stores Card'}{order} = $i++;
  1295. }
  1296. }
  1297. for (split /;/, $myconfig{acs}) { delete $button{$_} }
  1298. print qq|
  1299. </tr>
  1300. </table>
  1301. </td>
  1302. </tr>
  1303. <tr>
  1304. <td><hr size=3 noshade></td>
  1305. </tr>
  1306. </table>
  1307. <br>
  1308. <form method=post action=$form->{script}>
  1309. |;
  1310. $form->hide_form(qw(callback path login sessionid project));
  1311. foreach $item (sort { $a->{order} <=> $b->{order} } %button) {
  1312. print $item->{code};
  1313. }
  1314. if ($form->{lynx}) {
  1315. require "bin/menu.pl";
  1316. &menubar;
  1317. }
  1318. print qq|
  1319. </form>
  1320. </body>
  1321. </html>
  1322. |;
  1323. }
  1324. sub continue { &{ $form->{nextsub} } };
  1325. sub add_time_card {
  1326. $form->{type} = "timecard";
  1327. &add;
  1328. }
  1329. sub add_stores_card {
  1330. $form->{type} = "storescard";
  1331. &add;
  1332. }
  1333. sub print_options {
  1334. if ($form->{selectlanguage}) {
  1335. $form->{"selectlanguage"} = $form->unescape($form->{"selectlanguage"});
  1336. $form->{"selectlanguage"} =~ s/ selected//;
  1337. $form->{"selectlanguage"} =~ s/(<option value="\Q$form->{language_code}\E")/$1 selected/;
  1338. $lang = qq|<select name=language_code>$form->{selectlanguage}</select>
  1339. <input type=hidden name=selectlanguage value="|.
  1340. $form->escape($form->{selectlanguage},1).qq|">|;
  1341. }
  1342. $form->{selectformname} = $form->unescape($form->{selectformname});
  1343. $form->{selectformname} =~ s/ selected//;
  1344. $form->{selectformname} =~ s/(<option value="\Q$form->{formname}\E")/$1 selected/;
  1345. $type = qq|<select name=formname>$form->{selectformname}</select>
  1346. <input type=hidden name=selectformname value="|.$form->escape($form->{selectformname},1).qq|">|;
  1347. $media = qq|<select name=media>
  1348. <option value="screen">|.$locale->text('Screen');
  1349. $form->{selectformat} = qq|<option value="html">html\n|;
  1350. if (%{LedgerSMB::Sysconfig::printer} && ${LedgerSMB::Sysconfig::latex}) {
  1351. for (sort keys %{LedgerSMB::Sysconfig::printer}) { $media .= qq|
  1352. <option value="$_">$_| }
  1353. }
  1354. if (${LedgerSMB::Sysconfig::latex}) {
  1355. $media .= qq|
  1356. <option value="queue">|.$locale->text('Queue');
  1357. $form->{selectformat} .= qq|
  1358. <option value="postscript">|.$locale->text('Postscript').qq|
  1359. <option value="pdf">|.$locale->text('PDF');
  1360. }
  1361. $format = qq|<select name=format>$form->{selectformat}</select>|;
  1362. $format =~ s/(<option value="\Q$form->{format}\E")/$1 selected/;
  1363. $format .= qq|
  1364. <input type=hidden name=selectformat value="|.$form->escape($form->{selectformat},1).qq|">|;
  1365. $media .= qq|</select>|;
  1366. $media =~ s/(<option value="\Q$form->{media}\E")/$1 selected/;
  1367. print qq|
  1368. <table width=100%>
  1369. <tr>
  1370. <td>$type</td>
  1371. <td>$lang</td>
  1372. <td>$format</td>
  1373. <td>$media</td>
  1374. <td align=right width=90%>
  1375. |;
  1376. if ($form->{printed} =~ /$form->{formname}/) {
  1377. print $locale->text('Printed').qq|<br>|;
  1378. }
  1379. if ($form->{queued} =~ /$form->{formname}/) {
  1380. print $locale->text('Queued');
  1381. }
  1382. print qq|
  1383. </td>
  1384. </tr>
  1385. </table>
  1386. |;
  1387. }
  1388. sub print {
  1389. if ($form->{media} !~ /screen/) {
  1390. $form->error($locale->text('Select postscript or PDF!')) if $form->{format} !~ /(postscript|pdf)/;
  1391. $old_form = new Form;
  1392. for (keys %$form) { $old_form->{$_} = $form->{$_} }
  1393. }
  1394. &{ "print_$form->{formname}" }($old_form);
  1395. }
  1396. sub print_timecard {
  1397. my ($old_form) = @_;
  1398. $display_form = ($form->{display_form}) ? $form->{display_form} : "update";
  1399. $form->{description} =~ s/^\s+//g;
  1400. for (qw(partnumber projectnumber)) { $form->{$_} =~ s/--.*// }
  1401. @a = qw(hour min sec);
  1402. foreach $item (qw(in out)) {
  1403. for (@a) { $form->{"$item$_"} = substr(qq|00$form->{"$item$_"}|, -2) }
  1404. $form->{"checked$item"} = qq|$form->{"${item}hour"}:$form->{"${item}min"}:$form->{"${item}sec"}|;
  1405. }
  1406. @a = ();
  1407. for (qw(company address tel fax businessnumber)) { $form->{$_} = $myconfig{$_} }
  1408. $form->{address} =~ s/\\n/\n/g;
  1409. push @a, qw(partnumber description projectnumber projectdescription);
  1410. push @a, qw(company address tel fax businessnumber username useremail);
  1411. $form->format_string(@a);
  1412. $form->{total} = $form->format_amount(\%myconfig, $form->parse_amount(\%myconfig, $form->{qty}) * $form->parse_amount(\%myconfig, $form->{sellprice}), 2);
  1413. ($form->{employee}, $form->{employee_id}) = split /--/, $form->{employee};
  1414. $form->{templates} = "$myconfig{templates}";
  1415. $form->{IN} = "$form->{formname}.html";
  1416. if ($form->{format} =~ /(postscript|pdf)/) {
  1417. $form->{IN} =~ s/html$/tex/;
  1418. }
  1419. if ($form->{media} !~ /(screen|queue)/) {
  1420. $form->{OUT} = "${LedgerSMB::Sysconfig::printer}{$form->{media}}";
  1421. $form->{printmode} = '|-';
  1422. if ($form->{printed} !~ /$form->{formname}/) {
  1423. $form->{printed} .= " $form->{formname}";
  1424. $form->{printed} =~ s/^ //;
  1425. $form->update_status(\%myconfig);
  1426. }
  1427. %audittrail = ( tablename => jcitems,
  1428. reference => $form->{id},
  1429. formname => $form->{formname},
  1430. action => 'printed',
  1431. id => $form->{id} );
  1432. %status = ();
  1433. for (qw(printed queued audittrail)) { $status{$_} = $form->{$_} }
  1434. $status{audittrail} .= $form->audittrail("", \%myconfig, \%audittrail);
  1435. }
  1436. if ($form->{media} eq 'queue') {
  1437. %queued = split / /, $form->{queued};
  1438. if ($filename = $queued{$form->{formname}}) {
  1439. $form->{queued} =~ s/$form->{formname} $filename//;
  1440. unlink "${LedgerSMB::Sysconfig::spool}/$filename";
  1441. $filename =~ s/\..*$//g;
  1442. } else {
  1443. $filename = time;
  1444. $filename .= $$;
  1445. }
  1446. $filename .= ($form->{format} eq 'postscript') ? '.ps' : '.pdf';
  1447. $form->{OUT} = "${LedgerSMB::Sysconfig::spool}/$filename";
  1448. $form->{printmode} = '>';
  1449. $form->{queued} = "$form->{formname} $filename";
  1450. $form->update_status(\%myconfig);
  1451. %audittrail = ( tablename => jcitems,
  1452. reference => $form->{id},
  1453. formname => $form->{formname},
  1454. action => 'queued',
  1455. id => $form->{id} );
  1456. %status = ();
  1457. for (qw(printed queued audittrail)) { $status{$_} = $form->{$_} }
  1458. $status{audittrail} .= $form->audittrail("", \%myconfig, \%audittrail);
  1459. }
  1460. if (($form->{'media'} eq 'screen') and ($form->{'format'} eq 'html')) {
  1461. my $template = LedgerSMB::Template->new(\%myconfig, $form->{'formname'}, 'HTML');
  1462. try {
  1463. $template->render($form);
  1464. $form->header;
  1465. print $template->{'output'};
  1466. exit;
  1467. } catch Error::Simple with {
  1468. my $E = shift;
  1469. $form->error($E->stacktrace);
  1470. };
  1471. }
  1472. $form->parse_template(\%myconfig, ${LedgerSMB::Sysconfig::userspath});
  1473. if (defined %$old_form) {
  1474. for (keys %$old_form) { $form->{$_} = $old_form->{$_} }
  1475. for (qw(printed queued audittrail)) { $form->{$_} = $status{$_} }
  1476. &{ "$display_form" };
  1477. }
  1478. }