Advertisement
Guest User

terra-invoice

a guest
Aug 2nd, 2012
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 34.00 KB | None | 0 0
  1. ;; -*-scheme-*-
  2. ;; fancy-invoice.scm -- a Fancy Invoice Report, used to print a GncInvoice
  3. ;;
  4. ;; Created by: Derek Atkins <warlord@MIT.EDU>
  5. ;; Copyright (c) 2003 Derek Atkins <warlord@MIT.EDU>
  6. ;;
  7. ;; This program is free software; you can redistribute it and/or
  8. ;; modify it under the terms of the GNU General Public License as
  9. ;; published by the Free Software Foundation; either version 2 of
  10. ;; the License, or (at your option) any later version.
  11. ;;
  12. ;; This program is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;;
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with this program; if not, contact:
  19. ;;
  20. ;; Free Software Foundation Voice: +1-617-542-5942
  21. ;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
  22. ;; Boston, MA 02110-1301, USA gnu@gnu.org
  23.  
  24.  
  25. ;; Fancy Invoice customized from "invoice.scm"
  26. ;; Customized by: Oliver Jones <gnucash at oliverstech dot com>
  27. ;;
  28. ;; WARNING: customizations are hard-coded, some translations might be
  29. ;; broken and it won't work for bills/expense vouchers
  30. ;;
  31. ;; Customizations are marked with "oli-custom".
  32. ;;
  33. ;; Hint: you may set your default options here until a way to save report
  34. ;; options will be implemented.
  35. ;;
  36. ;; You will need to upgrade to gtkhtml-1.1 for the latest features or
  37. ;; it won't look right. gtkhtml doesn't have support for table
  38. ;; colgroup, tbody, thead and rules tags yet. When it will, the
  39. ;; invoice will look even better.
  40. ;;
  41. ;; This is a quick and dirty hack. The proper way to do this (when I
  42. ;; or someone else will have time) is to have the user supply an HTML
  43. ;; template. The most common used templates will be distributed with
  44. ;; gnucash.
  45.  
  46. ;; Modifed to use settable options instead of the hard coded ones.
  47. ;; modified by Brian Dolbec <dol-sen at telus dot net> Feb. 6, 2006
  48.  
  49. (define-module (gnucash report Terra-Invoice))
  50.  
  51. (use-modules (srfi srfi-1))
  52. (use-modules (gnucash printf))
  53. (use-modules (gnucash gnc-module))
  54.  
  55. (gnc:module-load "gnucash/report/report-system" 0)
  56. (gnc:module-load "gnucash/business-utils" 0)
  57.  
  58. (use-modules (gnucash report standard-reports))
  59. (use-modules (gnucash report business-reports))
  60.  
  61. (define invoice-page gnc:pagename-general)
  62. (define invoice-name (N_ "Invoice Number"))
  63.  
  64. (define-macro (addto! alist element)
  65. `(set! ,alist (cons ,element ,alist)))
  66.  
  67. (define (set-last-row-style! table tag . rest)
  68. (let ((arg-list
  69. (cons table
  70. (cons (- (gnc:html-table-num-rows table) 1)
  71. (cons tag rest)))))
  72. (apply gnc:html-table-set-row-style! arg-list)))
  73.  
  74. (define (date-col columns-used)
  75. (vector-ref columns-used 0))
  76. (define (description-col columns-used)
  77. (vector-ref columns-used 1))
  78. (define (action-col columns-used)
  79. (vector-ref columns-used 2))
  80. (define (quantity-col columns-used)
  81. (vector-ref columns-used 3))
  82. (define (price-col columns-used)
  83. (vector-ref columns-used 4))
  84. (define (discount-col columns-used)
  85. (vector-ref columns-used 5))
  86. (define (tax-col columns-used)
  87. (vector-ref columns-used 6))
  88. (define (taxvalue-col columns-used)
  89. (vector-ref columns-used 7))
  90. (define (value-col columns-used)
  91. (vector-ref columns-used 8))
  92.  
  93. (define columns-used-size 9)
  94.  
  95. (define (num-columns-required columns-used)
  96. (do ((i 0 (+ i 1))
  97. (col-req 0 col-req))
  98. ((>= i columns-used-size) col-req)
  99. (if (vector-ref columns-used i)
  100. (set! col-req (+ col-req 1)))))
  101.  
  102. (define (build-column-used options)
  103. (define (opt-val section name)
  104. (gnc:option-value
  105. (gnc:lookup-option options section name)))
  106. (define (make-set-col col-vector)
  107. (let ((col 0))
  108. (lambda (used? index)
  109. (if used?
  110. (begin
  111. (vector-set! col-vector index col)
  112. (set! col (+ col 1)))
  113. (vector-set! col-vector index #f)))))
  114.  
  115. (let* ((col-vector (make-vector columns-used-size #f))
  116. (set-col (make-set-col col-vector)))
  117. (set-col (opt-val "Display Columns" "Date") 0)
  118. (set-col (opt-val "Display Columns" "Description") 1)
  119. (set-col (opt-val "Display Columns" "Action") 2)
  120. (set-col (opt-val "Display Columns" "Quantity") 3)
  121. (set-col (opt-val "Display Columns" "Price") 4)
  122. (set-col (opt-val "Display Columns" "Discount") 5)
  123. (set-col (opt-val "Display Columns" "Taxable") 6)
  124. (set-col (opt-val "Display Columns" "Tax Amount") 7)
  125. (set-col (opt-val "Display Columns" "Total") 8)
  126. col-vector))
  127.  
  128. (define (make-heading-list column-vector)
  129.  
  130. (let ((heading-list '()))
  131. (if (date-col column-vector)
  132. (addto! heading-list (_ "Date")))
  133. (if (description-col column-vector)
  134. (addto! heading-list (_ "Description")))
  135. (if (action-col column-vector)
  136. (addto! heading-list (_ "Charge Type")))
  137. (if (quantity-col column-vector)
  138. (addto! heading-list (_ "Quantity")))
  139. (if (price-col column-vector)
  140. (addto! heading-list (string-expand (_ "Unit Price") #\space "&nbsp;")))
  141. (if (discount-col column-vector)
  142. (addto! heading-list (_ "Discount")))
  143. (if (tax-col column-vector)
  144. (addto! heading-list (_ "Taxable")))
  145. (if (taxvalue-col column-vector)
  146. (addto! heading-list (_ "Tax Amount")))
  147. (if (value-col column-vector)
  148. (addto! heading-list (_ "Total")))
  149. (reverse heading-list)))
  150.  
  151. (define (make-account-hash) (make-hash-table 23))
  152.  
  153. (define (update-account-hash hash values)
  154. (for-each
  155. (lambda (item)
  156. (let* ((acct (car item))
  157. (val (cdr item))
  158. (ref (hash-ref hash acct)))
  159.  
  160. (hash-set! hash acct (if ref (gnc-numeric-add-fixed ref val) val))))
  161. values))
  162.  
  163.  
  164. (define (monetary-or-percent numeric currency entry-type)
  165. (if (gnc:entry-type-percent-p entry-type)
  166. ;; oli-custom - make a string instead of a table
  167. (string-append (gnc:default-html-gnc-numeric-renderer numeric #f) " " (_ "%"))
  168. (gnc:make-gnc-monetary currency numeric)))
  169.  
  170. (define (add-entry-row table currency entry column-vector row-style invoice?)
  171. (let* ((row-contents '())
  172. (entry-value (gnc:make-gnc-monetary
  173. currency
  174. (gncEntryReturnValue entry invoice?)))
  175. (entry-tax-value (gnc:make-gnc-monetary
  176. currency
  177. (gncEntryReturnTaxValue entry invoice?))))
  178.  
  179. (if (date-col column-vector)
  180. (addto! row-contents
  181. (gnc-print-date (gncEntryGetDate entry))))
  182.  
  183. (if (description-col column-vector)
  184. (addto! row-contents
  185. (gncEntryGetDescription entry)))
  186.  
  187. (if (action-col column-vector)
  188. (addto! row-contents
  189. (gncEntryGetAction entry)))
  190.  
  191. (if (quantity-col column-vector)
  192. (addto! row-contents
  193. (gnc:make-html-table-cell/markup
  194. "number-cell"
  195. (gncEntryGetQuantity entry))))
  196.  
  197. (if (price-col column-vector)
  198. (addto! row-contents
  199. (gnc:make-html-table-cell/markup
  200. "number-cell"
  201. (gnc:make-gnc-monetary
  202. currency (if invoice? (gncEntryGetInvPrice entry)
  203. (gncEntryGetBillPrice entry))))))
  204.  
  205. (if (discount-col column-vector)
  206. (addto! row-contents
  207. (if invoice?
  208. (gnc:make-html-table-cell/markup
  209. "number-cell"
  210. (monetary-or-percent (gncEntryGetInvDiscount entry)
  211. currency
  212. (gncEntryGetInvDiscountType entry)))
  213. "")))
  214.  
  215. (if (tax-col column-vector)
  216. (addto! row-contents
  217. (if (if invoice?
  218. (and (gncEntryGetInvTaxable entry)
  219. (gncEntryGetInvTaxTable entry))
  220. (and (gncEntryGetBillTaxable entry)
  221. (gncEntryGetBillTaxTable entry)))
  222. ;; Translators: This "T" is displayed in the taxable column, if this entry contains tax
  223. (_ (gncTaxTableGetName (gncEntryGetInvTaxTable entry))) "")))
  224. ;; (_ "T") "")))
  225.  
  226. (if (taxvalue-col column-vector)
  227. (addto! row-contents
  228. (gnc:make-html-table-cell/markup
  229. "number-cell"
  230. entry-tax-value)))
  231.  
  232. (if (value-col column-vector)
  233. (addto! row-contents
  234. (gnc:make-html-table-cell/markup
  235. "number-cell"
  236. entry-value)))
  237.  
  238. (gnc:html-table-append-row/markup! table row-style
  239. (reverse row-contents))
  240.  
  241. (cons entry-value entry-tax-value)))
  242.  
  243. ;; oli-custom - here you can set your default options
  244.  
  245. (define (options-generator)
  246.  
  247. (define gnc:*report-options* (gnc:new-options))
  248.  
  249. (define (gnc:register-inv-option new-option)
  250. (gnc:register-option gnc:*report-options* new-option))
  251.  
  252. (gnc:register-inv-option
  253. (gnc:make-invoice-option invoice-page invoice-name "x" ""
  254. (lambda () '()) #f))
  255.  
  256. (gnc:register-inv-option
  257. (gnc:make-string-option
  258. invoice-page (N_ "Custom Title")
  259. "z" (N_ "A custom string to replace Invoice, Bill or Expense Voucher")
  260. ""))
  261.  
  262. (gnc:register-inv-option
  263. (gnc:make-simple-boolean-option
  264. (N_ "Display Columns") (N_ "Date")
  265. "b" (N_ "Display the date?") #f))
  266.  
  267. (gnc:register-inv-option
  268. (gnc:make-simple-boolean-option
  269. (N_ "Display Columns") (N_ "Description")
  270. "d" (N_ "Display the description?") #t))
  271.  
  272. (gnc:register-inv-option
  273. (gnc:make-simple-boolean-option
  274. (N_ "Display Columns") (N_ "Action")
  275. "g" (N_ "Display the action?") #f))
  276.  
  277. (gnc:register-inv-option
  278. (gnc:make-simple-boolean-option
  279. (N_ "Display Columns") (N_ "Quantity")
  280. "ha" (N_ "Display the quantity of items?") #t))
  281.  
  282. (gnc:register-inv-option
  283. (gnc:make-simple-boolean-option
  284. (N_ "Display Columns") (N_ "Price")
  285. "hb" (N_ "Display the price per item?") #t))
  286.  
  287. (gnc:register-inv-option
  288. (gnc:make-simple-boolean-option
  289. (N_ "Display Columns") (N_ "Discount")
  290. "k" (N_ "Display the entry's discount") #f))
  291.  
  292. (gnc:register-inv-option
  293. (gnc:make-simple-boolean-option
  294. (N_ "Display Columns") (N_ "Taxable")
  295. "l" (N_ "Display the entry's taxable status") #t))
  296.  
  297. (gnc:register-inv-option
  298. (gnc:make-simple-boolean-option
  299. (N_ "Display Columns") (N_ "Tax Amount")
  300. "m" (N_ "Display each entry's total total tax") #f))
  301.  
  302. (gnc:register-inv-option
  303. (gnc:make-simple-boolean-option
  304. (N_ "Display Columns") (N_ "Total")
  305. "n" (N_ "Display the entry's value") #t))
  306.  
  307. (gnc:register-inv-option
  308. (gnc:make-simple-boolean-option
  309. (N_ "Display") (N_ "Individual Taxes")
  310. "o" (N_ "Display all the individual taxes?") #t))
  311.  
  312. (gnc:register-inv-option
  313. (gnc:make-simple-boolean-option
  314. (N_ "Display") (N_ "Totals")
  315. "p" (N_ "Display the totals?") #t))
  316.  
  317. (gnc:register-inv-option
  318. (gnc:make-simple-boolean-option
  319. (N_ "Display") (N_ "References")
  320. "s" (N_ "Display the invoice references?") #t))
  321.  
  322. (gnc:register-inv-option
  323. (gnc:make-simple-boolean-option
  324. (N_ "Display") (N_ "Billing Terms")
  325. "t" (N_ "Display the invoice billing terms?") #t))
  326.  
  327. (gnc:register-inv-option
  328. (gnc:make-simple-boolean-option
  329. (N_ "Display") (N_ "Billing ID")
  330. "ta" (N_ "Display the billing id?") #t))
  331.  
  332. (gnc:register-inv-option
  333. (gnc:make-simple-boolean-option
  334. (N_ "Display") (N_ "Invoice Notes")
  335. "tb" (N_ "Display the invoice notes?") #f))
  336.  
  337. (gnc:register-inv-option
  338. (gnc:make-simple-boolean-option
  339. (N_ "Display") (N_ "Payments")
  340. "tc" (N_ "Display the payments applied to this invoice?") #t)
  341.  
  342. (gnc:register-inv-option
  343. (gnc:make-number-range-option
  344. (N_ "Display") (N_ "Minimum # of entries")
  345. "u" (N_ "The minimum number of invoice entries to display. (-1)") 5
  346. 4 23 0 1))
  347.  
  348. (gnc:register-inv-option
  349. (gnc:make-text-option
  350. (N_ "Display") (N_ "Extra Notes")
  351. "u" (N_ "Extra notes to put on the invoice")
  352. (_ "Thank you for your patronage")))
  353.  
  354. (gnc:register-inv-option
  355. (gnc:make-complex-boolean-option
  356. (N_ "Display") (N_ "Payable to")
  357. "ua1" (N_ "Display the Payable to: information") #t #f
  358. (lambda (x) (gnc-option-db-set-option-selectable-by-name
  359. gnc:*report-options* "Display" "Payable to string" x))))
  360.  
  361. (gnc:register-inv-option
  362. (gnc:make-text-option
  363. (N_ "Display") (N_ "Payable to string")
  364. "ua2" (N_ "The phrase for specifying to whom payments should be made")
  365. (_ "Make all cheques Payable to")))
  366.  
  367. (gnc:register-inv-option
  368. (gnc:make-complex-boolean-option
  369. (N_ "Display") (N_ "Company contact")
  370. "ub1" (N_ "Display the Company contact information") #t #f
  371. (lambda (x) (gnc-option-db-set-option-selectable-by-name
  372. gnc:*report-options* "Display" "Company contact string" x))))
  373.  
  374. (gnc:register-inv-option
  375. (gnc:make-text-option
  376. (N_ "Display") (N_ "Company contact string")
  377. "ub2" (N_ "The phrase used to introduce the company contact")
  378. (_ "Direct all inquiries to")))
  379.  
  380. ; not used
  381. ; (gnc:register-inv-option
  382. ; (gnc:make-string-option
  383. ; (N_ "Display") (N_ "Today Date Format")
  384. ; "v" (N_ "The format for the date->string conversion for today's date.")
  385. ; (gnc-default-strftime-date-format)))
  386.  
  387. (gnc:options-set-default-section gnc:*report-options* "General")
  388.  
  389. gnc:*report-options*)
  390.  
  391.  
  392. (define (make-entry-table invoice options add-order invoice?)
  393. (define (opt-val section name)
  394. (gnc:option-value
  395. (gnc:lookup-option options section name)))
  396.  
  397. (let ((show-payments (opt-val "Display" "Payments"))
  398. (display-all-taxes (opt-val "Display" "Individual Taxes"))
  399. (lot (gncInvoiceGetPostedLot invoice))
  400. (txn (gncInvoiceGetPostedTxn invoice))
  401. (currency (gncInvoiceGetCurrency invoice))
  402. (entries-added 0))
  403.  
  404. (define (colspan monetary used-columns)
  405. (cond
  406. ((value-col used-columns) (value-col used-columns))
  407. ((taxvalue-col used-columns) (taxvalue-col used-columns))
  408. (else (price-col used-columns))))
  409.  
  410. (define (display-subtotal monetary used-columns)
  411. (if (value-col used-columns)
  412. monetary
  413. (let ((amt (gnc:gnc-monetary-amount monetary)))
  414. (if amt
  415. (if (gnc-numeric-negative-p amt)
  416. (gnc:monetary-neg monetary)
  417. monetary)
  418. monetary))))
  419.  
  420. (define (get-empty-row colcount)
  421. (define row-contents '())
  422. (do ((i 1 (+ i 1)))
  423. ((> i colcount))
  424. (addto! row-contents (gnc:make-html-table-cell)) ;;do stuff here
  425. )
  426. row-contents
  427. )
  428.  
  429. (define (add-subtotal-row table used-columns
  430. subtotal-collector subtotal-style subtotal-label)
  431. (let ((currency-totals (subtotal-collector
  432. 'format gnc:make-gnc-monetary #f)))
  433.  
  434. (for-each (lambda (currency)
  435. (gnc:html-table-append-row/markup!
  436. table
  437. subtotal-style
  438. ;; oli-custom modified to colspan the subtotal labels
  439. ;; instead of the data fields
  440. (append (cons (gnc:make-html-table-cell/size/markup
  441. 1 (colspan currency used-columns)
  442. "total-label-cell" subtotal-label)
  443. '())
  444. (list (gnc:make-html-table-cell/markup
  445. ;; 1 (colspan currency used-columns)
  446. "total-number-cell"
  447. (display-subtotal currency used-columns))))))
  448. currency-totals)))
  449.  
  450. (define (add-payment-row table used-columns split total-collector)
  451. (let* ((t (xaccSplitGetParent split))
  452. (currency (xaccTransGetCurrency t))
  453. (invoice (opt-val invoice-page invoice-name))
  454. (owner '())
  455. ;; XXX Need to know when to reverse the value
  456. (amt (gnc:make-gnc-monetary currency (xaccSplitGetValue split)))
  457. (payment-style "grand-total")
  458. (row '()))
  459.  
  460. ; Update to fix bug 564380, payment on bill doubles bill. Mike Evans <mikee@saxicola.co.uk>
  461. ;; Reverse the value when needed
  462. (if (not (null? invoice))
  463. (begin
  464. (set! owner (gncInvoiceGetOwner invoice))
  465. (let ((type (gncOwnerGetType
  466. (gncOwnerGetEndOwner owner))))
  467. (cond
  468. ((eqv? type GNC-OWNER-CUSTOMER)
  469. (total-collector 'add
  470. (gnc:gnc-monetary-commodity amt)
  471. (gnc:gnc-monetary-amount amt)))
  472. ((eqv? type GNC-OWNER-VENDOR)
  473. (total-collector 'add
  474. (gnc:gnc-monetary-commodity amt)
  475. (gnc:gnc-monetary-amount (gnc:monetary-neg amt))))
  476. ))))
  477.  
  478.  
  479. (if (date-col used-columns)
  480. (addto! row
  481. (gnc-print-date (gnc-transaction-get-date-posted t))))
  482.  
  483. (if (description-col used-columns)
  484. (addto! row (_ "Payment, thank you")))
  485.  
  486. (gnc:html-table-append-row/markup!
  487. table
  488. payment-style
  489. (append (reverse row)
  490. (list (gnc:make-html-table-cell/size/markup
  491. 1 (colspan currency used-columns)
  492. "total-number-cell"
  493. (display-subtotal amt used-columns)))))))
  494.  
  495. (define (do-rows-with-subtotals entries
  496. table
  497. used-columns
  498. width
  499. odd-row?
  500. value-collector
  501. tax-collector
  502. total-collector
  503. acct-hash)
  504. (if (null? entries)
  505. (begin
  506. ;; oli-custom - modified to have a minimum of entries per table,
  507. ;; currently defaults to 24
  508. ;; also, doesn't count payment rows and stuff
  509. (do ((entries-added entries-added (+ entries-added 1))
  510. (odd-row? odd-row? (not odd-row?)))
  511. ((> entries-added (opt-val "Display" "Minimum # of entries" )))
  512. (gnc:html-table-append-row/markup!
  513. table (if odd-row? "normal-row" "alternate-row")
  514. (get-empty-row (num-columns-required used-columns)))
  515. )
  516. (add-subtotal-row table used-columns value-collector
  517. "grand-total" (_ "Net Price"))
  518.  
  519. (if display-all-taxes
  520. (hash-for-each
  521. (lambda (acct value)
  522. (let ((collector (gnc:make-commodity-collector))
  523. (commodity (xaccAccountGetCommodity acct))
  524. (name (xaccAccountGetName acct)))
  525. (collector 'add commodity value)
  526. (add-subtotal-row table used-columns collector
  527. "grand-total" (string-expand
  528. name #\space "&nbsp;"))))
  529. acct-hash)
  530.  
  531. ; nope, just show the total tax.
  532. (add-subtotal-row table used-columns tax-collector
  533. "grand-total" (_ "Tax")))
  534.  
  535. (add-subtotal-row table used-columns total-collector
  536. "grand-total" (string-expand (_ "Total Price")
  537. #\space "&nbsp;"))
  538.  
  539. (if (and show-payments (not (null? lot)))
  540. (let ((splits (sort-list!
  541. (gnc-lot-get-split-list lot)
  542. (lambda (s1 s2)
  543. (let ((t1 (xaccSplitGetParent s1))
  544. (t2 (xaccSplitGetParent s2)))
  545. (< (xaccTransOrder t1 t2) 0))))))
  546. (for-each
  547. (lambda (split)
  548. (if (not (equal? (xaccSplitGetParent split) txn))
  549. (add-payment-row table used-columns
  550. split total-collector)))
  551. splits)))
  552.  
  553. (add-subtotal-row table used-columns total-collector
  554. "grand-total" (string-expand (_ "Amount Due")
  555. #\space "&nbsp;")))
  556.  
  557. ;;
  558. ;; End of BEGIN -- now here's the code to handle all the entries!
  559. ;;
  560. (let* ((current (car entries))
  561. (current-row-style (if odd-row? "normal-row" "alternate-row"))
  562. (rest (cdr entries))
  563. (next (if (null? rest) #f
  564. (car rest)))
  565. (entry-values (add-entry-row table
  566. currency
  567. current
  568. used-columns
  569. current-row-style
  570. invoice?)))
  571.  
  572. (if display-all-taxes
  573. (let ((tax-list (gncEntryReturnTaxValues current invoice?)))
  574. (update-account-hash acct-hash tax-list))
  575. (tax-collector 'add
  576. (gnc:gnc-monetary-commodity (cdr entry-values))
  577. (gnc:gnc-monetary-amount (cdr entry-values))))
  578.  
  579. (value-collector 'add
  580. (gnc:gnc-monetary-commodity (car entry-values))
  581. (gnc:gnc-monetary-amount (car entry-values)))
  582.  
  583. (total-collector 'add
  584. (gnc:gnc-monetary-commodity (car entry-values))
  585. (gnc:gnc-monetary-amount (car entry-values)))
  586. (total-collector 'add
  587. (gnc:gnc-monetary-commodity (cdr entry-values))
  588. (gnc:gnc-monetary-amount (cdr entry-values)))
  589.  
  590. (let ((order (gncEntryGetOrder current)))
  591. (if (not (null? order)) (add-order order)))
  592.  
  593. (set! entries-added (+ entries-added 1))
  594.  
  595. (do-rows-with-subtotals rest
  596. table
  597. used-columns
  598. width
  599. (not odd-row?)
  600. value-collector
  601. tax-collector
  602. total-collector
  603. acct-hash))))
  604.  
  605. (let* ((table (gnc:make-html-table))
  606. (used-columns (build-column-used options))
  607. (width (num-columns-required used-columns))
  608. (entries (gncInvoiceGetEntries invoice))
  609. (totals (gnc:make-commodity-collector)))
  610.  
  611. (gnc:html-table-set-col-headers!
  612. table
  613. (make-heading-list used-columns))
  614.  
  615. (do-rows-with-subtotals entries
  616. table
  617. used-columns
  618. width
  619. #t
  620. (gnc:make-commodity-collector)
  621. (gnc:make-commodity-collector)
  622. totals
  623. (make-account-hash))
  624. table)))
  625.  
  626. (define (string-expand string character replace-string)
  627. (define (car-line chars)
  628. (take-while (lambda (c) (not (eqv? c character))) chars))
  629. (define (cdr-line chars)
  630. (let ((rest (drop-while (lambda (c) (not (eqv? c character))) chars)))
  631. (if (null? rest)
  632. '()
  633. (cdr rest))))
  634. (define (line-helper chars)
  635. (if (null? chars)
  636. ""
  637. (let ((first (car-line chars))
  638. (rest (cdr-line chars)))
  639. (string-append (list->string first)
  640. (if (null? rest) "" replace-string)
  641. (line-helper rest)))))
  642. (line-helper (string->list string)))
  643.  
  644. (define (make-client-table owner orders)
  645. (let ((table (gnc:make-html-table))
  646. (name-cell (gnc:make-html-table-cell)))
  647. (gnc:html-table-set-style!
  648. table "table"
  649. 'attribute (list "border" 0)
  650. 'attribute (list "cellspacing" 0)
  651. 'attribute (list "cellpadding" 0))
  652. (gnc:html-table-cell-append-objects!
  653. name-cell (gnc:owner-get-name-dep owner))
  654. (gnc:html-table-cell-set-style!
  655. name-cell "td"
  656. 'font-size "+2")
  657. (gnc:html-table-append-row! table (list name-cell "" "")) ;;Bert: had a newline and a "<br>"
  658. (gnc:html-table-append-row!
  659. table
  660. (list
  661. (string-expand (gnc:owner-get-address-dep owner) #\newline "<br>")))
  662. (gnc:html-table-append-row!
  663. table
  664. (list "<br>"))
  665. (for-each
  666. (lambda (order)
  667. (let* ((reference (gncOrderGetReference order)))
  668. (if (and reference (> (string-length reference) 0))
  669. (gnc:html-table-append-row!
  670. table
  671. (list
  672. (string-append (_ "REF") ":&nbsp;" reference))))))
  673. orders)
  674. (set-last-row-style!
  675. table "td"
  676. 'attribute (list "valign" "top"))
  677. table))
  678.  
  679. (define (make-date-row! table label date)
  680. (gnc:html-table-append-row!
  681. table
  682. (list
  683. (string-append label ":&nbsp;")
  684. ;; oli-custom - modified to display a custom format
  685. ;; for the invoice date/due date fields
  686. ;; I could have taken the format from the report options, but... ;)
  687. (string-expand (strftime (gnc-default-strftime-date-format)
  688. (localtime (car date)))
  689. #\space "&nbsp;")
  690. ;;(string-expand (gnc-print-date date) #\space "&nbsp;")
  691. )))
  692.  
  693. (define (make-date-table)
  694. (let ((table (gnc:make-html-table)))
  695. (gnc:html-table-set-style!
  696. table "table"
  697. 'attribute (list "border" 0)
  698. 'attribute (list "cellpadding" 0))
  699. (set-last-row-style!
  700. table "td"
  701. 'attribute (list "valign" "top"))
  702. table))
  703.  
  704. (define (make-myname-table book date-format title)
  705. (let* ((table (gnc:make-html-table))
  706. (slots (qof-book-get-slots book))
  707. (name (kvp-frame-get-slot-path-gslist
  708. slots (append gnc:*kvp-option-path*
  709. (list gnc:*business-label* gnc:*company-name*))))
  710. ;; (contact (kvp-frame-get-slot-path-gslist
  711. ;; slots (append gnc:*kvp-option-path*
  712. ;; (list gnc:*business-label* gnc:*company-contact*))))
  713. (addy (kvp-frame-get-slot-path-gslist
  714. slots (append gnc:*kvp-option-path*
  715. (list gnc:*business-label* gnc:*company-addy*))))
  716. (id (kvp-frame-get-slot-path-gslist
  717. slots (append gnc:*kvp-option-path*
  718. (list gnc:*business-label* gnc:*company-id*))))
  719. (phone (kvp-frame-get-slot-path-gslist
  720. slots (append gnc:*kvp-option-path*
  721. (list gnc:*business-label* gnc:*company-phone*))))
  722. (fax (kvp-frame-get-slot-path-gslist
  723. slots (append gnc:*kvp-option-path*
  724. (list gnc:*business-label* gnc:*company-fax*))))
  725. (url (kvp-frame-get-slot-path-gslist
  726. slots (append gnc:*kvp-option-path*
  727. (list gnc:*business-label* gnc:*company-url*))))
  728. (invoice-cell (gnc:make-html-table-cell))
  729. (name-cell (gnc:make-html-table-cell))
  730.  
  731. )
  732. ;; oli-custom - modified the name table to increase the
  733. ;; font size of the company name
  734. ;; and add an "INVOICE" title to the upper right, also,
  735. ;; put some contact information in the middle
  736. ;; FIXME: "INVOICE" should be translated and support bills/expense vouchers
  737. (gnc:html-table-set-style!
  738. table "table"
  739. 'attribute (list "border" 0)
  740. 'attribute (list "cellspacing" 0)
  741. 'attribute (list "cellpadding" 0)
  742. 'attribute (list "width" "100%"))
  743. (gnc:html-table-cell-append-objects!
  744. invoice-cell title)
  745. (gnc:html-table-cell-set-style!
  746. invoice-cell "td"
  747. 'font-size "+2")
  748. (gnc:html-table-cell-append-objects!
  749. name-cell (if name name ""))
  750. (gnc:html-table-cell-set-style!
  751. name-cell "td"
  752. 'font-size "+2")
  753. (gnc:html-table-append-row! table (list name-cell (gnc:make-html-table-cell) invoice-cell)) ;;(gnc:make-html-table-cell) was ""
  754. (gnc:html-table-set-col-style!
  755. table 1 "td"
  756. 'attribute (list "align" "center")
  757. 'attribute (list "width" "33%"))
  758. (gnc:html-table-set-col-style!
  759. table 2 "td"
  760. 'attribute (list "align" "right")
  761. 'attribute (list "width" "33%"))
  762. (gnc:html-table-append-row!
  763. table (list (string-expand (string-append (if addy addy "") (if id (string-append "\n" id) "")) #\newline "<br>")
  764. (string-expand
  765. (string-append (if phone
  766. (string-append (_ "Phone:") " " phone)
  767. "")
  768. (if fax (string-append (if phone "\n" "")
  769. (_ "Fax:") " " fax)
  770. ""))
  771. #\newline "<br>" )
  772. (if url (string-append (_ "Web:") " " url) "")))
  773.  
  774. ;; oli-custom - I didn't want today's date on the invoice.
  775. ;; The invoice already has a date.
  776. ;; Today's date can be in the email, fax or letter accompanying the invoice.
  777. ;; (gnc:html-table-append-row! table (list
  778. ;; (strftime
  779. ;; date-format
  780. ;; (localtime (car (gnc:get-today))))))
  781. table))
  782.  
  783. (define (make-break! document)
  784. (gnc:html-document-add-object!
  785. document
  786. (gnc:make-html-text
  787. (gnc:html-markup-br))))
  788.  
  789. (define (reg-renderer report-obj)
  790. (define (opt-val section name)
  791. (gnc:option-value
  792. (gnc:lookup-option (gnc:report-options report-obj) section name)))
  793.  
  794. (define (title-string title custom-title)
  795. (if (not (equal? "" custom-title))
  796. (string-expand custom-title
  797. #\space "&nbsp;")
  798. title))
  799.  
  800. (let* ((document (gnc:make-html-document))
  801. (table '())
  802. (orders '())
  803. (invoice (opt-val invoice-page invoice-name))
  804. (owner '())
  805. (references? (opt-val "Display" "References"))
  806. (default-title (_ "Invoice"))
  807. (custom-title (opt-val invoice-page "Custom Title"))
  808. (invoice? #f))
  809.  
  810.  
  811. (define (add-order o)
  812. (if (and references? (not (member o orders)))
  813. (addto! orders o)))
  814.  
  815. (if (not (null? invoice))
  816. (begin
  817. (set! owner (gncInvoiceGetOwner invoice))
  818. (let ((type (gncOwnerGetType
  819. (gncOwnerGetEndOwner owner))))
  820. (cond
  821. ((eqv? type GNC-OWNER-CUSTOMER)
  822. (set! invoice? #t))
  823. ((eqv? type GNC-OWNER-VENDOR)
  824. (set! default-title (_ "Bill")))
  825. ((eqv? type GNC-OWNER-EMPLOYEE)
  826. (set! default-title (_ "Expense Voucher")))))
  827. ))
  828.  
  829. ;; oli-custom - title redundant, "Invoice" moved to myname-table,
  830. ;; invoice number moved below
  831. ;;(gnc:html-document-set-title! document title)
  832.  
  833.  
  834. (if (not (null? invoice))
  835. (let* ((book (gncInvoiceGetBook invoice))
  836. (slots (qof-book-get-slots book))
  837. (date-object #f)
  838. (helper-table (gnc:make-html-table))
  839. (title (title-string default-title custom-title)))
  840. (set! table (make-entry-table invoice
  841. (gnc:report-options report-obj)
  842. add-order invoice?))
  843.  
  844. (gnc:html-table-set-style!
  845. table "table"
  846. 'attribute (list "border" 1)
  847. 'attribute (list "cellspacing" 0)
  848. 'attribute (list "cellpadding" 4)
  849. ;; oli-custom - make table as wide as possible
  850. ;; works fine with simple style sheet templates,
  851. ;; doesn't work quite right with fancy ones
  852. ;; probably supplying the style sheet with a wide image
  853. ;; for the header (even if transparent/white) would fix it
  854. 'attribute (list "width" "100%"))
  855.  
  856. ;; oli-custom - make the description column big
  857. ;; 50% or 60%, depending on whether the first column is
  858. ;; displayed or not
  859. ;; should actually be something more complicated,
  860. ;; it's a really ugly hack right now :)
  861. (gnc:html-table-set-col-style!
  862. table (if (opt-val "Display Columns" "Date") 1 0) "td"
  863. 'attribute (list "width" (if (opt-val "Display Columns" "Date")
  864. "50%" "60%")))
  865.  
  866. (gnc:html-document-add-object!
  867. document (make-myname-table
  868. book ;;(opt-val "Display" "Today Date Format")))
  869. "" title))
  870.  
  871. (make-break! document)
  872. (make-break! document)
  873. (make-break! document)
  874.  
  875. ;; oli-custom - client table and table with invoice
  876. ;; number/date/due date both inserted into a table
  877. (gnc:html-table-set-style!
  878. helper-table "table"
  879. 'attribute (list "border" 0)
  880. 'attribute (list "cellspacing" 0)
  881. 'attribute (list "cellpadding" 0)
  882. 'attribute (list "width" "100%"))
  883.  
  884. (set! date-object (let ((date-table #f)
  885. (post-date (gncInvoiceGetDatePosted invoice))
  886. (due-date (gncInvoiceGetDateDue invoice)))
  887.  
  888. (if (not (equal? post-date (cons 0 0)))
  889. (begin
  890. (set! date-table (make-date-table))
  891. ;; oli-custom - moved invoice number here
  892. (gnc:html-table-append-row!
  893. date-table (list (sprintf #f (_ "%s&nbsp;#") title) (gncInvoiceGetID invoice)))
  894. ;; Translators: The first %s below is "Invoice" or
  895. ;; "Bill" or even the custom title from the
  896. ;; options. This string sucks for i18n, but I don't
  897. ;; have a better solution right now without breaking
  898. ;; other people's invoices.
  899. (make-date-row! date-table (sprintf #f (_ "%s&nbsp;Date") title) post-date)
  900. (make-date-row! date-table (_ "Due Date") due-date)
  901. date-table)
  902. (gnc:make-html-text
  903. ;; oli-custom - FIXME: I have a feeling I broke a
  904. ;; translation by not using string-expand for &nbsp;
  905. (string-append title "<br>" (_ "Invoice in progress..."))))))
  906.  
  907. (gnc:html-table-append-row!
  908. helper-table
  909. (list (make-client-table owner orders) date-object))
  910.  
  911. (gnc:html-table-set-col-style!
  912. helper-table 0 "td"
  913. 'attribute (list "valign" "top"))
  914.  
  915. (gnc:html-table-set-col-style!
  916. helper-table 1 "td"
  917. 'attribute (list "valign" "top")
  918. 'attribute (list "align" "right")
  919. ;; oli-custom - "squeeze" the date table,
  920. ;; or else it's spaced out
  921. 'attribute (list "width" "1%"))
  922.  
  923. (gnc:html-document-add-object!
  924. document
  925. helper-table)
  926.  
  927. (make-break! document)
  928.  
  929. (if (opt-val "Display" "Billing ID")
  930. (let ((billing-id (gncInvoiceGetBillingID invoice)))
  931. (if (and billing-id (> (string-length billing-id) 0))
  932. (begin
  933. (gnc:html-document-add-object!
  934. document
  935. (gnc:make-html-text
  936. (string-append
  937. (_ "Reference") ":&nbsp;"
  938. (string-expand billing-id #\newline "<br>"))))
  939. (make-break! document)))))
  940.  
  941. (if (opt-val "Display" "Billing Terms")
  942. (let* ((term (gncInvoiceGetTerms invoice))
  943. (terms (gncBillTermGetDescription term)))
  944. (if (and terms (> (string-length terms) 0))
  945. (gnc:html-document-add-object!
  946. document
  947. (gnc:make-html-text
  948. (string-append
  949. (_ "Terms") ":&nbsp;"
  950. (string-expand terms #\newline "<br>")))))))
  951.  
  952. (make-break! document)
  953.  
  954. (gnc:html-document-add-object! document table)
  955.  
  956. (make-break! document)
  957. (make-break! document)
  958.  
  959. (if (opt-val "Display" "Invoice Notes")
  960. (let ((notes (gncInvoiceGetNotes invoice)))
  961. (gnc:html-document-add-object!
  962. document
  963. (gnc:make-html-text
  964. (string-expand notes #\newline "<br>")))))
  965.  
  966. (make-break! document)
  967.  
  968. (if (opt-val "Display" "Payable to")
  969. (let* ((name (kvp-frame-get-slot-path-gslist
  970. slots (append gnc:*kvp-option-path*
  971. (list gnc:*business-label*
  972. gnc:*company-name*))))
  973. (name-str (opt-val "Display" "Payable to string")))
  974. (if (and name (> (string-length name) 0))
  975. (gnc:html-document-add-object!
  976. document
  977. (gnc:make-html-text
  978. (string-append name-str ":&nbsp;"
  979. (string-expand name #\newline "<br>")))))))
  980.  
  981. (make-break! document)
  982.  
  983. (if (opt-val "Display" "Company contact")
  984. (let* ((contact (kvp-frame-get-slot-path-gslist
  985. slots (append gnc:*kvp-option-path*
  986. (list gnc:*business-label*
  987. gnc:*company-contact*))))
  988. (contact-str (opt-val "Display" "Company contact string")))
  989. (if (and contact (> (string-length contact) 0))
  990. (gnc:html-document-add-object!
  991. document
  992. (gnc:make-html-text
  993. (string-append contact-str ":&nbsp;"
  994. (string-expand contact #\newline "<br>")))))))
  995.  
  996. (gnc:html-document-add-object!
  997. document
  998. (gnc:make-html-text
  999. (gnc:html-markup-br)
  1000. (string-expand (opt-val "Display" "Extra Notes") #\newline "<br>")
  1001. (gnc:html-markup-br))))
  1002.  
  1003. ; else
  1004. (gnc:html-document-add-object!
  1005. document
  1006. (gnc:make-html-text
  1007. (_ "No valid invoice selected. Click on the Options button and select the invoice to use."))))
  1008.  
  1009. document))
  1010.  
  1011. (define Terra-Invoice-guid "3ce293441e894423a2425d7a22dd1ac8")
  1012.  
  1013. (gnc:define-report
  1014. 'version 1
  1015. 'name (N_ "Terra Invoice")
  1016. 'report-guid Terra-Invoice-guid
  1017. ;; 'menu-path (list gnc:menuname-business-reports)
  1018. 'options-generator options-generator
  1019. 'renderer reg-renderer
  1020. 'in-menu? #t)
  1021.  
  1022. (define (gnc:fancy-invoice-report-create-internal invoice)
  1023. (let* ((options (gnc:make-report-options fancy-invoice-guid))
  1024. (invoice-op (gnc:lookup-option options invoice-page invoice-name)))
  1025.  
  1026. (gnc:option-set-value invoice-op invoice)
  1027. (gnc:make-report fancy-invoice-guid options)))
  1028.  
  1029. (export gnc:fancy-invoice-report-create-internal)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement