1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
2   "http://www.w3.org/TR/html4/loose.dtd">
3<?scm
4(let ((x 42)) ; only here to allow (define)s
5              ; i.e. to avoid "Bad define placement" error
6
7;; taxinvoice.eguile.scm  0.03
8;; GnuCash report template called from taxinvoice.scm 0.02
9;; (c) 2009 Chris Dennis chris@starsoftanalysis.co.uk
10;;  ©  2012 Dmitry Smirnov <onlyjob@member.fsf.org>
11;;
12;; $Author: chris $ $Date: 2009/07/23 10:42:08 $ $Revision: 1.33 $
13;; Modified by Dmitry Smirnov <onlyjob@member.fsf.org>  16 Feb 2012
14;;
15;; This file is a mixture of HTML and Guile --
16;; see eguile-gnc.scm for details.
17;;
18;; This program is free software; you can redistribute it and/or
19;; modify it under the terms of the GNU General Public License as
20;; published by the Free Software Foundation; either version 2 of the
21;; License, or (at your option) any later version.
22;;
23;; This program is distributed in the hope that it will be useful,
24;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26;; General Public License for more details.
27;;
28;; You should have received a copy of the GNU General Public License
29;; along with this program; if not, write to the Free Software
30;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
31;; 02111-1307 USA
32  (define (display-report opt-invoice)
33
34    (define (date<? s1 s2)
35      (< (xaccTransGetDate (xaccSplitGetParent s1))
36         (xaccTransGetDate (xaccSplitGetParent s2))))
37
38    ;; Main function that creates the tax invoice report
39    (let* (; invoice and company details
40           (invoiceid    (gncInvoiceGetID         opt-invoice))
41           (credit-note? (gncInvoiceGetIsCreditNote opt-invoice))
42           (book         (gncInvoiceGetBook       opt-invoice))
43           (isposted     (gncInvoiceIsPosted      opt-invoice))
44           (postdate     (gncInvoiceGetDatePosted opt-invoice))
45           (duedate      (gncInvoiceGetDateDue    opt-invoice))
46           (billingid    (gncInvoiceGetBillingID  opt-invoice))
47           (notes        (gncInvoiceGetNotes      opt-invoice))
48           (terms        (gncInvoiceGetTerms      opt-invoice))
49           (termsdesc    (gncBillTermGetDescription terms))
50           (lot          (gncInvoiceGetPostedLot  opt-invoice))
51           (txn          (gncInvoiceGetPostedTxn  opt-invoice))
52           (currency     (gncInvoiceGetCurrency   opt-invoice))
53           (entries      (gncInvoiceGetEntries    opt-invoice))
54           (splits       (sort (gnc-lot-get-split-list lot) date<?))
55           (dateformat   (gnc:options-fancy-date book))
56           (coyname      (gnc:company-info book gnc:*company-name*))
57           (coycontact   (gnc:company-info book gnc:*company-contact*))
58           (coyaddr      (gnc:company-info book gnc:*company-addy*))
59           (coyid        (gnc:company-info book gnc:*company-id*))
60           (coyphone     (gnc:company-info book gnc:*company-phone*))
61           (coyfax       (gnc:company-info book gnc:*company-fax*))
62           (coyurl       (gnc:company-info book gnc:*company-url*))
63           (coyemail     (gnc:company-info book gnc:*company-email*))
64           (owner        (gncInvoiceGetOwner  opt-invoice))
65           (owneraddr  (gnc:owner-get-address-dep owner))
66           (ownername  (gnc:owner-get-name-dep owner))
67           (jobnumber  (gncJobGetID (gncOwnerGetJob (gncInvoiceGetOwner  opt-invoice))))
68           (jobname    (gncJobGetName (gncOwnerGetJob (gncInvoiceGetOwner  opt-invoice))))
69           (billcontact  (gncAddressGetName (gnc:owner-get-address owner)))
70           (cust-doc? (eqv? (gncInvoiceGetType opt-invoice) GNC-INVOICE-CUST-INVOICE))
71           (reverse-payments? (not (gncInvoiceAmountPositive opt-invoice)))
72           ; flags and counters
73           (discount?  #f) ; any discounts on this invoice?
74           (tax?       #f) ; any taxable entries on this invoice?
75           (payments?  #f) ; have any payments been made on this invoice?
76           (units?     #f) ; does any row specify units?
77           (qty?       #f) ; does any row have qty <> 1?
78           (tbl_cols   0)) ; number of columns for 'colspan' attributes
79
80      ;; pre-scan invoice entries to look for discounts and taxes
81      (for-each
82       (lambda (entry)
83         (unless (string-null? (gncEntryGetAction entry)) (set! units? #t))
84         (unless (= 1 (gncEntryGetDocQuantity entry credit-note?)) (set! qty? #t))
85         (cond
86          (cust-doc?
87           (unless (zero? (gncEntryGetInvDiscount entry)) (set! discount? #t))
88           (unless (null? (gncEntryGetInvTaxTable entry)) (set! tax? #t)))
89          (else
90           (unless (null? (gncEntryGetBillTaxTable entry)) (set! tax? #t)))))
91       entries)
92
93      ;; pre-scan invoice splits to see if any payments have been made
94      (let lp ((splits splits))
95        (cond
96         ((null? splits) #f)
97         ((equal? (xaccSplitGetParent (car splits)) txn) (lp (cdr splits)))
98         (else (set! payments? #t))))
99?>
100
101<!-- ====================================================================== -->
102<!-- The HTML for the invoice starts here -->
103<html dir='auto'>
104<head>
105<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
106<title><?scm:d (G_ "Invoice") ?> <?scm:d invoiceid ?></title>
107
108<link rel="stylesheet" href="<?scm:d (make-file-url opt-css-file) ?>" type="text/css">
109<!-- Note that the external stylesheet file is overridden by this following: -->
110<style type="text/css">
111  body {
112    <?scm:d opt-text-font ?>
113  }
114  table { /* table does not inherit font */
115    <?scm:d opt-text-font ?>
116    <?scm:d opt-css-border-collapse ?>
117  }
118  table[border="1"] th {
119    border-color:<?scm:d opt-css-border-color-th ?>;
120  }
121  table[border="1"] td {
122    border-color:<?scm:d opt-css-border-color-td ?>;
123  }
124
125  h1.coyname {
126    <?scm:d opt-heading-font ?>
127  }
128  <?scm:d opt-extra-css ?>
129</style>
130
131</head>
132<body>
133
134<div class="main">
135
136<!-- company info -->
137<table class="coytable" border="0" width="100%">
138<tr valign="top" style="vertical-align: top">
139  <?scm (if (access? opt-logofile R_OK) (begin ?>
140    <td align="left">
141      <img align="left" src="<?scm:d (make-file-url opt-logofile) ?>" alt="logo" class="logo"
142        <?scm (if opt-logo-width (begin ?>
143          style="width: <?scm:d opt-logo-width ?>"
144        <?scm )) ?>
145        >
146    </td>
147  <?scm )) ?>
148  <td align="left">
149    <h1 class="coyname"><?scm:d (or coyname (G_ "Company Name")) ?></h1>
150  </td>
151  <td align="right"><h2 class="invoice"><?scm:d opt-report-title ?>
152    <?scm (if opt-invnum-next-to-title (begin ?><?scm:d (nbsp invoiceid) ?><?scm )) ?>
153  </h2></td>
154</tr>
155</table>
156<table border="0" width="100%">
157<tr valign="top">
158  <td align="left">
159    <?scm (if (and opt-row-address coyaddr) (begin ?>
160      <?scm:d (nl->br coyaddr) ?><br>
161    <?scm )) ?>
162    <?scm (if coyid (begin ?>
163      <strong><?scm:d coyid ?></strong><br>
164    <?scm )) ?>
165  </td>
166  <td align="right">
167    <table border="0">
168      <?scm (if (and opt-row-contact coycontact) (begin ?>
169        <tr>
170          <th colspan="2" align="right"><?scm:d coycontact ?></th>
171        </tr>
172      <?scm )) ?>
173      <?scm (if coyphone (begin ?>
174        <tr>
175          <td align="right"><?scm:d (G_ "Phone") ?>:&nbsp;</td>
176          <td align="right"><?scm:d coyphone ?></td>
177        </tr>
178      <?scm )) ?>
179      <?scm (if coyfax (begin ?>
180        <tr>
181          <td align="right"><?scm:d (G_ "Fax") ?>:&nbsp;</td>
182          <td align="right"><?scm:d coyfax ?></td>
183        </tr>
184      <?scm )) ?>
185      <?scm (if coyemail (begin ?>
186        <tr>
187          <td align="right"><?scm:d (G_ "Email") ?>:&nbsp;</td>
188          <td align="right"><?scm:d coyemail ?></td>
189        </tr>
190      <?scm )) ?>
191      <?scm (if coyurl (begin ?>
192        <tr>
193          <td align="right"><?scm:d (G_ "Website") ?>:&nbsp;</td>
194          <td align="right"><?scm:d coyurl ?></td>
195        </tr>
196      <?scm )) ?>
197    </table>
198</tr>
199</table>
200<hr>
201
202<table border="0" width="100%">
203<tr valign="top">
204  <!-- customer info -->
205  <th align="right" width="1%"><?scm:d opt-to-text ?></th>
206  <td align="left">
207    <?scm (if (and opt-row-company-name (not (string=? ownername ""))) (begin ?>
208        <?scm:d ownername ?><br>
209    <?scm )) ?>
210    <?scm (if (not (string=? owneraddr "")) (begin ?>
211      <?scm:d (nl->br owneraddr) ?>
212    <?scm )) ?>
213  </td>
214  <!-- invoice number etc. -->
215  <td align="right">
216    <table border="0">
217      <?scm (if opt-row-invoice-number (begin ?>
218      <tr>
219        <td align="right" class="invnum"><big><strong><?scm:d (nbsp opt-invoice-number-text) ?></strong></big></td>
220        <td align="right" class="invnum"><big><strong><?scm:d invoiceid ?></strong></big></td>
221      </tr>
222      <?scm )) ?>
223      <?scm (if (not isposted) (begin ?>
224        <tr>
225           <td colspan="2" align="right"><?scm:d (G_ "Invoice in progress...") ?></td>
226        </tr>
227      <?scm ) (begin ?>
228        <tr>
229           <td align="right"><?scm:d (nbsp (G_ "Invoice Date")) ?>:&nbsp;</td>
230           <td align="right"><?scm:d (nbsp (gnc-print-time64 postdate dateformat)) ?></td>
231        </tr>
232        <tr>
233           <td align="right"><?scm:d (nbsp (G_ "Due Date")) ?>:&nbsp;</td>
234           <td align="right"><?scm:d (nbsp (gnc-print-time64 duedate dateformat)) ?></td>
235        </tr> <?scm )) ?>
236        <?scm (if (not (string=? billingid "")) (begin ?>
237          <tr>
238            <td align="right"><?scm:d opt-ref-text ?></td>
239            <td align="right"><?scm:d billingid ?></td>
240          </tr>
241        <?scm )) ?>
242        <?scm (if (and opt-jobname-show (not (string=? jobname ""))) (begin ?>
243          <tr>
244            <td align="right"><?scm:d opt-jobname-text ?></td>
245            <td align="right"><?scm:d jobname ?></td>
246          </tr>
247        <?scm )) ?>
248        <?scm (if (and opt-jobnumber-show (not (string=? jobnumber ""))) (begin ?>
249          <tr>
250            <td align="right"><?scm:d opt-jobnumber-text ?></td>
251            <td align="right"><?scm:d jobnumber ?></td>
252          </tr>
253      <?scm )) ?>
254      <?scm (if (not (string=? termsdesc "")) (begin ?>
255        <tr><td colspan="2" align="right"><?scm:d termsdesc ?></td></tr>
256      <?scm )) ?>
257    </table>
258  </td>
259</tr>
260</table>
261
262<!-- invoice lines table -->
263<p>
264<table border="1" width="100%" cellpadding="4" class="entries">
265  <thead>
266    <tr bgcolor="#ccc" valign="bottom">
267      <?scm (if opt-col-date (begin ?>
268      <th align="center" ><?scm:d (G_ "Date") ?></th>
269      <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
270      <th align="left" width="80%"><?scm:d (G_ "Description") ?></th>
271      <?scm (if (and units? opt-col-units) (begin ?>
272        <th align="left"><?scm:d opt-units-heading ?></th>
273      <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
274      <?scm (if (or units? qty?) (begin ?>
275        <th align="right"><?scm:d opt-qty-heading ?></th>
276      <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
277      <?scm (if (or units? qty? discount?) (begin ?>
278        <th align="right"><?scm:d opt-unit-price-heading ?></th>
279      <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
280      <?scm (if discount? (begin ?>
281        <th align="right"><?scm:d opt-disc-rate-heading ?></th>
282        <th align="right"><?scm:d opt-disc-amount-heading ?></th>
283      <?scm (set! tbl_cols (+ tbl_cols 2)) )) ?>
284      <?scm (if tax? (begin ?>
285        <th align="right"><?scm:d opt-net-price-heading ?></th>
286        <?scm (set! tbl_cols (+ tbl_cols 1)) ?>
287        <?scm (if opt-col-taxrate (begin ?>
288        <th align="right"><?scm:d opt-tax-rate-heading ?></th>
289        <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
290        <th align="right"><?scm:d opt-tax-amount-heading ?></th>
291      <?scm (set! tbl_cols (+ tbl_cols 1)) )) ?>
292      <th align="right"><?scm:d opt-total-price-heading ?></th>
293    </tr>
294  </thead>
295
296  <tbody> <!-- display invoice entry lines, keeping running totals -->
297    <?scm
298      (let* ((inv-total (gncInvoiceGetTotal opt-invoice))
299             (tax-total (gncInvoiceGetTotalTax opt-invoice))
300             (sub-total (gncInvoiceGetTotalSubtotal opt-invoice))
301             (dsc-total (- inv-total tax-total sub-total))
302             (total-col (gnc:make-commodity-collector)))
303        (total-col 'add currency inv-total)
304        (for-each
305         (lambda (entry)
306            (let ((qty       (gncEntryGetDocQuantity entry credit-note?))
307                  (each      (gncEntryGetPrice entry cust-doc? opt-netprice))
308                  (action    (gncEntryGetAction entry))
309                  (rval      (gncEntryGetDocValue entry #t cust-doc? credit-note?))
310                  (rdiscval  (gncEntryGetDocDiscountValue entry #t cust-doc? credit-note?))
311                  (rtaxval   (gncEntryGetDocTaxValue entry #t cust-doc? credit-note?))
312                  (disc      (if cust-doc? (gncEntryGetInvDiscount entry)))
313                  (disctype  (gncEntryGetInvDiscountType entry))
314                  (acc       (if cust-doc? (gncEntryGetInvAccount entry)(gncEntryGetBillAccount entry)))
315                  (taxable   (if cust-doc? (gncEntryGetInvTaxable entry)(gncEntryGetBillTaxable entry)))
316                  (taxtable  (if cust-doc? (gncEntryGetInvTaxTable entry)(gncEntryGetBillTaxTable entry))))
317    ?>
318    <tr valign="top">
319      <?scm (if opt-col-date (begin ?>
320      <td align="center" ><?scm:d (nbsp (qof-print-date (gncEntryGetDate entry))) ?></td>
321      <?scm )) ?>
322      <td align="left"><?scm:d (gncEntryGetDescription entry) ?></td>
323      <!-- td align="left">< ?scm:d (gncEntryGetNotes entry) ?></td -->
324      <?scm (if opt-col-units (begin ?>
325      <?scm (if units? (begin ?>
326        <td align="left"><?scm:d action ?></td>
327      <?scm )) ?>
328      <?scm )) ?>
329      <?scm (if (or units? qty?) (begin ?>
330        <td align="right"><?scm:d (fmtnumeric qty) ?></td>
331      <?scm )) ?>
332      <?scm (if (or units? qty? discount?) (begin ?>
333        <td align="right"><?scm:d (fmtmoney currency each) ?></td>
334      <?scm )) ?>
335      <?scm (if discount? (begin ?>
336        <?scm (if (equal? disctype GNC-AMT-TYPE-VALUE) (begin ?>
337          <td align="right"><?scm:d (gnc:monetary->string (gnc:make-gnc-monetary currency disc)) ?></td>
338        <?scm ) (begin ?>
339          <td align="right"><?scm:d (fmtnumeric disc) ?>%</td>
340        <?scm )) ?>
341        <td align="right"><?scm:d (fmtmoney currency rdiscval) ?></td>
342      <?scm )) ?>
343      <?scm (if tax? (begin ?>
344        <td align="right"><?scm:d (fmtmoney currency rval) ?></td>
345        <?scm (if opt-col-taxrate (begin ?>
346        <td align="right"><?scm (taxrate taxable taxtable currency) ?></td>
347        <?scm )) ?>
348        <td align="right"><?scm:d (fmtmoney currency rtaxval) ?></td>
349      <?scm )) ?>
350      <!-- TO DO: need an option about whether to display the tax-inclusive total? -->
351      <td align="right"><?scm:d (fmtmoney currency (gnc-numeric-add rval rtaxval GNC-DENOM-AUTO GNC-RND-ROUND)) ?></td>
352    </tr>
353    <?scm ))
354         entries) ?>
355
356    <!-- subtotals row -->
357    <?scm (if (or tax? discount? payments?) (begin ?>
358      <tr valign="top">
359        <td align="left" class="subtotal" colspan="<?scm:d
360        (- tbl_cols (if (and tax? opt-col-taxrate) 1 0)
361                    (if tax? 1 -1)
362                    (if (and discount?) 1 0)
363        ) ?>"><strong><?scm:d opt-subtotal-heading ?></strong></td>
364        <?scm (if discount? (begin ?>
365        <td align="right" class="subtotal"><strong><?scm:d (fmtmoney currency dsc-total) ?></strong></td>
366        <?scm )) ?>
367        <?scm (if tax? (begin ?>
368          <td align="right" class="subtotal"><strong><?scm:d (fmtmoney currency sub-total) ?></strong></td>
369          <?scm (if opt-col-taxrate (begin ?>
370          <td>&nbsp;</td>
371          <?scm )) ?>
372          <td align="right" class="subtotal"><strong><?scm:d (fmtmoney currency tax-total) ?></strong></td>
373        <?scm )) ?>
374        <td align="right" class="subtotal"><strong><?scm:d (fmtmoney currency inv-total) ?></strong></td>
375      </tr>
376    <?scm )) ?>
377
378    <!-- payments row -->
379    <?scm
380      (when payments?
381        (for-each
382         (lambda (split)
383           (let ((t (xaccSplitGetParent split)))
384             (unless (equal? t txn) ; don't process the entry itself as a split ;'
385               (let ((c (xaccTransGetCurrency t))
386                     (a (if reverse-payments?
387                            (- (xaccSplitGetValue split))
388                            (xaccSplitGetValue split))))
389                 (total-col 'add c a)
390    ?>
391    <tr valign="top">
392      <?scm (when opt-col-date ?>
393      <td align="center"><?scm:d (qof-print-date (xaccTransGetDate t)) ?></td>
394      <?scm ) ?>
395      <td align="left" colspan="<?scm:d (+ tbl_cols (if opt-col-date 0 1)) ?>"><?scm:d opt-payment-recd-heading ?></td>
396      <td align="right"><?scm:d (fmtmoney c a) ?></td>
397    </tr>
398    <?scm ))))
399         splits)) ?>
400
401    <!-- total row -->
402    <tr valign="top">
403      <td align="left" class="total" colspan="<?scm:d (+ tbl_cols 1) ?>"><strong>
404        <?scm:d opt-amount-due-heading ?><?scm (if (not (string=? (gnc-commodity-get-mnemonic opt-invoice-currency) "")) (begin ?>,
405        <?scm:d (gnc-commodity-get-mnemonic opt-invoice-currency) ?><?scm )) ?></strong></td>
406      <td align="right" class="total"><strong><?scm (display-comm-coll-total total-col #f) ?></strong></td>
407    </tr>
408
409  </tbody>
410  <?scm ) ?> <!-- end of (let) surrounding table body -->
411</table>
412
413<p><?scm:d (nl->br notes) ?>
414<p><?scm:d (nl->br opt-extra-notes) ?>
415
416<?scm )) ; end of display-report function
417
418  ;; 'mainline' code: check for a valid invoice, then display the report
419
420
421  (cond
422   ((null? opt-invoice)
423    (display (string-append "<h2>" (G_ "Tax Invoice") "</h2>"))
424    (display (string-append "<p>" (G_ "No invoice has been selected -- please use the Options menu to select one.") "</p>")))
425
426   (else
427    (display-report opt-invoice)))
428
429?>
430</div>
431</body>
432</html>
433<?scm
434) ; end of enclosing let
435?>
436