download

[projop@project-open-v34 tcl]$ cvs diff intranet-timesheet2-tasks-procs.tcl
Index: intranet-timesheet2-tasks-procs.tcl
===================================================================
RCS file: /home/cvsroot/intranet-timesheet2-tasks/tcl/intranet-timesheet2-tasks-procs.tcl,v
retrieving revision 1.83
diff -r1.83 intranet-timesheet2-tasks-procs.tcl

705c706,712
<     set table_footer_action "
---
>     # Handle Use Case: Freelancer can update task progress
>     if {[im_permission $user_id "edit_timesheet_task_completion"]} {
>       set write 1
>       set delete_drop_down_option ""
>     } else {
>       set delete_drop_down_option "


"
>     }
706a714
>     set table_footer_action "
716c724
<


---
>               $delete_drop_down_option
722a731
>
[projop@project-open-v34 tcl]$
[projop@project-open-v34 www]$ cvs diff task-action.tcl
Index: task-action.tcl
===================================================================
RCS file: /home/cvsroot/intranet-timesheet2-tasks/www/task-action.tcl,v
retrieving revision 1.19
diff -r1.19 task-action.tcl
37a38,41
>
> # Check if Freelancer is allowed to update task progress
> if {[im_permission $current_user_id "edit_timesheet_task_completion"]} {set write 1}
>
39,40c43,44
<     ad_return_complaint 1 "
  • [_ intranet-core.lt_You_have_insufficient_6]" < ad_script_abort --- > ad_return_complaint 1 "
  • [_ intranet-core.lt_You_have_insufficient_6]" > ad_script_abort 42a47 > [projop@project-open-v34 www]$
  • Since its not sure yet if Dynfield support will be included in V4.0 of ]project-open[ following the instructions on how to patch your system to get the feature as shown in above video.

    ----------------------------------------------------------------------------------
    a) Prepare
    ----------------------------------------------------------------------------------
    - Please note that the patch requires some ]po[/OpenACS developer knowledge
    - make sure you have installed the package “instranet-rest” is installed
    - Download files

    ———————————————————————————-
    b) Patch /web/projop/packages/intranet-dynfield/tcl/ intranet-dynfield-procs.tcl
    ———————————————————————————-

    The following lines have been added:

    Right on top of the function:

        upvar 1 ajax_post_data ajax_post_data_build
        set ajax_post_data ""

    and right after “im_dynfield::append_attribute_to_form” add the following code

            if { 0 != $field_cnt } {
                append ajax_post_data_build " + "
            }
            if { "date" == $widget } {
                append ajax_post_data_build "\"<$attribute_name>\""
                append ajax_post_data_build " + evalReturnValue('date', "
                append ajax_post_data_build " document.invoices_dynfield\['$attribute_name.year'\].value + \"-\" + document.invoices_dynfield\['$attribute_name.month'\].value + \"-\" + document.invoices_dynfield\['$attribute_name.day'\].value, "
                append ajax_post_data_build "'$required_p'"
                append ajax_post_data_build ") "
                append ajax_post_data_build " + \"</$attribute_name>\""
     
            } else {
                append ajax_post_data_build "\"<$attribute_name>\" + evalReturnValue('text', document.invoices_dynfield.$attribute_name.value, '$required_p') + \"</$attribute_name>\""
            }

    Following the patched function V3.5 (cvs branch 3-5-0-patches)

     
    ad_proc -public im_dynfield::append_attributes_to_form {
        {-object_subtype_id "" }
        -object_type:required
        -form_id:required
        {-object_id ""}
        {-search_p "0"}
        {-form_display_mode "edit" }
        {-advanced_filter_p 0}
        {-include_also_hard_coded_p 0 }
        {-page_url "default" }
        {-debug 0}
    } {
        Append intranet-dynfield attributes for object_type to an existing form.<p>
        @option object_type The object_type attributes you want to add to the form
        @option object_subtype_id Specifies the "subtype" of the objects (i.e. project_type_id)
        @option advanced_filter_p Tells us that the dynfields are used for an 
                "advanced filter" as oposed to a data form. Text fields dont make
                much sense here, so we'll skip them.
     
        @param include_also_hard_coded_p Should we include fields that are also hard
                coded in ]po[ screens?
     
        @param page_url
    		Serves to identify the page layout.
     
        @return Returns the number of added fields
     
        The code consists of two main parts:
        <ul>
        <li>Adding the the attributes to the forum and
        <li>Extracting the values of the attributes from a number of storage tables.
        </ul>
    } {
     
        upvar 1 ajax_post_data ajax_post_data_build
        set ajax_post_data ""
     
        if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: object_type=$object_type, object_id=$object_id" }
        set user_id [ad_get_user_id]
     
        # Does the specified layout page exist? Otherwise use "default".
        set page_url_exists_p [db_string exists "select count(*) from im_dynfield_layout_pages where object_type = :object_type and page_url = :page_url"]
        if {!$page_url_exists_p} { set page_url "default" }
        set form_page_url $page_url
     
        # Add a hidden "object_type" field to the form
        if {![template::element::exists $form_id "object_type"]} {
    	if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: creating object_type=$object_type" }
        	template::element create $form_id "object_type" \
        			    -datatype text \
        			    -widget hidden \
        			    -value  $object_type
        }
     
        # add a hidden object_id field to the form
        if {[exists_and_not_null object_id]} {
        	if {![template::element::exists $form_id "object_id"]} {
    	    if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: creating object_id=$object_id" }
    	    template::element create $form_id "object_id" \
    		-datatype integer \
    		-widget hidden \
    		-value  $object_id
        	}
        }
     
        # Get display mode per attribute and object_type_id
        set sql "
           select	m.attribute_id,
                    m.object_type_id as ot,
                    m.display_mode as dm
            from
                    im_dynfield_type_attribute_map m,
                    im_dynfield_attributes a,
                    acs_attributes aa
            where
                    m.attribute_id = a.attribute_id
                    and a.acs_attribute_id = aa.attribute_id
                    and aa.object_type = :object_type
        "
     
        # Default: Set all field to form's display mode
        set default_display_mode $form_display_mode
     
        db_foreach attribute_table_map $sql {
    	set key "$attribute_id.$ot"
    	set display_mode_hash($key) $dm
     
    	# Now we've got atleast one display mode configured:
    	# Set the default to "none", so that no field is shown
    	# except for the configured fields.
    	set default_display_mode "none"
     
    	if {$debug} { ns_log Notice "append_attributes_to_form: display_mode($key) <= $dm" }
        }
     
        # Disable the mechanism if the object_type_id hasn't been specified
        # (compatibility mode)
     
     
     
        if {"" == $object_subtype_id} { set default_display_mode "edit" }
     
        db_1row object_type_info "
            select
                    t.table_name as object_type_table_name,
                    t.id_column as object_type_id_column
            from
                    acs_object_types t
            where
                    t.object_type = :object_type
        "
     
        set extra_wheres [list "1=1"]
        if {$advanced_filter_p} {
    	lappend extra_wheres "aw.widget in (
    		'select', 'generic_sql', 
    		'im_category_tree', 'im_cost_center_tree',
    		'checkbox'
    	)"
        }
        set extra_where [join $extra_wheres "\n\t\tand "]
     
     
        # We need to exclude also_hard_coded_p fields for most forms
        # since a lot of meta-fields were added for the REST interface. 
        # Otherwise object creation will fail for most objects.
        set also_hard_coded_p_sql ""
        if {!$include_also_hard_coded_p} { 
    	set also_hard_coded_p_sql "and (also_hard_coded_p is NULL or also_hard_coded_p = 'f')" 
        } 
     
        set attributes_sql "
    	select *
    	from (
    		select
    			dl.*,
    			coalesce(dl.pos_y, 10000 + a.attribute_id) as pos_y_coalesce,
    			a.attribute_id,
    			aa.attribute_id as dynfield_attribute_id,
    			a.table_name as attribute_table_name,
    			tt.id_column as attribute_id_column,
    			a.attribute_name,
    			a.pretty_name,
    			a.datatype, 
    			case when a.min_n_values = 0 then 'f' else 't' end as required_p, 
    			a.default_value, 
    			aw.widget,
    			aw.parameters,
    			aw.storage_type_id,
    			im_category_from_id(aw.storage_type_id) as storage_type
    		from
    			im_dynfield_attributes aa
    			LEFT OUTER JOIN	(
    				select	* 
    				from	im_dynfield_layout 
    				where	page_url = :form_page_url
    			) dl ON (aa.attribute_id = dl.attribute_id),
    			im_dynfield_widgets aw,
    			acs_attributes a 
    			left outer join 
    				acs_object_type_tables tt 
    				on (tt.object_type = :object_type and tt.table_name = a.table_name)
    		where 
    			a.object_type = :object_type
    			and a.attribute_id = aa.acs_attribute_id
    			and aa.widget_name = aw.widget_name
    			and $extra_where
    			$also_hard_coded_p_sql
    		) t
    	order by
    		pos_y_coalesce
        "
     
        set field_cnt 0
        db_foreach attributes $attributes_sql {
     
    	# Check if the elements as disabled in the layout page
    	if {$page_url_exists_p && "" == $page_url} { continue }
     
    	# Check if the current user has the right to read and write on the dynfield
    	set read_p [im_object_permission \
    			-object_id $dynfield_attribute_id \
    			-user_id $user_id \
    			-privilege "read" \
    	]
    	set write_p [im_object_permission \
    			-object_id $dynfield_attribute_id \
    			-user_id $user_id \
    			-privilege "write" \
    	]
    	if {!$read_p} { continue }
     
    	set display_mode $default_display_mode
     
    	# object_subtype_id can be a list, so go through the list
    	# and take the highest one (none - display - edit).
    	foreach subtype_id $object_subtype_id {
    	    set key "$dynfield_attribute_id.$subtype_id"
    	    if {[info exists display_mode_hash($key)]} { 
    		switch $display_mode_hash($key) {
    		    edit { set display_mode "edit" }
    		    display { if {$display_mode == "none"} { set display_mode "display" } }
    		}
    	    }
    	}
     
    	if {"edit" == $display_mode && "display" == $form_display_mode}  {
                set display_mode $form_display_mode
            }
    	if {"edit" == $display_mode && !$write_p}  {
                set display_mode "display"
            }
     
    	if {"none" == $display_mode} { continue }
     
    	if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: attribute_name=$attribute_name, datatype=$datatype, widget=$widget, storage_type_id=$storage_type_id" }
     
    	# set optional all attributes if search mode
    	if {$search_p} { set required_p "f" }
     
    	# No help yet...
    	set help ""
     
    	im_dynfield::append_attribute_to_form \
    	    -attribute_name $attribute_name \
    	    -widget $widget \
    	    -form_id $form_id \
    	    -datatype $datatype \
    	    -display_mode $display_mode \
    	    -parameters $parameters \
    	    -required_p $required_p \
    	    -pretty_name $pretty_name \
    	    -help $help
     
            if { 0 != $field_cnt } {
                append ajax_post_data_build " + "
            }
            if { "date" == $widget } {
                append ajax_post_data_build "\"<$attribute_name>\""
                append ajax_post_data_build " + evalReturnValue('date', "
                append ajax_post_data_build " document.invoices_dynfield\['$attribute_name.year'\].value + \"-\" + document.invoices_dynfield\['$attribute_name.month'\].value + \"-\" + document.invoices_dynfield\['$attribute_name.day'\].value, "
                append ajax_post_data_build "'$required_p'"
                append ajax_post_data_build ") "
                append ajax_post_data_build " + \"</$attribute_name>\""
     
            } else {
                append ajax_post_data_build "\"<$attribute_name>\" + evalReturnValue('text', document.invoices_dynfield.$attribute_name.value, '$required_p') + \"</$attribute_name>\""
            }
     
    	incr field_cnt
     
        }	
     
        # That's all until here IF this is a new object. Otherwise, we'll need 
        # to retreive the object's values from several tables and from the multi-fields...
        #
        if { ![template::form is_request $form_id] } { return }
        if { ![info exists object_id]} { return }
     
     
        # Same loop as before...
        db_foreach attributes $attributes_sql {
     
    	# Check if the elements is disabled in the layout page
    	if {$page_url_exists_p && "" == $page_url} { continue }
     
    	# Check if the current user has the right to read the dynfield
    	if {![im_object_permission -object_id $dynfield_attribute_id -user_id $user_id]} { continue }
     
    	# Default display mode
    	set display_mode $default_display_mode
     
    	# object_subtype_id can be a list, so go through the list
    	# and take the highest one (none - display - edit).
    	foreach subtype_id $object_subtype_id {
    	    set key "$dynfield_attribute_id.$subtype_id"
    	    if {[info exists display_mode_hash($key)]} { 
    		switch $display_mode_hash($key) {
    		    edit { set display_mode "edit" }
    		    display { if {$display_mode == "none"} { set display_mode "display" } }
    		}
    	    }
    	}
     
    #        set key "$dynfield_attribute_id.$object_subtype_id"
    #        if {[info exists display_mode_hash($key)]} { set display_mode $display_mode_hash($key) }
     
    	# Don't show "none" fields...
    	if {"none" == $display_mode} { continue }
     
    	switch $storage_type {
    	    multimap {
     
    		# "MultiMaps" (select with multiple values) are stored in a separate
    		# "im_dynfield_attr_multi_value", because we can't store it like the
    		# other attributes directly inside the object's table.
    		if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: multipmap storage" }
    		template::element set_properties $form_id $attribute_name "multiple_p" "1"
    		set value_list [db_list get_multiple_values "
    			select	value 
    			from	im_dynfield_attr_multi_value
    			where	attribute_id = :dynfield_attribute_id
    				and object_id = :object_id
    		"]
    		template::element::set_values $form_id $attribute_name $value_list
     
    	    }
     
    	    date {
     
    		# ToDo: Remove this part. It's not used anymore. Dates are stored as
    		# values in YYYY-MM-DD format
    		if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: date storage" }
    		set value [template::util::date::get_property ansi [set $attribute_name]]
    		set value_list [split $value "-"]			
    		set value "[lindex $value_list 0] [lindex $value_list 1] [lindex $value_list 2]"
    		template::element::set_value $form_id $attribute_name $value
     
    	    }
     
    	    value - default {
     
    		# ToDo: slow. This piece issues N SQL statements, instead of constructing
    		# a single SQL and issuing it once. Causes performance problems at BaselKB
    		# for example.
    		if {$debug} { ns_log Notice "im_dynfield::append_attributes_to_form: value - default storage" }
    		set value [db_string get_single_value "
    		    select	$attribute_name
    		    from	$attribute_table_name
    		    where	$attribute_id_column = :object_id
    		" -default ""]
    		template::element::set_value $form_id $attribute_name $value
     
    	    }
    	}
        }
        return $field_cnt
    }

    ———————————————————————————-
    d) Patch /web/projop/packages/intranet-invoices/www/view.tcl
    ———————————————————————————-

    Relevant parts are the ones titled:

    # —————————————————————————————-
    # Check if there are Dynamic Fields of type date and localize them
    # —————————————————————————————-

    and

    # ———————————————————————
    # Dynfields
    # ———————————————————————

    Here’s the complete file /packages/intranet-invoices/www/view.tcl
    based on V3.5 – cvs branch: b3-5-0-patches:

    # /packages/intranet-invoices/www/view.tcl
    #
    # Copyright (C) 2003 - 2009 ]project-open[
    #
    # All rights reserved. Please check
    # http://www.project-open.com/license/ for details.
     
    ad_page_contract {
        View all the info about a specific project
     
        @param render_template_id specifies whether the invoice should be show
    	   in plain HTML format or formatted using an .adp template
        @param show_all_comments whether to show all comments
        @param send_to_user_as "html" or "pdf".
               Indicates that the content of the
               invoice should be rendered using the default template
               and sent to the default contact.
               The difficulty is that it's not sufficient just to redirect
               to a mail sending page, because it is only this page that 
               "knows" how to render an invoice. So in order to send the
               PDF we first need to redirect to this page, render the invoice
               and then redirect to the mail sending page.
     
        @author frank.bergmann@project-open.com
    } {
        { invoice_id:integer 0}
        { object_id:integer 0}
     
        { show_all_comments 0 }
        { render_template_id:integer 0 }
        { return_url "" }
        { send_to_user_as ""}
        { output_format "html" }
        { err_mess "" }
        { item_list_type:integer 0 }
    }
     
    # ---------------------------------------------------------------
    # Defaults & Security
    # ---------------------------------------------------------------
     
    # Get user parameters
    set user_id [ad_maybe_redirect_for_registration]
    set user_locale [lang::user::locale]
    set locale $user_locale
    set page_title ""
     
    # Security is defered after getting the invoice information
    # from the database, because the customer's users should
    # be able to see this invoice even if they don't have any
    # financial view permissions otherwise.
     
    if {0 == $invoice_id} {set invoice_id $object_id}
    if {0 == $invoice_id} {
        ad_return_complaint 1 "<li>[lang::message::lookup $locale intranet-invoices.lt_You_need_to_specify_a]"
        return
    }
     
    if {"" == $return_url} { set return_url [im_url_with_query] }
     
    set bgcolor(0) "class=invoiceroweven"
    set bgcolor(1) "class=invoicerowodd"
     
    set required_field "<font color=red size=+1><B>*</B></font>"
     
    # ---------------------------------------------------------------
    # Set default values from parameters
    # ---------------------------------------------------------------
     
    # Number formats
    set cur_format [im_l10n_sql_currency_format]
    set vat_format $cur_format
    set tax_format $cur_format
     
     
    # Rounding precision can be between 2 (USD,EUR, ...) and -5 (Old Turkish Lira, ...).
    set rounding_precision 2
    set rounding_factor [expr exp(log(10) * $rounding_precision)]
    set rf $rounding_factor
     
     
    # Default Currency
    set default_currency [ad_parameter -package_id [im_package_cost_id] "DefaultCurrency" "" "EUR"]
    set invoice_currency [db_string cur "select currency from im_costs where cost_id = :invoice_id" -default $default_currency]
    set rf 100
    catch {set rf [db_string rf "select rounding_factor from currency_codes where iso = :invoice_currency" -default 100]}
     
    # Show dynfields?
    set show_dynfield_tab_p [ad_parameter -package_id [im_package_invoices_id] "DynamicFieldSupport" "" "0"]
     
    # Where is the template found on the disk?
    set invoice_template_base_path [ad_parameter -package_id [im_package_invoices_id] InvoiceTemplatePathUnix "" "/tmp/templates/"]
     
    # Invoice Variants showing or not certain fields.
    # Please see the parameters for description.
    set discount_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceDiscountFieldP" "" 0]
    set surcharge_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceSurchargeFieldP" "" 0]
    set canned_note_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceCannedNoteP" "" 0]
    set show_qty_rate_p [ad_parameter -package_id [im_package_invoices_id] "InvoiceQuantityUnitRateEnabledP" "" 0]
    set show_our_project_nr [ad_parameter -package_id [im_package_invoices_id] "ShowInvoiceOurProjectNr" "" 1]
    set show_our_project_nr_first_column_p [ad_parameter -package_id [im_package_invoices_id] "ShowInvoiceOurProjectNrFirstColumnP" "" 1]
    set show_company_project_nr [ad_parameter -package_id [im_package_invoices_id] "ShowInvoiceCustomerProjectNr" "" 1]
    set show_leading_invoice_item_nr [ad_parameter -package_id [im_package_invoices_id] "ShowLeadingInvoiceItemNr" "" 0]
     
    # Show or not "our" and the "company" project nrs.
    set company_project_nr_exists [im_column_exists im_projects company_project_nr]
    set show_company_project_nr [expr $show_company_project_nr && $company_project_nr_exists]
     
     
    # Which report to show for timesheet invoices as the detailed list of hours
    set timesheet_report_url [ad_parameter -package_id [im_package_invoices_id] "TimesheetInvoiceReport" "" "/intranet-reporting/timesheet-invoice-hours.tcl"]
     
    # Check if (one of) the PDF converter(s) is installed
    set pdf_enabled_p [llength [info commands im_html2pdf]]
     
    # Unified Business Language?
    set ubl_enabled_p [llength [info commands im_ubl_invoice2xml]]
     
     
    # ---------------------------------------------------------------
    # Audit
    # ---------------------------------------------------------------
     
    # Check if the invoices was changed outside of ]po[...
    # Normally, the current values of the invoice should match
    # exactly the last registered audit version...
    im_audit -object_id $invoice_id -action pre_update
     
     
    # ---------------------------------------------------------------
    # Determine if it's an Invoice or a Bill
    # ---------------------------------------------------------------
     
    set cost_type_id [db_string cost_type_id "select cost_type_id from im_costs where cost_id = :invoice_id" -default 0]
     
    # Invoices and Quotes have a "Customer" fields.
    set invoice_or_quote_p [expr $cost_type_id == [im_cost_type_invoice] || $cost_type_id == [im_cost_type_quote] || $cost_type_id == [im_cost_type_delivery_note] || $cost_type_id == [im_cost_type_interco_quote] || $cost_type_id == [im_cost_type_interco_invoice]]
     
    # Vars for ADP (can't use the commands in ADP)
    set quote_cost_type_id [im_cost_type_quote]
    set delnote_cost_type_id [im_cost_type_delivery_note]
    set po_cost_type_id [im_cost_type_po]
    set invoice_cost_type_id [im_cost_type_invoice]
    set bill_cost_type_id [im_cost_type_bill]
     
    # Invoices and Bills have a "Payment Terms" field.
    set invoice_or_bill_p [expr $cost_type_id == [im_cost_type_invoice] || $cost_type_id == [im_cost_type_bill]]
     
    # CostType for "Generate Invoice from Quote" or "Generate Bill from PO"
    set target_cost_type_id ""
    set generation_blurb ""
    if {$cost_type_id == [im_cost_type_quote]} {
        set target_cost_type_id [im_cost_type_invoice]
        set generation_blurb "[lang::message::lookup $locale intranet-invoices.lt_Generate_Invoice_from]"
    }
    if {$cost_type_id == [im_cost_type_po]} {
        set target_cost_type_id [im_cost_type_bill]
        set generation_blurb "[lang::message::lookup $locale intranet-invoices.lt_Generate_Provider_Bil]"
    }
     
    if {$invoice_or_quote_p} {
        # A Customer document
        set customer_or_provider_join "and ci.customer_id = c.company_id"
        set provider_company "Customer"
    } else {
        # A provider document
        set customer_or_provider_join "and ci.provider_id = c.company_id"
        set provider_company "Provider"
    }
     
    if {!$invoice_or_quote_p} { set company_project_nr_exists 0}
     
     
    # Check if this is a timesheet invoice and enable the timesheet report link.
    # This links allows the user to extract a detailed list of included hours.
    set cost_object_type [db_string cost_object_type "select object_type from acs_objects where object_id = :invoice_id" -default ""]
    set timesheet_report_enabled_p 0
    if {"im_timesheet_invoice" == $cost_object_type} {
        if {$cost_type_id == [im_cost_type_invoice]} {
    	set timesheet_report_enabled_p 1
        }
    }
     
     
    # ---------------------------------------------------------------
    # Find out if the invoice is associated with a _single_ project
    # or with more then one project. Only in the case of exactly one
    # project we can access the "customer_project_nr" for the invoice.
    # ---------------------------------------------------------------
     
    set related_projects_sql "
            select distinct
    	   	r.object_id_one as project_id,
    		p.project_name,
    		p.project_nr,
    		p.parent_id,
    		trim(both p.company_project_nr) as customer_project_nr
    	from
    	        acs_rels r,
    		im_projects p
    	where
    		r.object_id_one = p.project_id
    	        and r.object_id_two = :invoice_id
    "
     
    set related_projects {}
    set related_project_nrs {}
    set related_project_names {}
    set related_customer_project_nrs {}
     
    set num_related_projects 0
    db_foreach related_projects $related_projects_sql {
        lappend related_projects $project_id
        if {"" != $project_nr} { 
    	lappend related_project_nrs $project_nr 
        }
        if {"" != $project_name} { 
    	lappend related_project_names $project_name 
        }
     
        # Check of the "customer project nr" of the superproject, as the PMs
        # are probably too lazy to maintain it in the subprojects...
        set cnt 0
        while {[string equal "" $customer_project_nr] && ![string equal "" $parent_id] && $cnt < 10} {
    	set customer_project_nr [db_string custpn "select company_project_nr from im_projects where project_id = :parent_id" -default ""]
    	set parent_id [db_string parentid "select parent_id from im_projects where project_id = :parent_id" -default ""]
    	incr cnt
        }
        if {"" != $customer_project_nr} { 
    	lappend related_customer_project_nrs $customer_project_nr 
        }
        incr num_related_projects
    }
     
    set rel_project_id 0
    if {1 == [llength $related_projects]} {
        set rel_project_id [lindex $related_projects 0]
    }
     
     
    # ---------------------------------------------------------------
    # Get everything about the "internal" company
    # ---------------------------------------------------------------
     
    db_1row internal_company_info "
    	select
    		c.company_name as internal_name,
    		c.company_path as internal_path,
    		c.vat_number as internal_vat_number,
    		c.site_concept as internal_web_site,
    		im_name_from_user_id(c.manager_id) as internal_manager_name,
    		im_email_from_user_id(c.manager_id) as internal_manager_email,
    		c.primary_contact_id as internal_primary_contact_id,
    		im_name_from_user_id(c.primary_contact_id) as internal_primary_contact_name,
    		im_email_from_user_id(c.primary_contact_id) as internal_primary_contact_email,
    		c.accounting_contact_id as internal_accounting_contact_id,
    		im_name_from_user_id(c.accounting_contact_id) as internal_accounting_contact_name,
    		im_email_from_user_id(c.accounting_contact_id) as internal_accounting_contact_email,
    		o.office_name as internal_office_name,
    		o.fax as internal_fax,
    		o.phone as internal_phone,
    		o.address_line1 as internal_address_line1,
    		o.address_line2 as internal_address_line2,
    		o.address_city as internal_city,
    		o.address_state as internal_state,
    		o.address_postal_code as internal_postal_code,
    		o.address_country_code as internal_country_code,
    		cou.country_name as internal_country_name,
    		paymeth.category_description as internal_payment_method_desc
    	from
    		im_companies c
    		LEFT OUTER JOIN im_offices o ON (c.main_office_id = o.office_id)
    		LEFT OUTER JOIN country_codes cou ON (o.address_country_code = iso)
    		LEFT OUTER JOIN im_categories paymeth ON (c.default_payment_method_id = paymeth.category_id)
    	where
    		c.company_path = 'internal'
    "
     
     
    # ---------------------------------------------------------------
    # Get everything about the invoice
    # ---------------------------------------------------------------
     
    set query "
    	select
    		c.*,
    		i.*,
    		ci.effective_date::date + ci.payment_days AS due_date,
    		ci.effective_date AS invoice_date,
    		ci.cost_status_id AS invoice_status_id,
    		ci.cost_type_id AS invoice_type_id,
    		ci.template_id AS invoice_template_id,
    		ci.*,
    		ci.note as cost_note,
    		ci.project_id as cost_project_id,
    		to_date(to_char(ci.effective_date, 'YYYY-MM-DD'), 'YYYY-MM-DD') + ci.payment_days as calculated_due_date,
    		im_cost_center_name_from_id(ci.cost_center_id) as cost_center_name,
    		im_category_from_id(ci.cost_status_id) as cost_status,
    		im_category_from_id(ci.cost_type_id) as cost_type, 
    		im_category_from_id(ci.template_id) as template
    	from
    		im_invoices i,
    		im_costs ci,
    	        im_companies c
    	where 
    		i.invoice_id=:invoice_id
    		and ci.cost_id = i.invoice_id
    		$customer_or_provider_join
    "
     
    if { ![db_0or1row invoice_info_query $query] } {
     
        # Check if there is a cost item with this ID and forward
        set cost_exists_p [db_string cost_ex "select count(*) from im_costs where cost_id = :invoice_id"]
        if {$cost_exists_p} { 
    	ad_returnredirect [export_vars -base "/intranet-cost/costs/new" {{form_mode display} {cost_id $invoice_id}}] 
        } else {
    	ad_return_complaint 1 "[lang::message::lookup $locale intranet-invoices.lt_Cant_find_the_documen]"
        }
        return
    }
     
    # ---------------------------------------------------------------
    # Get information about start- and end time of invoicing period
    # ---------------------------------------------------------------
     
    set invoice_period_start ""
    set invoice_period_end ""
    set timesheet_invoice_p 0
     
    set query "
    	select	ti.*,
    		1 as timesheet_invoice_p
    	from	im_timesheet_invoices ti
    	where 	ti.invoice_id = :invoice_id
    "
    catch { db_1row timesheet_invoice_info_query $query } err_msg
     
     
    # ---------------------------------------------------------------
    # Get everything about our "internal" Office -
    # identified as the "main_office_id" of the Internal company.
    # ---------------------------------------------------------------
     
    # ToDo: Isn't this included in the Internal company query above?
     
    set cost_type_mapped [string map {" " "_"} $cost_type]
    set cost_type_l10n [lang::message::lookup $locale intranet-invoices.$cost_type_mapped $cost_type]
     
    # Fallback for empty office_id: Main Office
    if {"" == $invoice_office_id} {
        set invoice_office_id $main_office_id
    }
     
    db_1row office_info_query "
    	select *
    	from im_offices
    	where office_id = :invoice_office_id
    "
     
     
    # ---------------------------------------------------------------
    # Get everything about the contact person.
    # ---------------------------------------------------------------
     
    # Use the "company_contact_id" of the invoices as the main contact.
    # Fallback to the accounting_contact_id and primary_contact_id
    # if not present.
    if {"" == $company_contact_id} { 
        set company_contact_id $accounting_contact_id
    }
    if {"" == $company_contact_id} { 
        set company_contact_id $primary_contact_id 
    }
    set org_company_contact_id $company_contact_id
     
    set company_contact_name ""
    set company_contact_email ""
    set company_contact_first_names ""
    set company_contact_last_name ""
     
    db_0or1row accounting_contact_info "
    	select
    		im_name_from_user_id(person_id) as company_contact_name,
    		im_email_from_user_id(person_id) as company_contact_email,
    		first_names as company_contact_first_names,
    		last_name as company_contact_last_name
    	from	persons
    	where	person_id = :company_contact_id
    "
     
    # Fields normally available from intranet-contacts.
    # Set these fields if contacts is not installed:
    if {![info exists salutation]} { set salutation "" }
    if {![info exists user_position]} { set user_position "" }
     
    # Get contact person's contact information
    set contact_person_work_phone ""
    set contact_person_work_fax ""
    set contact_person_email ""
    db_0or1row contact_info "
    	select
    		work_phone as contact_person_work_phone,
    		fax as contact_person_work_fax,
    		im_email_from_user_id(user_id) as contact_person_email
    	from
    		users_contact
    	where
    		user_id = :company_contact_id
    "
     
    # Set the email and name of the current user as internal contact
    db_1row accounting_contact_info "
        select
    	im_name_from_user_id(:user_id) as internal_contact_name,
    	im_email_from_user_id(:user_id) as internal_contact_email,
    	uc.work_phone as internal_contact_work_phone,
    	uc.home_phone as internal_contact_home_phone,
    	uc.cell_phone as internal_contact_cell_phone,
    	uc.fax as internal_contact_fax,
    	uc.wa_line1 as internal_contact_wa_line1,
    	uc.wa_line2 as internal_contact_wa_line2,
    	uc.wa_city as internal_contact_wa_city,
    	uc.wa_state as internal_contact_wa_state,
    	uc.wa_postal_code as internal_contact_wa_postal_code,
    	uc.wa_country_code as internal_contact_wa_country_code
        from
    	users u
    	LEFT OUTER JOIN users_contact uc ON (u.user_id = uc.user_id)
        where
    	u.user_id = :user_id
    "
     
     
    # ---------------------------------------------------------------
    # Determine the language of the template from the template name
    # ---------------------------------------------------------------
     
    set template_type ""
    if {0 != $render_template_id} {
     
        # Maintain compatibility with old convention "invoice-english.adp"
        # ToDo: Remove this compatibility with V4.0
        if {[regexp {english} $template]} { set locale en }
        if {[regexp {spanish} $template]} { set locale es }
        if {[regexp {german} $template]} { set locale de }
        if {[regexp {french} $template]} { set locale fr }
     
        # New convention, "invoice.en_US.adp"
        if {[regexp {(.*)\.([_a-zA-Z]*)\.([a-zA-Z][a-zA-Z][a-zA-Z])} $template match body loc template_type]} {
    	set locale $loc
        }
    }
     
    # Check if the given locale throws an error
    # Reset the locale to the default locale then
    if {[catch {
        lang::message::lookup $locale "dummy_text"
    } errmsg]} {
        set locale $user_locale
    }
     
    ns_log Notice "view.tcl: locale=$locale"
    ns_log Notice "view.tcl: template_type=$template_type"
     
    # ----------------------------------------------------------------------------------------
    # Check if there are Dynamic Fields of type date and localize them 
    # ----------------------------------------------------------------------------------------
     
    set date_fields [list]
    set column_sql "
            select  w.widget_name,
                    aa.attribute_name
            from    im_dynfield_widgets w,
                    im_dynfield_attributes a,
                    acs_attributes aa
            where   a.widget_name = w.widget_name and
                    a.acs_attribute_id = aa.attribute_id and
                    aa.object_type = 'im_invoice' and
                    w.widget_name = 'date'
    "
    db_foreach column_list_sql $column_sql {
        set y ${attribute_name}
        set z [lc_time_fmt [subst $${y}] "%x" $locale]
        set ${attribute_name} $z
    }
     
    # ---------------------------------------------------------------
    # OOoo ODT Function
    # Split the template into the outer template and the one for
    # formatting the invoice lines.
    # ---------------------------------------------------------------
     
     
    if {"odt" == $template_type} {
     
     
    #    ad_return_complaint 1 $date_qoute
     
        # Special ODT functionality: We need to parse the ODT template
        # in order to extract the table row that needs to be formatted
        # by the loop below.
     
        # ------------------------------------------------
        # Create a temporary directory for our contents
        set odt_tmp_path [ns_tmpnam]
        ns_log Notice "view.tcl: odt_tmp_path=$odt_tmp_path"
        ns_mkdir $odt_tmp_path
     
        # The document 
        set odt_zip "${odt_tmp_path}.odt"
        set odt_content "${odt_tmp_path}/content.xml"
        set odt_styles "${odt_tmp_path}/styles.xml"
     
        # ------------------------------------------------
        # Create a copy of the ODT
     
        # Determine the location of the template
        set invoice_template_path "$invoice_template_base_path/$template"
        ns_log Notice "view.tcl: invoice_template_path='$invoice_template_path'"
     
        # Create a copy of the template into the temporary dir
        ns_cp $invoice_template_path $odt_zip
     
        # Unzip the odt into the temorary directory
        exec unzip -d $odt_tmp_path $odt_zip 
     
        # ------------------------------------------------
        # Read the content.xml file
        set file [open $odt_content]
        fconfigure $file -encoding "utf-8"
        set odt_template_content [read $file]
        close $file
     
        # ------------------------------------------------
        # Search the <row> ...<cell>..</cell>.. </row> line
        # representing the part of the template that needs to
        # be repeated for every template.
     
        # Get the list of all "tables" in the document
        set odt_doc [dom parse $odt_template_content]
        set root [$odt_doc documentElement]
        set odt_table_nodes [$root selectNodes "//table:table"]
     
        # Search for the table that contains "@item_name_pretty"
        set odt_template_table_node ""
        foreach table_node $odt_table_nodes {
    	set table_as_list [$table_node asList]
    	if {[regexp {item_units_pretty} $table_as_list match]} { set odt_template_table_node $table_node }
        }
     
        # Deal with the the situation that we didn't find the line
        if {"" == $odt_template_table_node} {
    	ad_return_complaint 1 "
    		<b>Didn't find table including '@item_units_pretty'</b>:<br>
    		We have found a valid OOoo template at '$invoice_template_path'.
    		However, this template does not include a table with the value
    		above.
    	"
    	ad_script_abort
        }
     
        # Seach for the 2nd table:table-row tag
        set odt_table_rows_nodes [$odt_template_table_node selectNodes "//table:table-row"]
        set odt_template_row_node ""
        set odt_template_row_count 0
        foreach row_node $odt_table_rows_nodes {
    	set row_as_list [$row_node asList]
    	if {[regexp {item_units_pretty} $row_as_list match]} { set odt_template_row_node $row_node }
    	incr odt_template_row_count
        }
     
        if {"" == $odt_template_row_node} {
    	ad_return_complaint 1 "
    		<b>Didn't find row including '@item_units_pretty'</b>:<br>
    		We have found a valid OOoo template at '$invoice_template_path'.
    		However, this template does not include a row with the value
    		above.
    	"
    	ad_script_abort
        }
     
        # Convert the tDom tree into XML for rendering
        set odt_row_template_xml [$odt_template_row_node asXML]
     
    }
     
     
     
    # ---------------------------------------------------------------
    # Format Invoice date information according to locale
    # ---------------------------------------------------------------
     
    set invoice_date_pretty [lc_time_fmt $invoice_date "%x" $locale]
    set calculated_due_date_pretty [lc_time_fmt $calculated_due_date "%x" $locale]
     
    set invoice_period_start_pretty [lc_time_fmt $invoice_period_start "%x" $locale]
    set invoice_period_end_pretty [lc_time_fmt $invoice_period_end "%x" $locale]
     
     
    # ---------------------------------------------------------------
    # Get more about the invoice's project
    # ---------------------------------------------------------------
     
    # We give priority to the project specified in the cost item,
    # instead of associated projects.
    if {"" != $cost_project_id && 0 != $cost_project_id} {
        set rel_project_id $cost_project_id
    }
     
    set project_short_name_default [db_string short_name_default "select project_nr from im_projects where project_id=:rel_project_id" -default ""]
    set customer_project_nr_default ""
     
    if {$company_project_nr_exists && $rel_project_id} {
     
        db_0or1row project_info_query "
        	select
        		p.company_project_nr as customer_project_nr_default
        	from
        		im_projects p
        	where
        		p.project_id = :rel_project_id
        "
    }
     
    # ---------------------------------------------------------------
    # Check permissions
    # ---------------------------------------------------------------
     
    im_cost_permissions $user_id $invoice_id view read write admin
    if {!$read} {
        ad_return_complaint "[lang::message::lookup $locale intranet-invoices.lt_Insufficient_Privileg]" "
        <li>[lang::message::lookup $locale intranet-invoices.lt_You_have_insufficient_1]<BR>
        [lang::message::lookup $locale intranet-invoices.lt_Please_contact_your_s]"
        ad_script_abort
    }
     
    # ---------------------------------------------------------------
    # Page Title and Context Bar
    # ---------------------------------------------------------------
     
    set page_title [lang::message::lookup $locale intranet-invoices.One_cost_type]
    set context_bar [im_context_bar [list /intranet-invoices/ "[lang::message::lookup $locale intranet-invoices.Finance]"] $page_title]
     
     
    # ---------------------------------------------------------------
    #
    # ---------------------------------------------------------------
     
    set comp_id $company_id
    set query "
    select
            pm_cat.category as invoice_payment_method,
    	pm_cat.category_description as invoice_payment_method_desc
    from 
            im_categories pm_cat
    where
            pm_cat.category_id = :payment_method_id
    "
    if { ![db_0or1row category_info_query $query] } {
        set invoice_payment_method ""
        set invoice_payment_method_desc ""
    }
     
    set invoice_payment_method_key [lang::util::suggest_key $invoice_payment_method]
    set invoice_payment_method_l10n [lang::message::lookup $locale intranet-core.$invoice_payment_method_key $invoice_payment_method]
     
     
    # ---------------------------------------------------------------
    # Determine the country name and localize
    # ---------------------------------------------------------------
     
    set country_name ""
    if {"" != $address_country_code} {
        set query "
    	select	cc.country_name
    	from	country_codes cc
    	where	cc.iso = :address_country_code"
        if { ![db_0or1row country_info_query $query] } {
    	    set country_name $address_country_code
        }
        set country_name [lang::message::lookup $locale intranet-core.$country_name $country_name]
    }
     
    # ---------------------------------------------------------------
    # Update the amount paid for this cost_item
    # ---------------------------------------------------------------
     
    # This is redundant now - The same calculation is done
    # when adding/removing costs. However, there may be cases
    # with manually added costs. ToDo: Not very, very clean
    # solution.
    im_cost_update_payments $invoice_id
     
     
    # ---------------------------------------------------------------
    # Payments list
    # ---------------------------------------------------------------
     
    set payment_list_html ""
    if {[im_table_exists im_payments]} {
     
        set cost_id $invoice_id
        set payment_list_html "
    	<form action=payment-action method=post>
    	[export_form_vars cost_id return_url]
    	<table border=0 cellPadding=1 cellspacing=1>
            <tr>
              <td align=middle class=rowtitle colspan=3>
    	    [lang::message::lookup $locale intranet-invoices.Related_Payments]
    	  </td>
            </tr>"
     
        set payment_list_sql "
    select
    	p.*,
            to_char(p.received_date,'YYYY-MM-DD') as received_date_pretty,
    	im_category_from_id(p.payment_type_id) as payment_type
    from
    	im_payments p
    where
    	p.cost_id = :invoice_id
    "
     
        set payment_ctr 0
        db_foreach payment_list $payment_list_sql {
    	append payment_list_html "
            <tr $bgcolor([expr $payment_ctr % 2])>
              <td>
    	    <A href=/intranet-payments/view?payment_id=$payment_id>
    	      $received_date_pretty
     	    </A>
    	  </td>
              <td>
    	      $amount $currency
              </td>\n"
    	if {$write} {
    	    append payment_list_html "
                <td>
    	      <input type=checkbox name=payment_id value=$payment_id>
                </td>\n"
    	}
    	append payment_list_html "
            </tr>\n"
    	incr payment_ctr
        }
     
        if {!$payment_ctr} {
    	append payment_list_html "<tr class=roweven><td colspan=2 align=center><i>[lang::message::lookup $locale intranet-invoices.No_payments_found]</i></td></tr>\n"
        }
     
     
        if {$write} {
    	append payment_list_html "
            <tr $bgcolor([expr $payment_ctr % 2])>
              <td align=right colspan=3>
    	    <input type=submit name=add value=\"[lang::message::lookup $locale intranet-invoices.Add_a_Payment]\">
    	    <input type=submit name=del value=\"[lang::message::lookup $locale intranet-invoices.Del]\">
              </td>
            </tr>\n"
        }
        append payment_list_html "
    	</table>
            </form>\n"
    }
     
    # ---------------------------------------------------------------
    # 3. Select and format Invoice Items
    # ---------------------------------------------------------------
     
    set decoration_item_nr [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleItemNr" "" "align=center"]
    set decoration_description [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleDescription" "" "align=left"]
    set decoration_quantity [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleQuantity" "" "align=right"]
    set decoration_unit [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleUnit" "" "align=left"]
    set decoration_rate [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleRate" "" "align=right"]
    set decoration_po_number [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitlePoNumber" "" "align=center"]
    set decoration_our_ref [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleOurRef" "" "align=center"]
    set decoration_amount [ad_parameter -package_id [im_package_invoices_id] "InvoiceDecorationTitleAmount" "" "align=right"]
     
     
    # start formatting the list of sums with the header...
    set invoice_item_html "<tr align=center>\n"
     
    if {$show_our_project_nr && $show_leading_invoice_item_nr} {
        append invoice_item_html "
              <td class=rowtitle $decoration_item_nr>[lang::message::lookup $locale intranet-invoices.Line_no "#"]</td>
        "
    }
     
    append invoice_item_html "
              <td class=rowtitle $decoration_description>[lang::message::lookup $locale intranet-invoices.Description]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
    "
     
    if {$show_qty_rate_p} {
        append invoice_item_html "
              <td class=rowtitle $decoration_quantity>[lang::message::lookup $locale intranet-invoices.Qty]</td>
              <td class=rowtitle $decoration_unit>[lang::message::lookup $locale intranet-invoices.Unit]</td>
              <td class=rowtitle $decoration_rate>[lang::message::lookup $locale intranet-invoices.Rate]</td>
        "
    }
     
    if {$show_company_project_nr} {
        # Only if intranet-translation has added the field and param is set
        append invoice_item_html "
              <td class=rowtitle $decoration_po_number>[lang::message::lookup $locale intranet-invoices.Yr_Job__PO_No]</td>\n"
    }
     
    if {$show_our_project_nr} {
        # Only if intranet-translation has added the field and param is set
        append invoice_item_html "
              <td class=rowtitle $decoration_our_ref>[lang::message::lookup $locale intranet-invoices.Our_Ref]</td>
        "
    }
     
    append invoice_item_html "
              <td class=rowtitle $decoration_amount>[lang::message::lookup $locale intranet-invoices.Amount]</td>
            </tr>
    "
     
    set ctr 1
    	set colspan [expr 2 + 3*$show_qty_rate_p + 1*$show_company_project_nr + $show_our_project_nr]
     
    set oo_table_xml ""
     
     
    if { 0 == $item_list_type } {
    	db_foreach invoice_items {} {
    	    # $company_project_nr is normally related to each invoice item,
    	    # because invoice items can be created based on different projects.
    	    # However, frequently we only have one project per invoice, so that
    	    # we can use this project's company_project_nr as a default
    	    if {$company_project_nr_exists && "" == $company_project_nr} { 
    		set company_project_nr $customer_project_nr_default
    	    }
    	    if {"" == $project_short_name} { 
    		set project_short_name $project_short_name_default
    	    }
     
    	    set amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $amount+0] $rounding_precision] "" $locale]
    	    set item_units_pretty [lc_numeric [expr $item_units+0] "" $locale]
    	    set price_per_unit_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $price_per_unit+0] $rounding_precision] "" $locale]
     
    	    append invoice_item_html "
    		<tr $bgcolor([expr $ctr % 2])>
    	    "
     
    	    if {$show_leading_invoice_item_nr} {
    	        append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2]) align=right>$sort_order</td>\n"
    	    }
     
    	    append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2])>$item_name</td>
    	    "
    	    if {$show_qty_rate_p} {
    	        append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2]) align=right>$item_units_pretty</td>
    	          <td $bgcolor([expr $ctr % 2]) align=left>[lang::message::lookup $locale intranet-core.$item_uom $item_uom]</td>
    	          <td $bgcolor([expr $ctr % 2]) align=right>$price_per_unit_pretty&nbsp;$currency</td>
    	        "
    	    }
     
    	    if {$show_company_project_nr} {
    		# Only if intranet-translation has added the field
    		append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2]) align=left>$company_project_nr</td>\n"
    	    }
     
    	    if {$show_our_project_nr} {
    		append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2]) align=left>$project_short_name</td>\n"
    	    }
     
    	    append invoice_item_html "
    	          <td $bgcolor([expr $ctr % 2]) align=right>$amount_pretty&nbsp;$currency</td>
    		</tr>"
     
    	    # Insert a new XML table row into OpenOffice document
    	    if {"odt" == $template_type} {
     
    		# Replace placeholders in the OpenOffice template row with values
    		eval [template::adp_compile -string $odt_row_template_xml]
    		set odt_row_xml $__adp_output
     
    		# Parse the new row and insert into OOoo document
    		set row_doc [dom parse $odt_row_xml]
    		set new_row [$row_doc documentElement]
    		$odt_template_table_node insertBefore $new_row $odt_template_row_node
     
    	    }
     
    	    incr ctr
    	}
    } else {
     
    	set indent_level [db_string get_view_id "
    			select 
    				tree_level(children.tree_sortkey) - tree_level(parent.tree_sortkey) as level
    		 	from
    				im_projects parent,
    				im_projects children
    			where
    				children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) and
    				children.project_id in (select task_id from im_invoice_items where invoice_id=$invoice_id)
    			order by 
    				level DESC
    			limit 1
    	" -default 0]
     
    	set invoice_items_sql "
    		select 
    			all_items.*,
    			im_category_from_id(item_type_id) as item_type,
    			im_category_from_id(item_uom_id) as item_uom,
    			round(price_per_unit * item_units * $rf) / $rf as amount,
    			to_char(round(price_per_unit * item_units * $rf) / $rf, '$cur_format' ) as amount_formatted
    		from 
    			(
    			select
    				parent.project_id as parent_id,
    				parent.project_nr as parent_nr,
    				parent.project_name as parent_name,
    				children.project_id,
    				children.project_nr,
    				children.project_name,
    				tree_level(children.tree_sortkey) - tree_level(parent.tree_sortkey) as level,
    				t.task_id,
    				(select item_units from im_invoice_items i where (t.task_id = i.task_id and i.invoice_id=$invoice_id)) as item_units,
    				(select item_type_id from im_invoice_items i where (t.task_id = i.task_id and i.invoice_id=$invoice_id)) as item_type_id,
    				(select i.item_uom_id from im_invoice_items i where (t.task_id = i.task_id and i.invoice_id=$invoice_id)) as item_uom_id,
    				(select i.price_per_unit from im_invoice_items i where (t.task_id = i.task_id and i.invoice_id=$invoice_id)) as price_per_unit,
    				parent.tree_sortkey as parent_tree_sortkey,
    				children.tree_sortkey as children_tree_sortkey
    		 	from
    				im_projects parent,
    				im_projects children
    				LEFT OUTER JOIN im_timesheet_tasks t ON (children.project_id = t.task_id)
    			where
    				children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey) and
    				children.project_id in (select task_id from im_invoice_items where invoice_id=$invoice_id)
    			UNION 
    			select 
    				0 as parent_id,
    				'' as parent_nr,
    				item_name as parent_name,
    				0 as project_id,
    				'' as project_nr,
    				item_name as project_name,
    				0 as level,
    				task_id,
    				item_units,
    				item_type_id,
    				item_uom_id,
    				price_per_unit,
    				'1111111111111111111111111111111111111' as parent_tree_sortkey,
    				'1111111111111111111111111111111111111' as children_tree_sortkey
    			from 
    				im_invoice_items
    			where  
    				invoice_id=30822 and 
    				task_id=-1
    			) all_items
     
    		ORDER BY 
    			parent_tree_sortkey,
    			children_tree_sortkey,
    			project_id;
    	"
     
    	set old_parent_id -1
    	set amount_sub_total 0
    	db_foreach related_projects $invoice_items_sql {
    		# if {"" == $material_name} { set material_name $default_material_name }
       		if { ("0"!=$ctr && $old_parent_id!=$parent_id && "0"!=$level && 0!=$amount_sub_total) || "-1"==$task_id } {
    			 if { "NULL"!=$task_id } {
    	    			append invoice_item_html "
    					<tr><td class='invoiceroweven' colspan ='100' align='right'>
    					[lc_numeric [im_numeric_add_trailing_zeros [expr $amount_sub_total+0] $rounding_precision] "" $locale]&nbsp;$currency</td></tr>
    				"
    				set amount_sub_total 0    		
    			} else {
                                    append invoice_item_html "<tr><td>[lang::message::lookup $locale intranet-timesheet2-invoices.No_Information]</td></tr>"
    			}
       		}
    		set indent ""
    		set indent_level_item [expr $indent_level - $level]  
    		for {set i 0} {$i < $indent_level_item} {incr i} { 
    		    	append indent "&nbsp;&nbsp;" 
    		}
    		# this items is not related to a task; it has been created as part of the financial document
    		if { "-1" == $task_id } { 
    			set indent ""
    		}
    		# insert headers for every project
    		if { $old_parent_id != $parent_id } {
    	    	if { 0 != $level } {     	
    		    		append invoice_item_html "<tr><td class='invoiceroweven'>$indent$parent_name </td></tr>"
    		    		set old_parent_id $parent_id
    				} else {
    				    set amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $amount+0] $rounding_precision] "" $locale]
    			    	set item_units_pretty [lc_numeric [expr $item_units+0] "" $locale]
    		    		set price_per_unit_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $price_per_unit+0] $rounding_precision] "" $locale]
    				append invoice_item_html "<tr>" 
    				append invoice_item_html "<td class='invoiceroweven'>$indent$parent_name</td>" 
    				if {$show_qty_rate_p} {
    					append invoice_item_html "
    					<td $bgcolor([expr $ctr % 2]) align=right>$item_units_pretty</td>
    					<td $bgcolor([expr $ctr % 2]) align=left>[lang::message::lookup $locale intranet-core.$item_uom $item_uom]</td>
    					<td $bgcolor([expr $ctr % 2]) align=right>$price_per_unit_pretty&nbsp;$currency</td>
    		       			"
    				}
    				if {$show_company_project_nr} {
    					# Only if intranet-translation has added the field
    					# append invoice_item_html "<td align=left>$company_project_nr</td>\n"
    		    		}
    				if {$show_our_project_nr} {
    					append invoice_item_html "
    					<td $bgcolor([expr $ctr % 2]) align=left>$project_short_name</td>\n"
    		    		}
    				append invoice_item_html "<td $bgcolor([expr $ctr % 2]) align=right>$amount_pretty&nbsp;$currency</td></tr>"
    					set amount_sub_total [expr $amount_sub_total + $amount]				
    				}
    		}
    	    incr ctr
    	} if_no_rows {
    		append invoice_item_html "<tr><td>[lang::message::lookup $locale intranet-timesheet2-invoices.No_Information]</td></tr>"
        	}
    	append invoice_item_html "<tr><td class='invoiceroweven' colspan ='100' align='right'>[lc_numeric [im_numeric_add_trailing_zeros [expr $amount_sub_total+0] $rounding_precision] "" $locale]&nbsp;$currency</td></tr>"
    }
     
     
    # ---------------------------------------------------------------
    # Add subtotal + VAT + TAX = Grand Total
    # ---------------------------------------------------------------
     
     
    # Set these values to 0 in order to allow to calculate the
    # formatted grand total
    if {"" == $vat} { set vat 0}
    if {"" == $tax} { set tax 0}
     
    # Calculate grand total based on the same inner SQL
    db_1row calc_grand_total ""
     
    set subtotal_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $subtotal+0] $rounding_precision] "" $locale]
    set vat_amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $vat_amount+0] $rounding_precision] "" $locale]
    set tax_amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $tax_amount+0] $rounding_precision] "" $locale]
     
    set vat_perc_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $vat+0] $rounding_precision] "" $locale]
    set tax_perc_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $tax+0] $rounding_precision] "" $locale]
     
     
    set grand_total_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $grand_total+0] $rounding_precision] "" $locale]
    set total_due_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $total_due+0] $rounding_precision] "" $locale]
    set discount_perc_pretty $discount_perc
    set surcharge_perc_pretty $surcharge_perc
     
    set discount_amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $discount_amount+0] $rounding_precision] "" $locale]
    set surcharge_amount_pretty [lc_numeric [im_numeric_add_trailing_zeros [expr $surcharge_amount+0] $rounding_precision] "" $locale]
     
    set colspan_sub [expr $colspan - 1]
     
    # Add a subtotal
    set subtotal_item_html "
            <tr> 
              <td class=roweven colspan=$colspan_sub align=right><B>[lang::message::lookup $locale intranet-invoices.Subtotal]</B></td>
              <td class=roweven align=right><B><nobr>$subtotal_pretty $currency</nobr></B></td>
            </tr>
    "
     
    # Discount
    if {$discount_enabled_p && 0 != $discount_perc} {
        append subtotal_item_html "
            <tr> 
    <!--          <td class=roweven colspan=$colspan_sub align=right>[lang::message::lookup $locale intranet-invoices.Discount]</td> -->
              <td class=roweven colspan=$colspan_sub align=right>$discount_text $discount_perc_pretty %</td>
              <td class=roweven align=right><nobr>$discount_amount_pretty $currency</nobr></td>
            </tr>
        "
    }
     
    # Surcharge
    if {$surcharge_enabled_p && 0 != $surcharge_perc} {
        append subtotal_item_html "
            <tr> 
    <!--          <td class=roweven colspan=$colspan_sub align=right>[lang::message::lookup $locale intranet-invoices.Surcharge]</td> -->
              <td class=roweven colspan=$colspan_sub align=right>$surcharge_text $surcharge_perc_pretty %</td>
              <td class=roweven align=right><nobr>$surcharge_amount_pretty $currency</nobr></td>
            </tr>
        "
    }
     
    # New Subtotal line
    if {$discount_enabled_p || $surcharge_enabled_p} {
        append subtotal_item_html "
            <tr> 
              <td class=roweven colspan=$colspan_sub align=right><B>[lang::message::lookup $locale intranet-invoices.GrandTotal "Grand Total"]</B></td>
              <td class=roweven align=right><B><nobr>$grand_total_pretty $currency</nobr></B></td>
            </tr>
        "
    }
     
    if {"" != $vat && 0 != $vat} {
        append subtotal_item_html "
            <tr>
              <td class=roweven colspan=$colspan_sub align=right>[lang::message::lookup $locale intranet-invoices.VAT]: $vat_perc_pretty %&nbsp;</td>
              <td class=roweven align=right>$vat_amount_pretty $currency</td>
            </tr>
    "
    } else {
        append subtotal_item_html "
            <tr>
              <td class=roweven colspan=$colspan_sub align=right>[lang::message::lookup $locale intranet-invoices.VAT]: 0 %&nbsp;</td>
              <td class=roweven align=right>0 $currency</td>
            </tr>
    "
    }
     
    if {"" != $tax && 0 != $tax} {
        append subtotal_item_html "
            <tr> 
              <td class=roweven colspan=$colspan_sub align=right>[lang::message::lookup $locale intranet-invoices.TAX]: $tax_perc_pretty  %&nbsp;</td>
              <td class=roweven align=right>$tax_amount_pretty $currency</td>
            </tr>
        "
    }
     
    append subtotal_item_html "
            <tr> 
              <td class=roweven colspan=$colspan_sub align=right><b>[lang::message::lookup $locale intranet-invoices.Total_Due]</b></td>
              <td class=roweven align=right><b><nobr>$total_due_pretty $currency</nobr></b></td>
            </tr>
    "
     
    set payment_terms_html "
            <tr>
    	  <td valign=top class=rowplain>[lang::message::lookup $locale intranet-invoices.Payment_Terms]</td>
              <td valign=top colspan=[expr $colspan-1] class=rowplain> 
                [lang::message::lookup $locale intranet-invoices.lt_This_invoice_is_past_]
              </td>
            </tr>
    "
     
    set payment_method_html "
            <tr>
    	  <td valign=top class=rowplain>[lang::message::lookup $locale intranet-invoices.Payment_Method_1]</td>
              <td valign=top colspan=[expr $colspan-1] class=rowplain> $invoice_payment_method_desc</td>
            </tr>
    "
     
    set canned_note_html ""
    if {$canned_note_enabled_p} {
     
        set canned_note_sql "
                    select  c.aux_string1 as canned_note
                    from    im_dynfield_attr_multi_value v,
    			im_categories c
                    where   object_id = :invoice_id
    			and v.value::integer = c.category_id
        "
        set canned_notes ""
        db_foreach canned_notes $canned_note_sql {
    	append canned_notes "$canned_note\n"
        }
     
        set canned_note_html "
            <tr>
    	  <td valign=top class=rowplain>[lang::message::lookup $locale intranet-invoices.Canned_Note "Canned Note"]</td>
              <td valign=top colspan=[expr $colspan-1]>
    	    &lt;pre><span style=\"font-family: verdana, arial, helvetica, sans-serif\">$canned_notes</font>&lt;/pre>
    	  </td>
            </tr>
        "
    }
     
     
    set note_html "
            <tr>
    	  <td valign=top class=rowplain>[lang::message::lookup $locale intranet-invoices.Note]</td>
              <td valign=top colspan=[expr $colspan-1]>
    	    &lt;pre><span style=\"font-family: verdana, arial, helvetica, sans-serif\">$cost_note</font>&lt;/pre>
    	  </td>
            </tr>
    "
     
    set terms_html ""
    if {$cost_type_id == [im_cost_type_invoice] || $cost_type_id == [im_cost_type_bill]} {
        set terms_html [concat $payment_terms_html $payment_method_html]
    }
    append terms_html "$canned_note_html $note_html"
     
    set item_list_html [concat $invoice_item_html $subtotal_item_html]
    set item_html [concat $item_list_html $terms_html]
     
     
    # ---------------------------------------------------------------
    # Special Output: Format using a template and/or send out as PDF
    # ---------------------------------------------------------------
     
    # Use a specific template ("render_template_id") to render the "preview"
    # of this invoice
    if {0 != $render_template_id || "" != $send_to_user_as} {
     
        # New template type: OpenOffice document
        if {"odt" == $template_type} { set output_format "odt" }
     
        if {"" == $template} {
    	ad_return_complaint "$cost_type Template not specified" "
    	<li>You haven't specified a template for your $cost_type."
    	return
        }
     
        set invoice_template_path "$invoice_template_base_path/$template"
        if {![file isfile $invoice_template_path] || ![file readable $invoice_template_path]} {
    	ad_return_complaint "Unknown $cost_type Template" "
    	<li>$cost_type template '$invoice_template_path' doesn't exist or is not readable
    	for the web server. Please notify your system administrator."
    	return
        }
     
        # Render the page using the template
        # Always, as HTML is the input for the PDF converter
        set invoices_as_html [ns_adp_parse -file $invoice_template_path]
     
        if {$output_format == "html" } {
     
    	# HTML preview or email
    	if {"" != $send_to_user_as} {
    	    # Redirect to mail sending page:
    	    # Add the rendered invoice to the form variables
    	    ns_log Notice "view.tcl: html sending email"
    	    rp_form_put invoice_html $invoices_as_html
    	    rp_internal_redirect notify
    	    ad_script_abort
     
    	} else {
     
    	    # Show invoice using template
    	    ns_log Notice "view.tcl: html showing template"
    	    db_release_unused_handles
    	    ns_return 200 text/html $invoices_as_html
    	    ad_script_abort
    	}
     
        }
     
     
        # PDF output
        if {$output_format == "pdf" && $pdf_enabled_p} {
     
    	ns_log Notice "view.tcl: pdf output format"
    	set result [im_html2pdf $invoices_as_html]
    	set tmp_pdf_file [lindex $result 0]
    	set errlist [lindex $result 1]
     
    	if {[llength $errlist] > 0} {
    	    # Delete the temp file
    	    im_html2pdf_read_file -delete_file_p 1 $tmp_pdf_file
     
    	    # Return the error
    	    ad_return_complaint 1 $errlist
    	    ad_script_abort
    	}
     
    	# Write PDF out - either as preview or as email
    	if {"" != $send_to_user_as} {
    	    # Redirect to mail sending page:
    	    # Add the rendered invoice to the form variables
    	    ns_log Notice "view.tcl: pdf send out"
    	    rp_form_put invoice_pdf $binary_content
    	    rp_internal_redirect notify
    	    ad_script_abort
     
    	} else {
     
    	    # PDF Preview
    	    ns_log Notice "view.tcl: pdf preview"
    	    db_release_unused_handles
    	    ns_returnfile 200 application/pdf $tmp_pdf_file
    	    catch { file delete $tmp_pdf_file } err
    	    ad_script_abort
    	}
        }
     
        # OpenOffice Output
        if {$output_format == "odt"} {
     
    	ns_log Notice "view.tcl: odf formatting"
    	# ------------------------------------------------
            # setup and constants
     
    	if {$internal_path != "internal"} {
    	    set internal_tax_id "208 171 00202"
    	} else {
    	    set internal_tax_id "208 120 20138"
    	}
     
    	# ------------------------------------------------
    	# Delete the original template row, which is duplicate
    	$odt_template_table_node removeChild $odt_template_row_node
     
    	# ------------------------------------------------
            # Process the content.xml file
     
    	set odt_template_content [$root asXML]
     
    	# Perform replacements
            eval [template::adp_compile -string $odt_template_content]
            set content $__adp_output
     
    	# set date_quote "ccc"
    	# ad_return_complaint 1 $__adp_output
    	# ad_return_complaint 1 $odt_template_content
     
    	# Save the content to a file.
    	set file [open $odt_content w]
    	fconfigure $file -encoding "utf-8"
    	puts $file $content
    	flush $file
    	close $file
     
     
    	# ------------------------------------------------
            # Process the styles.xml file
     
            set file [open $odt_styles]
    	fconfigure $file -encoding "utf-8"
            set style_content [read $file]
            close $file
     
            # Perform replacements
            eval [template::adp_compile -string $style_content]
            set style $__adp_output
     
    	# Save the content to a file.
    	set file [open $odt_styles w]
    	fconfigure $file -encoding "utf-8"
    	puts $file $style
    	flush $file
    	close $file
     
    	# ------------------------------------------------
            # Replace the files inside the odt file by the processed files
     
    	# The zip -j command replaces the specified file in the zipfile 
    	# which happens to be the OpenOffice File. 
    	ns_log Notice "view.tcl: before zipping"
    	exec zip -j $odt_zip $odt_content
    	exec zip -j $odt_zip $odt_styles
     
            db_release_unused_handles
     
    	# ------------------------------------------------
            # Return the file
    	ns_log Notice "view.tcl: before returning file"
            set outputheaders [ns_conn outputheaders]
            ns_set cput $outputheaders "Content-Disposition" "attachment; filename=${invoice_nr}.odt"
            ns_returnfile 200 application/odt $odt_zip
     
    	# ------------------------------------------------
            # Delete the temporary files
     
    	# delete other tmpfiles
    	# ns_unlink "${dir}/$document_filename"
    	# ns_unlink "${dir}/$content.xml"
    	# ns_unlink "${dir}/$style.xml"
    	# ns_unlink "${dir}/document.odf"
    	# ns_rmdir $dir
    	ad_script_abort
     
        }
     
        ad_return_complaint 1 "Internal Error - No output format specified"
     
    } 
     
     
    # ---------------------------------------------------------------------
    # Sub-Navbar
    # ---------------------------------------------------------------------
     
    # Choose the right subnavigation bar
    #
    if {[llength $related_projects] != 1} {
        set sub_navbar [im_costs_navbar "none" "/intranet-invoices/index" "" "" [list] ""]
    } else {
        set project_id [lindex $related_projects 0]
        set bind_vars [ns_set create]
        ns_set put $bind_vars project_id $project_id
        set parent_menu_id [db_string parent_menu "select menu_id from im_menus where label='project'" -default 0]
        set menu_label "project_finance"
        set sub_navbar [im_sub_navbar \
                            -components \
                            -base_url "/intranet/projects/view?project_id=$project_id" \
                            $parent_menu_id \
                            $bind_vars "" "pagedesriptionbar" $menu_label]
    }
     
    # ---------------------------------------------------------------------
    # correct problem created by -r 1.33 view.adp 
    # ---------------------------------------------------------------------
     
    if {$cost_type_id == [im_cost_type_po]} {
       set customer_id $comp_id
    }
     
    # ---------------------------------------------------------------------
    # ERR mess from intranet-trans-invoices
    # ---------------------------------------------------------------------
     
    if { "" != $err_mess } {
        set err_mess [lang::message::lookup "" $err_mess "Document Nr. not available anymore, please note and verify newly assigned number"]
    }
     
     
     
     
    # ---------------------------------------------------------------------
    # Dynfields
    # ---------------------------------------------------------------------
     
    set extra_selects [list "0 as zero"]
    set date_fields [list]
     
    set column_sql "
            select  w.deref_plpgsql_function,
                    aa.attribute_name,
    		w.widget_name
            from    im_dynfield_widgets w,
                    im_dynfield_attributes a,
                    acs_attributes aa
            where   a.widget_name = w.widget_name and
                    a.acs_attribute_id = aa.attribute_id and
                    aa.object_type = 'im_invoice'
    "
    db_foreach column_list_sql $column_sql {
    	if { "date" == $widget_name } {
    	   lappend date_fields $attribute_name      
    	}
    	lappend extra_selects "${deref_plpgsql_function}($attribute_name) as ${attribute_name}_deref"
    }
     
    set extra_selects [join $extra_selects ",\n\t"]
     
    set query "
    select
            $extra_selects
    from
            im_invoices p
    where
            p.invoice_id=:invoice_id
     
    "
     
    if { ![db_0or1row invoice_info_query $query] } {
        # no dynfields - deactivate tab view 
    }
     
    set project_base_data_html "
                            <table border=0 cellpadding='10px' cellspacing='10px'>
                              <tr>
                                <!--<td>[_ intranet-core.Project_name]</td>-->
                                <td><b>Attribute</b></td>
                                <td><b>Value</b></td>
                              </tr>"
    set column_sql "
            select
                    aa.pretty_name,
                    aa.attribute_name
            from
                    im_dynfield_widgets w,
                    acs_attributes aa,
                    im_dynfield_attributes a
                    LEFT OUTER JOIN (
                            select *
                            from im_dynfield_layout
                            where page_url = ''
                    ) la ON (a.attribute_id = la.attribute_id)
            where
                    a.widget_name = w.widget_name and
                    a.acs_attribute_id = aa.attribute_id and
                    aa.object_type = 'im_invoice'
            order by
                    coalesce(la.pos_y,0), coalesce(la.pos_x,0)
    "
     
     
    db_foreach column_list_sql $column_sql {
        set var ${attribute_name}_deref
        set value [expr $$var]
        if {"" != [string trim $value]} {
                    append project_base_data_html "
                      <tr>
                        <td>[lang::message::lookup "" intranet-core.$attribute_name $pretty_name]</td>
                        <td>$value</td>
                      </tr>
                    "
        }
    }
     
     
    append project_base_data_html "</table>"

    ———————————————————————————-
    c) Patch /web/projop/packages/intranet-invoices/www/view.adp
    ———————————————————————————-

    Here’s the complete file /packages/intranet-invoices/www/view.adp
    based on V3.5 – cvs branch: b3-5-0-patches:

    <master src="../../intranet-core/www/master">
    <property name="title">@page_title;noquote@</property>
    <property name="main_navbar_label">finance</property>
    <property name="sub_navbar">@sub_navbar;noquote@</property>
     
    <if @show_dynfield_tab_p@ eq 1>
     
    	<script src="http://yui.yahooapis.com/2.8.2r1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
    	<script src="http://yui.yahooapis.com/2.8.2r1/build/element/element-min.js"></script>
    	<script src="http://yui.yahooapis.com/2.8.2r1/build/tabview/tabview-min.js"></script>
    	<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.8.2r1/build/tabview/assets/skins/sam/tabview.css">
     
    	<script type="text/javascript">
    		var myTabs = new YAHOO.widget.TabView("demo");
    	</script>
     
    	<div class="yui-skin-sam">
     
    	<div id="demo" class="yui-navset">
    	    <ul class="yui-nav">
            	<li class="selected"><a href="#tab1"><em>Invoice</em></a></li>
    	        <li><a href="#tab2"><em>Dynamic Invoice Elements</em></a></li>
     	   </ul>
     
    	<div class="yui-content">
    	<div>
    </if>
     
     
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    <span style="color:red;font-weight:bold;">@err_mess@</span>
     
    <table cellpadding=1 cellspacing=1 border=0>
    <tr valign=top>
      <td>
     
    	  <%= [im_invoices_object_list_component $user_id $invoice_id $read $write $return_url] %>
      </td>
      <td>
        @payment_list_html;noquote@
      </td>
      <td>
    	<table border=0 cellPadding=1 cellspacing=1>
    	  <tr class=rowtitle>
    	    <td colspan=2 class=rowtitle>#intranet-invoices.Admin_Links#</td>
    	  </tr>
    	  <tr>
    	    <td>
     
    	<ul>
    	<li>
    	  <% set render_template_id $template_id %>
    	  <% set preview_vars [export_url_vars invoice_id render_template_id return_url] %>
    	  <A HREF="/intranet-invoices/view?@preview_vars@">
    		<%= [lang::message::lookup "" intranet-invoices.Preview_using_template "Preview using template"] %>
    	  </A>
     
    	<li>
    	  <% set render_template_id $template_id %>
    	  <% set preview_vars [export_url_vars invoice_id render_template_id return_url] %>
    	  <A HREF="/intranet-invoices/view?@preview_vars@&item_list_type=1">
    		<%= [lang::message::lookup "" intranet-invoices.Preview_using_template "Preview using template with task information"] %>
    	  </A>
     
    <if @pdf_enabled_p@>
    	<li>
    	  <% set render_template_id $template_id %>
    	  <% set preview_vars [export_url_vars invoice_id render_template_id return_url] %>
    	  <A HREF="/intranet-invoices/view?@preview_vars@&output_format=pdf">
    		<%= [lang::message::lookup "" intranet-invoices.Preview_as_PDF "Preview as PDF"] %>
    	  </A>
    </if>
     
    <if @timesheet_report_enabled_p@>
     
    	<li>
    	  <% 
    		set level_of_details [parameter::get -package_id [apm_package_id_from_key intranet-invoices] -parameter LevelOfDetailsTimesheetHoursReport -default 4]
    		set ts_url [export_vars -base $timesheet_report_url {{level_of_detail $level_of_details} {invoice_id $invoice_id}}] 	      %>
    	  <A HREF="@ts_url;noquote@">
    		<%= [lang::message::lookup "" intranet-invoices.Show_Included_Timesheet_Hours "Show Included Timesheet Hours"] %>
    	  </A>
     
    </if>
     
     
    <if @admin@>
    	<if @cost_type_id@ eq @quote_cost_type_id@>
    	<li>
    		<% set blurb [lang::message::lookup $locale intranet-invoices.Generate_Invoice_from_Quote "Generate Invoice from Quote"] %>
    		<% set source_invoice_id $invoice_id %>
    		<% set target_cost_type_id [im_cost_type_invoice] %>
    		<% set gen_vars [export_url_vars source_invoice_id target_cost_type_id return_url] %>
    		<A HREF="/intranet-invoices/new-copy?@gen_vars@">@blurb@</A>
     
    	<li>
    		<% set blurb [lang::message::lookup $locale intranet-invoices.Generate_Delivery_Note_from_Quote "Generate Delivery Note from Quote"] %>
    		<% set source_invoice_id $invoice_id %>
    		<% set target_cost_type_id [im_cost_type_delivery_note] %>
    		<% set gen_vars [export_url_vars source_invoice_id target_cost_type_id return_url] %>
    		<A HREF="/intranet-invoices/new-copy?@gen_vars@">@blurb@</A>
    	</if>
     
    	<if @cost_type_id@ eq @delnote_cost_type_id@>
    	<li>
    		<% set blurb [lang::message::lookup $locale intranet-invoices.Generate_Invoice_from_DelNote "Generate Invoice from Delivery Note"] %>
    		<% set source_invoice_id $invoice_id %>
    		<% set target_cost_type_id [im_cost_type_invoice] %>
    		<% set gen_vars [export_url_vars source_invoice_id target_cost_type_id return_url] %>
    		<A HREF="/intranet-invoices/new-copy?@gen_vars@">@blurb@</A>
    	</if>
     
     
    	<if @cost_type_id@ eq @po_cost_type_id@>
    	<li>
    		<% set blurb [lang::message::lookup $locale intranet-invoices.Generate_Provider_Bill_from_Purchase_Order "Generate Provider Bill from Purchase Order"] %>
    		<% set source_invoice_id $invoice_id %>
    		<% set target_cost_type_id [im_cost_type_bill] %>
    		<% set gen_vars [export_url_vars source_invoice_id target_cost_type_id return_url] %>
    		<A HREF="/intranet-invoices/new-copy?@gen_vars@">@blurb@</A>
    	</if>
    </if>
     
     
     
    <if @write@>
    <!--
    	<li>
    	  <% set notify_vars [export_url_vars invoice_id return_url] %>
    	  <A HREF="/intranet-invoices/notify?@notify_vars@">
    	  <%= [lang::message::lookup "" intranet-invoices.Send_document_as_HTML_link "Send this %cost_type% as HTML link"] %>
    	  </A>
    -->
     
    	<li>
    	  <% set url [export_vars -base "/intranet-invoices/view" {invoice_id {render_template_id $template_id} {send_to_user_as "html"} return_url}] %>
    	  <A HREF="@url@">
    	  <%= [lang::message::lookup "" intranet-invoices.Send_document_as_HTML_attachment "Send this %cost_type% as HTML attachment"] %>
    	  </A>
     
    <if @pdf_enabled_p@>
    	<li>
    	  <% set url [export_vars -base "/intranet-invoices/view" {invoice_id {render_template_id $template_id} {send_to_user_as "pdf"} return_url}] %>
    	  <A HREF="@url@">
    	  <%= [lang::message::lookup "" intranet-invoices.Send_document_as_PDF_attachment "Send this %cost_type% as PDF attachment"] %>
    	  </A>
    </if>
     
    </if>
     
     
    <if 0>
    <if @ubl_enabled_p@>
            <li>
              <% set render_template_id $template_id %>
              <% set preview_vars [export_url_vars invoice_id return_url] %>
              <A HREF="/intranet-ubl/document.xml?@preview_vars@">
                    <%= [lang::message::lookup "" intranet-invoices.Export_as_XML
    		"Export as XML"] %>
              </A>
              (<%= [lang::message::lookup "" intranet-invoices.See_kolon "See:"]
    	  %>
              <A HREF="/intranet-ubl/doc/"><%= [lang::message::lookup ""
    	  intranet-invoices.UBL_XML_Documentation "UBL-XML\
     Documentation"] %></a>)
    </if>
    </if>
     
    	</ul>
     
    	    </td>
    	  </tr>
    	</table>
      </td>
    </tr>
    </table>
     
    <!-- Invoice Data and Receipient Tables -->
    <table cellpadding=0 cellspacing=0 bordercolor=#6699CC border=0 width="100%">
      <tr valign=top> 
        <td>
     
    	<table border=0 cellPadding=0 cellspacing=2 width="100%">
            <tr>
    	  <td align=middle class=rowtitle colspan=2>#intranet-invoices.cost_type_Data#
              </td>
    	</tr>
            <tr>
              <td  class=rowodd>#intranet-invoices.cost_type_nr#.:</td>
              <td  class=rowodd>@invoice_nr@</td>
            </tr>
            <tr> 
              <td  class=roweven>#intranet-invoices.cost_type_date#:</td>
              <td  class=roweven>@invoice_date_pretty@</td>
            </tr>
    <if [apm_package_installed_p "intranet-cost-center"] >
            <tr> 
              <td  class=roweven><%= [lang::message::lookup "" intranet-cost.Cost_Center "Cost Center"] %>:</td>
              <td  class=roweven>@cost_center_name@</td>
            </tr>
    </if>
     
    <if @invoice_or_bill_p@>
            <tr> 
              <td  class=rowodd>#intranet-invoices.cost_type_due_date#</td>
              <td  class=rowodd>@due_date@</td>
    	</tr>
     
            <tr> 
              <td class=roweven>#intranet-invoices.Payment_terms#</td>
              <td class=roweven>#intranet-invoices.lt_payment_days_days_dat#</td>
    	</tr>
     
    	<tr>
              <td class=rowodd>#intranet-invoices.Payment_Method#</td>
              <td class=rowodd>@invoice_payment_method@</td>
    	</tr>
     
    </if>
     
     
    	<tr>
              <td class=roweven>#intranet-invoices.cost_type_template#</td>
              <td class=roweven>@template@</td>
    	</tr>
     
    	<tr>
              <td class=roweven>#intranet-invoices.cost_type_type_1#</td>
              <td class=roweven>@cost_type@</td>
            </tr>
     
            <tr> 
              <td class=rowodd>#intranet-invoices.cost_type_status#:</td>
              <td class=rowodd>@cost_status@</td>
            </tr>
     
    	<tr><td colspan=2 align=right>
    <if @write@>
    	  <form action=new method=POST>
    	    <%= [export_form_vars return_url invoice_id cost_type_id] %>
    	    <input type=submit name=edit_invoice value='#intranet-invoices.Edit#'>
    	    <input type=submit name=del_invoice value='#intranet-core.Delete#'>
    	  </form>
    </if>
    	</td></tr>
    	</table>
     
        </td>
        <td></td>
        <td align=right>
          <table border=0 cellspacing=2 cellpadding=0 width="100%">
     
            <tr><td align=center valign=top class=rowtitle colspan=2> #intranet-invoices.Recipient#</td></tr>
     
    <if @invoice_or_quote_p@>
            <tr> 
              <td  class=rowodd>#intranet-invoices.Company_name#</td>
              <td  class=rowodd>
                <A href="/intranet/companies/view?company_id=@customer_id@">@company_name@</A>
              </td>
            </tr>
    </if>
    <else>
            <tr> 
              <td  class=rowodd>#intranet-invoices.Provider#</td>
              <td  class=rowodd>
                <A href="/intranet/companies/view?company_id=@provider_id@">@company_name@</A>
              </td>
            </tr>
    </else>
     
            <tr> 
              <td  class=roweven>#intranet-invoices.VAT#</td>
              <td  class=roweven>@vat_number@</td>
            </tr>
            <tr> 
              <td  class=rowodd> #intranet-invoices.Contact#</td>
              <td  class=rowodd>
                <A href=/intranet/users/view?user_id=@org_company_contact_id@>@company_contact_name@</A>
              </td>
            </tr>
            <tr> 
              <td  class=roweven>#intranet-invoices.Adress#</td>
              <td  class=roweven>@address_line1@ <br> @address_line2@</td>
            </tr>
            <tr> 
              <td  class=rowodd>#intranet-invoices.Zip#</td>
              <td  class=rowodd>@address_postal_code@</td>
            </tr>
            <tr> 
              <td  class=roweven>#intranet-invoices.Country#</td>
              <td  class=roweven>@country_name@</td>
            </tr>
            <tr> 
              <td  class=rowodd>#intranet-invoices.Phone#</td>
              <td  class=rowodd>@phone@</td>
            </tr>
            <tr> 
              <td  class=roweven>#intranet-invoices.Fax#</td>
              <td  class=roweven>@fax@</td>
            </tr>
            <tr> 
              <td  class=rowodd>#intranet-invoices.Email#</td>
              <td  class=rowodd>@company_contact_email@</td>
            </tr>
          </table>
      </tr>
    </table>
     
    <table cellpadding=0 cellspacing=2 border=0 width="100%">
    <tr><td align=right>
      <table cellpadding=1 cellspacing=2 border=0>
        @item_list_html;noquote@
      </table>
     
      <table cellpadding=1 cellspacing=2 border=0>
        @terms_html;noquote@
      </table>
     
    </td></tr>
    </table>
     
    </div>
     
    <if @show_dynfield_tab_p@ eq 1>
    <div>
        <%= [im_table_with_title "" $project_base_data_html] %>
    </div>
     
    </div>
     
    </if>
     
    </div>
    </div>

    ———————————————————————————-
    e) Patch /web/projop/packages/intranet-invoices/www/new.tcl
    ———————————————————————————-

    # /packages/intranet-invoices/www/new.tcl
    #
    # Copyright (C) 2003 - 2009 ]project-open[
    #
    # All rights reserved. Please check
    # http://www.project-open.com/license/ for details.
     
    # ---------------------------------------------------------------
    # 1. Page Contract
    # ---------------------------------------------------------------
    ad_page_contract { 
        Receives the list of tasks to invoice, creates a draft invoice
        (status: "In Process") and displays it.
        Provides a button to advance to new-2.tcl, which takes the final
        steps of invoice generation by setting the state of the invoice
        to "Created" and the state of the associates im_tasks to "Invoiced".
     
        @param create_invoice_from_template
               Indicates that "Create Invoice" button was
               used to start creating an invoice from a Quote or a
               Provider Bill from a Purchase Order
     
        @author frank.bergmann@project-open.com
    } {
        { include_task:multiple "" }
        { invoice_id:integer 0}
        { cost_type_id:integer "" }
        { customer_id:integer 0}
        { provider_id:integer 0}
        { project_id:integer 0}
        { cost_center_id:integer 0}
        { invoice_currency ""}
        { create_invoice_from_template ""}
        { return_url "/intranet-invoices/list"}
        del_invoice:optional
    }
     
    # ---------------------------------------------------------------
    # 2. Defaults & Security
    # ---------------------------------------------------------------
     
    set user_id [ad_maybe_redirect_for_registration]
    set show_cost_center_p [ad_parameter -package_id [im_package_invoices_id] "ShowCostCenterP" "" 0]
    set current_url [im_url_with_query]
     
    # Check if we have to forward to "new-copy":
    if {"" != $create_invoice_from_template} {
        ad_returnredirect [export_vars -base "new-copy" {invoice_id cost_type_id}]
        ad_script_abort
    }
     
    # Check if we need to delete the invoice.
    # We get there because the "Delete" button in view.tcl can
    # only send to one target, which is this file...
    if {[info exists del_invoice]} {
        # Calculate the new return_url, because the invoice itself
        # will dissappear...
        set return_url "/intranet-invoices/list"
        set project_id [db_string pid "select project_id from im_costs where cost_id = :invoice_id" -default 0]
        if {"" != $project_id && 0 != $project_id} {
    	set view_name "finance"
    	set return_url [export_vars -base "/intranet/projects/view" {project_id view_name}] 
        }
        ad_returnredirect [export_vars -base delete {invoice_id return_url}]
    }
     
     
     
     
    # Do we need the cost_center_id for creating a new invoice?
    # This is necessary if the invoice_nr depends on the cost_center_id (profit center).
    set cost_center_required_p [parameter::get_from_package_key -package_key "intranet-invoices" -parameter "NewInvoiceRequiresCostCenterP" -default 0]
    if {$cost_center_required_p && 0 == $invoice_id && ($cost_center_id == "" || $cost_center_id == 0)} {
        ad_returnredirect [export_vars -base "new-cost-center-select" {
    	{pass_through_variables { cost_type_id customer_id provider_id include_task project_id invoice_currency create_invoice_from_template invoice_id select_project} }
    	include_task
    	invoice_id
    	cost_type_id 
    	customer_id 
    	provider_id 
    	select_project
    	project_id 
    	invoice_currency 
    	cost_center_id
    	create_invoice_from_template 
    	{ return_url $current_url}
        }]
    }
     
    # Permissions
    if {0 == $invoice_id} {
     
        if {"" == $cost_type_id} {
    	ad_return_complaint 1 "<li>You need to specify a Cost Type"
    	return
        }
     
        # CostCenter Permissions:
        # We are about to create a new invoice - Check specific creation perms
        set create_cost_types [im_cost_type_write_permissions $user_id]
        if {[lsearch -exact $create_cost_types $cost_type_id] == -1} {
    	ad_return_complaint "Insufficient Privileges" "
            <li>You don't have sufficient privileges to create a 
                [db_string t "select im_category_from_id(:cost_type_id)"]."
    	return
        }
     
    } else {
     
        # CostCenter Permissions:
        # The invoice already exists - Check invoice permissions
        im_cost_permissions $user_id $invoice_id view read write admin
        if {!$write} {
    	ad_return_complaint "Insufficient Privileges" "
            <li>You don't have sufficient privileges to see this page."    
        }
    }
     
     
    set return_url [im_url_with_query]
    set todays_date [db_string get_today "select to_char(sysdate,'YYYY-MM-DD') from dual"]
    set page_focus "im_header_form.keywords"
    set view_name "invoice_tasks"
     
    set bgcolor(0) " class=roweven"
    set bgcolor(1) " class=rowodd"
    set required_field "<font color=red size=+1><B>*</B></font>"
    set cost_note ""
    set canned_note ""
    set canned_note_id ""
     
    set tax_format "90.9"
    set vat_format "90.9"
     
    set discount_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceDiscountFieldP" "" 0]
    set surcharge_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceSurchargeFieldP" "" 0]
     
    # Canned Notes is a field with multiple messages per invoice
    set canned_note_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceCannedNoteP" "" 0]
     
    # Should we show the "Tax" field?
    set tax_enabled_p [ad_parameter -package_id [im_package_invoices_id] "EnabledInvoiceTaxFieldP" "" 1]
     
    # Should we show a "Material" field for invoice lines?
    set material_enabled_p [ad_parameter -package_id [im_package_invoices_id] "ShowInvoiceItemMaterialFieldP" "" 0]
    set project_type_enabled_p [ad_parameter -package_id [im_package_invoices_id] "ShowInvoiceItemProjectTypeFieldP" "" 1]
     
    # Show dynfields?
    set show_dynfield_tab_p [ad_parameter -package_id [im_package_invoices_id] "DynamicFieldSupport" "" "0"]
     
    # Tricky case: Sombebody has called this page from a project
    # So we need to find out the company of the project and create
    # an invoice from scratch, invoicing all project elements.
    if {0 != $project_id} {
        db_1row customer_info "
    	select
    		c.*
    	from
    		im_projects p,
    		im_companies c
    	where
    		project_id = :project_id
    		and p.company_id = c.company_id
        "
    }
     
     
    # ---------------------------------------------------------------
    # Determine whether it's an Invoice or a Bill
    # ---------------------------------------------------------------
     
    # Invoices and Quotes have a "Company" fields.
    set invoice_or_quote_p [im_cost_type_is_invoice_or_quote_p $cost_type_id]
     
    # Invoices and Bills have a "Payment Terms" field.
    set invoice_or_bill_p [im_cost_type_is_invoice_or_bill_p $cost_type_id]
     
    if {$invoice_or_quote_p} {
        if { 0 == $customer_id } {
    	set company_id [db_string cost_type "select customer_id from im_costs where cost_id = :invoice_id" -default ""]    
        } else {
    	set company_id $customer_id
        }
        set ajax_company_widget "customer_id"
        set custprov "customer"
    } else {
        set company_id $provider_id
        set ajax_company_widget "provider_id"
        set custprov "provider"
    }
     
    # ad_return_complaint 1 $company_id
     
     
    # ---------------------------------------------------------------
    # 3. Gather invoice data
    #	a: if the invoice already exists
    # ---------------------------------------------------------------
     
    # Check if we are editing an already existing invoice
    #
    if {$invoice_id} {
        # We are editing an already existing invoice
     
        db_1row invoices_info_query ""
     
        # Canned Notes is a field with multiple messages per invoice
        if {$canned_note_enabled_p} {
    	    set canned_note_id [db_list canned_notes "
    		select	value
    		from	im_dynfield_attr_multi_value
    		where	object_id = :invoice_id
    	    "]
        }
     
        set cost_type [im_category_from_id $cost_type_id]
        set invoice_mode "exists"
        set page_title "[_ intranet-invoices.Edit_cost_type]"
        set button_text $page_title
        set context_bar [im_context_bar [list /intranet/invoices/ "[_ intranet-invoices.Finance]"] $page_title]
     
        # Check if there is a single currency being used in the invoice
        # and get it.
        # This should always be the case, but doesn't need to...
        if {"" == $invoice_currency} {
    	catch {
    	    db_1row invoices_currency_query "
    		select distinct
    			currency as invoice_currency
    		from	im_invoice_items i
    		where	i.invoice_id=:invoice_id"
    	} err_msg
        }
     
    } else {
     
    # ---------------------------------------------------------------
    # Setup the fields for a new invoice
    # ---------------------------------------------------------------
     
        # Build the list of selected tasks ready for invoices
        set invoice_mode "new"
        set in_clause_list [list]
        set cost_type [im_category_from_id $cost_type_id]
        set button_text "[_ intranet-invoices.New_cost_type]"
        set page_title "[_ intranet-invoices.New_cost_type]"
        set context_bar [im_context_bar [list /intranet/invoices/ "[_ intranet-invoices.Finance]"] $page_title]
     
        set invoice_id [im_new_object_id]
        set invoice_nr [im_next_invoice_nr -cost_type_id $cost_type_id -cost_center_id $cost_center_id]
        set cost_status_id [im_cost_status_created]
        set effective_date $todays_date
        set payment_days [ad_parameter -package_id [im_package_cost_id] "DefaultCompanyInvoicePaymentDays" "" 30] 
        set due_date [db_string get_due_date "select sysdate+:payment_days from dual"]
        set vat 0
        set tax 0
        set discount_text ""
        set discount_perc 0
        set surcharge_text ""
        set surcharge_perc 0
        set note ""
        set cost_note ""
        set canned_note ""
        set canned_note_id ""
        set payment_method_id ""
        set template_id ""
        set company_contact_id [im_invoices_default_company_contact $company_id $project_id]
        set read_only_p "f"
     
        # Default for cost-centers - take the user's
        # dept from HR.
        if {0 == $cost_center_id} {
    	set cost_center_id [im_costs_default_cost_center_for_user $user_id]
        }
    }
     
    if {"" == $invoice_currency} {
        set invoice_currency [ad_parameter -package_id [im_package_cost_id] "DefaultCurrency" "" "EUR"]
    }
     
    if {"t" == $read_only_p} {
        ad_return_complaint 1 "
            <b>[lang::message::lookup "" intranet-cost.Invoice_Read_Only "Read Only"]</b>:
            [lang::message::lookup "" intranet-cost.Invoice_Read_Only_Message "
                    <p>This financial document is read only.</p>
                    <p>This situation may happen if the document has already been exported
                    to an external system or in similar cases.</p>
        "]
        "
        ad_script_abort
    }
     
     
    # ---------------------------------------------------------------
    # Get default values for VAT and invoice_id from company
    # ---------------------------------------------------------------
     
    if {[im_column_exists im_companies default_invoice_template_id]} {
        if {0 == $vat} {
    	set vat [db_string default_vat "select default_vat from im_companies where company_id = :company_id" -default "0"]
        }
     
        if {"" == $template_id} {
    	set template_id [db_string default_template "select default_invoice_template_id from im_companies where company_id = :company_id" -default ""]
        }
     
        if {"" == $payment_method_id} {
    	set payment_method_id [db_string default_payment_method "select default_payment_method_id from im_companies where company_id = :company_id" -default ""]
        }
     
        set company_payment_days [db_string default_payment_days "select default_payment_days from im_companies where company_id = :company_id" -default ""]
        if {"" != $company_payment_days} {
    	set payment_days $company_payment_days
        }
    }
     
    if {[im_column_exists im_companies default_tax]} {
        if {0 == $tax} {
            set tax [db_string default_tax "select default_tax from im_companies where company_id = :company_id" -default "0"]
        }
    }
     
     
    # Get a reasonable default value for the invoice_office_id,
    # either from the invoice or then from the company_main_office.
     
    set invoice_office_id [db_string invoice_office_info "select invoice_office_id from im_invoices where invoice_id = :invoice_id" -default ""]
    if {"" == $invoice_office_id} {
        set invoice_office_id [db_string company_main_office_info "select main_office_id from im_companies where company_id = :company_id" -default ""]
    }
     
    # ---------------------------------------------------------------
    # Calculate the selects for the ADP page
    # ---------------------------------------------------------------
     
    set payment_method_select [im_invoice_payment_method_select payment_method_id $payment_method_id]
    set template_select [im_cost_template_select template_id $template_id]
    set status_select [im_cost_status_select cost_status_id $cost_status_id]
     
    set type_select [im_cost_type_select cost_type_id $cost_type_id 0 "financial_doc"]
    if {"" != $cost_type_id} {
        set type_select "
    	<input type=hidden name=cost_type_id value=$cost_type_id>
    	$cost_type
        "
    }
     
    set customer_select [im_company_select -tag_attributes {onchange "ajaxFunction();" onkeyup "ajaxFunction();"} customer_id $customer_id "" "CustOrIntl"]
    set provider_select [im_company_select -tag_attributes {onchange "ajaxFunction();" onkeyup "ajaxFunction();"} provider_id $provider_id "" "Provider"]
    set contact_select [im_company_contact_select company_contact_id $company_contact_id $company_id]
     
    set invoice_address_label [lang::message::lookup "" intranet-invoices.Invoice_Address "Address"]
    set invoice_address_select [im_company_office_select invoice_office_id $invoice_office_id $company_id]
     
    set cost_center_label [lang::message::lookup "" intranet-invoices.Cost_Center "Cost Center"]
     
    if {$show_cost_center_p} {
        set cost_center_select [im_cost_center_select -include_empty 1 -department_only_p 0 cost_center_id $cost_center_id $cost_type_id]
    } else {
        set cost_center_hidden "<input type=hidden name=cost_center_id value=$cost_center_id>"
    }
     
    # ---------------------------------------------------------------
    # 7. Select and format the sum of the invoicable items
    # for a new invoice
    # ---------------------------------------------------------------
     
     
    # start formatting the list of sums with the header...
    set task_sum_html "
            <tr align=center> 
              <td class=rowtitle>[_ intranet-invoices.Line]</td>
              <td class=rowtitle>[_ intranet-invoices.Description]</td>
    "
    if {$material_enabled_p} {
        append task_sum_html "<td class=rowtitle>[lang::message::lookup "" intranet-invoices.Material "Material"]</td>"
    }
    if {$project_type_enabled_p} {
        append task_sum_html "<td class=rowtitle>[lang::message::lookup "" intranet-invoices.Type "Type"]</td>"
    }
    append task_sum_html "
              <td class=rowtitle>[_ intranet-invoices.Units]</td>
              <td class=rowtitle>[_ intranet-invoices.UOM]</td>
              <td class=rowtitle>[_ intranet-invoices.Rate]</td>
            </tr>
    "
     
     
     
    if {[string equal $invoice_mode "new"]} {
     
        # Start formatting the "reference price list" as well, even though it's going
        # to be shown at the very bottom of the page.
        #
        set price_colspan 11
        set ctr 1
        set old_project_id 0
        set colspan 6
        set vat_colspan 6
        set target_language_id ""
     
    } else {
     
    # ---------------------------------------------------------------
    # 8. Get the old invoice items for an already existing invoice
    # ---------------------------------------------------------------
     
        set ctr 1
        set old_project_id 0
        set colspan 6
        set vat_colspan 6
        set target_language_id ""
        db_foreach invoice_item "" {
     
    	append task_sum_html "
    	<tr $bgcolor([expr $ctr % 2])> 
              <td>
    	    <input type=text name=item_sort_order.$ctr size=2 value='$sort_order'>
    	  </td>
              <td>
    	    <input type=text name=item_name.$ctr size=40 value='[ns_quotehtml $item_name]'>
    	  </td>
    	"
    	append task_sum_html "<input type=hidden name=item_task_id.$ctr value='$task_id'>"
     
    	if {$material_enabled_p} {
    	    append task_sum_html "<td>[im_material_select -max_option_len 100 item_material_id.$ctr $item_material_id]</td>"
    	} else {
    	    append task_sum_html "<input type=hidden name=item_material_id.$ctr value='$item_material_id'>"
    	}
     
    	if {$project_type_enabled_p} {
    	    append task_sum_html "<td>[im_category_select "Intranet Project Type" item_type_id.$ctr $item_type_id]</td>"
    	} else {
    	    append task_sum_html "<input type=hidden name=item_type_id.$ctr value='$item_type_id'>"
    	}
     
    	append task_sum_html "
              <td align=right>
    	    <input type=text name=item_units.$ctr size=4 value='$item_units'>
    	  </td>
              <td align=right>
                [im_category_select "Intranet UoM" item_uom_id.$ctr $item_uom_id]
    	  </td>
              <td align=right>
    	    <nobr><input type=text name=item_rate.$ctr size=7 value='$price_per_unit'>[im_currency_select item_currency.$ctr $currency]</nobr>
    	  </td>
            </tr>
    	<input type=hidden name=item_project_id.$ctr value='$project_id'>
    	"
    	incr ctr
        }
    }
     
     
    # ---------------------------------------------------------------
    # Add some empty new lines for editing purposes
    # ---------------------------------------------------------------
     
    for {set i 0} {$i < 3} {incr i} {
     
        append task_sum_html "
    	<tr $bgcolor([expr $ctr % 2])> 
              <td>
    	    <input type=text name=item_sort_order.$ctr size=2 value='$ctr'>
    	  </td>
              <td>
    	    <input type=text name=item_name.$ctr size=40 value=''>
    	  </td>
        "
        append task_sum_html "<input type=hidden name=item_task_id.$ctr value='-1'>"
     
        if {$material_enabled_p} {
    	append task_sum_html "<td>[im_material_select -max_option_len 100 item_material_id.$ctr ""]</td>"
        } else {
    	append task_sum_html "<input type=hidden name=item_material_id.$ctr value=''>"
        }
     
        if {$project_type_enabled_p} {
    	append task_sum_html "<td>[im_category_select "Intranet Project Type" item_type_id.$ctr ""]</td>"
        } else {
    	append task_sum_html "<input type=hidden name=item_type_id.$ctr value=''>"
        }
     
        append task_sum_html "
              <td align=right>
    	    <input type=text name=item_units.$ctr size=4 value='0'>
    	  </td>
              <td align=right>
                [im_category_select "Intranet UoM" item_uom_id.$ctr 320]
    	  </td>
              <td align=right>
                <!-- rate and currency need to be together so that the line doesn't break -->
    	    <nobr><input type=text name=item_rate.$ctr size=7 value='0'>[im_currency_select item_currency.$ctr $invoice_currency]</nobr>
    	  </td>
            </tr>
    	<input type=hidden name=item_project_id.$ctr value=''>
        "
     
        incr ctr
    }
     
    # ---------------------------------------------------------------
    # Pass along the number of projects related to this document
    # ---------------------------------------------------------------
     
    # fraber 080515: @CTP: the project_id comes from im_invoice_ITEMS,
    # and causes trouble (adding an additional project to the list of
    # related projects). Did this code (own_project_related) make ever
    # sense?
     
    set own_project_related ""
    if {0 != $project_id} { set own_project_related "UNION select :project_id as project_id" }
     
    set related_project_sql "
    	select	object_id_one as project_id
    	from	acs_rels r
    	where	r.object_id_two = :invoice_id
    	$own_project_related
    "
     
    set select_project_html ""
    db_foreach related_project $related_project_sql {
    	append select_project_html "<input type=hidden name=select_project value=$project_id>\n"
    }
     
    set sub_navbar [im_costs_navbar "none" "/intranet/invoices/index" "" "" [list]] 
     
    db_release_unused_handles
     
     
    # ---------------------------------------------------------------
    # Set Dynfields
    # ---------------------------------------------------------------
     
     
    set form_id "invoices_dynfield"
     
    template::form::create $form_id -has_submit 1
    template::form::section $form_id ""
     
    set object_type "im_invoice"
    set dynfield_project_type_id [im_opt_val project_type_id]
    if {[info exists project_id]} {
        set existing_project_type_id [db_string ptype "select project_type_id from im_projects where project_id = :project_id" -default 0]
        if {0 != $existing_project_type_id && "" != $existing_project_type_id} {
            set dynfield_project_type_id $existing_project_type_id
        }
    }
     
    set dynfield_invoice_id 0
    if {[info exists invoice_id]} { set dynfield_invoice_id $invoice_id }
     
    set apd ""
     
    set dynfield_project_type_id ""
     
    set field_cnt [im_dynfield::append_attributes_to_form \
        -object_subtype_id $dynfield_project_type_id \
        -object_type $object_type \
        -form_id $form_id \
        -object_id $dynfield_invoice_id \
    		   ]
    if {![info exists ajax_post_data]} { 
        set ajax_post_data ""
    }

    ———————————————————————————-
    f) Patch /web/projop/packages/intranet-invoices/www/new.adp
    ———————————————————————————-

    <master src="../../intranet-core/www/master">
    <property name="title">@page_title;noquote@</property>
    <property name="main_navbar_label">finance</property>
    <property name="sub_navbar">@sub_navbar;noquote@</property>
     
    <if @show_dynfield_tab_p@ eq 1>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/element/element-min.js"></script>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/tabview/tabview-min.js"></script>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/yahoo/yahoo-min.js"></script>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/event/event-min.js"></script>
    <script src="http://yui.yahooapis.com/2.8.2r1/build/connection/connection_core-min.js"></script>
    <script type="text/javascript" src="http://yui.yahooapis.com/2.8.2r1/build/button/button-min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.8.2r1/build/tabview/assets/skins/sam/tabview.css">
    </if>
     
    <% 
        # Determine a security token to authenticate the AJAX function
        set auto_login [im_generate_auto_login -user_id [ad_get_user_id]] 
    %>
     
    <script type="text/javascript">
     
     
     
    var global_eval = true;
     
    function evalReturnValue(type, value, mandatory_p) {
            switch (type)
            {
            case "date":
                    if ('--' == value && 'f' == mandatory_p) {
                            return "";
                    } else  if (isValidDate(value,'yyyy/mm/dd')){
                            return value;
                    } else {
                            alert('Please verify date');
                            global_eval = false;
                            return "";
                    }
            case "text":
                    if ('' == value && 't' == mandatory_p) {
                            alert('Please provide value - mandatory fields');
                            global_eval = false;
                            return "";
                    } else {
                            return value;
                    }
            default:
                    return value;
            }
    }
    function isValidDate(date_string, format) {
        //http://lawrence.ecorp.net/inet/samples/regexp-validate.php
        var days = [0,31,28,31,30,31,30,31,31,30,31,30,31];
        var year, month, day, date_parts = null;
        var rtrn = false;
        var decisionTree = {
            'm/d/y':{
                're':/^(\d{1,2})[./-](\d{1,2})[./-](\d{2}|\d{4})$/,
                'month': 1,'day': 2, year: 3
            },
            'mm/dd/yy':{
                're':/^(\d{1,2})[./-](\d{1,2})[./-](\d{2})$/,
                'month': 1,'day': 2, year: 3
            },
            'mm/dd/yyyy':{
                're':/^(\d{1,2})[./-](\d{1,2})[./-](\d{4})$/,
                'month': 1,'day': 2, year: 3
            },
            'y/m/d':{
                're':/^(\d{2}|\d{4})[./-](\d{1,2})[./-](\d{1,2})$/,
                'month': 2,'day': 3, year: 1
            },
            'yy/mm/dd':{
                're':/^(\d{1,2})[./-](\d{1,2})[./-](\d{1,2})$/,
                'month': 2,'day': 3, year: 1
            },
            'yyyy/mm/dd':{
                're':/^(\d{4})[./-](\d{1,2})[./-](\d{1,2})$/,
                'month': 2,'day': 3, year: 1
            }
        };
        var test = decisionTree[format];
        if (test) {
            date_parts = date_string.match(test.re);
            if (date_parts) {
                year = date_parts[test.year];
                month = date_parts[test.month];
                day = date_parts[test.day];
     
                test = (month == 2 &&
                        isLeapYear() &&
                        29 ||
                        days[month] || 0);
     
                rtrn = 1 <= day && day <= test;
            }
        }
        function isLeapYear() {
            return (year % 4 != 0 ? false :
                ( year % 100 != 0? true:
                ( year % 1000 != 0? false : true)));
        }
        return rtrn;
    }//eof isValidDate
     
     
    // YUI Tabs 
    var myTabs = new YAHOO.widget.TabView("demo");
     
    // 
     
    function ltrim(str, chars) {
    	chars = chars || "\\s";
    	return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
    }
     
    function ajaxFunction() {
        var xmlHttp1;
        var xmlHttp2;
        try {
    	// Firefox, Opera 8.0+, Safari
    	xmlHttp1=new XMLHttpRequest();
    	xmlHttp2=new XMLHttpRequest();
        }
        catch (e) {
    	// Internet Explorer
    	try {
    	    xmlHttp1=new ActiveXObject("Msxml2.XMLHTTP");
    	    xmlHttp2=new ActiveXObject("Msxml2.XMLHTTP");
    	}
    	catch (e) {
    	    try {
    		xmlHttp1=new ActiveXObject("Microsoft.XMLHTTP");
    		xmlHttp2=new ActiveXObject("Microsoft.XMLHTTP");
    	    }
    	    catch (e) {
    		alert("Your browser does not support AJAX!");
    		return false;
    	    }
    	}
        }
     
        xmlHttp1.onreadystatechange = function() {
    	if(xmlHttp1.readyState==4) {
    	    // empty options
    	    for (i = document.invoice.invoice_office_id.options.length-1; i >= 0; i--) { 
    		document.invoice.invoice_office_id.remove(i); 
    	    }
     
    	    // loop through the komma separated list
    	    var res1 = xmlHttp1.responseText;
    	    var opts1 = res1.split("|");
    	    for (i=0; i < opts1.length; i = i+2) {
    		var newOpt = new Option(opts1[i+1], opts1[i], false, true);
    		document.invoice.invoice_office_id.options[document.invoice.invoice_office_id.options.length] = newOpt;
    	    }
    	}
        }
     
        xmlHttp2.onreadystatechange = function() {
    	if(xmlHttp2.readyState==4) {
    	    // empty options
    	    for (i = document.invoice.company_contact_id.options.length-1; i >= 0; i--) { 
    		document.invoice.company_contact_id.remove(i); 
    	    }
    	    // loop through the komma separated list
    	    var res2 = xmlHttp2.responseText;
    	    var opts2 = res2.split("|");
    	    // alert(opts2);	    
    	    for (i=0; i < opts2.length; i = i+2) {
    		//alert (opts2[i]);
    		var newOpt = new Option(opts2[i+1], ltrim(opts2[i]), false, true);
    		document.invoice.company_contact_id.options[document.invoice.company_contact_id.options.length] = newOpt;
    	    }
    	}
        }
     
        // get the company_id from the customer's drop-down
        var company_id = document.invoice.@ajax_company_widget@.value;
        xmlHttp1.open("GET","/intranet/offices/ajax-offices?user_id=@user_id@&auto_login=@auto_login@&company_id="+company_id,true);
        xmlHttp1.send(null);
        xmlHttp2.open("GET","/intranet/users/ajax-company-contacts?user_id=@user_id@&auto_login=@auto_login@&company_id="+company_id,true);
        xmlHttp2.send(null);
    }
    </script>
     
    <if @show_dynfield_tab_p@ eq 1>
    <div class="yui-skin-sam">
     
    <div id="demo" class="yui-navset">
        <ul class="yui-nav">
            <li class="selected"><a href="#tab1"><em>Invoice</em></a></li>
            <li><a href="#tab2"><em>Dynamic Invoice Elements</em></a></li>
        </ul>            
     
    <div class="yui-content">
    <div>
     
    </if>
     
    <form action=new-2 name=invoice method=POST>
    <%= [export_form_vars invoice_id return_url] %>
     
    <!-- Include a list of projects related to this document -->
    @select_project_html;noquote@
     
    <if @cost_center_hidden@ defined>
    @cost_center_hidden;noquote@
    </if>
     
    <table border=0 width="100%">
    <tr><td>
     
      <table cellpadding=0 cellspacing=0 bordercolor=#6699CC border=0 width="100%">
        <tr valign=top> 
          <td>
     
            <table border=0 cellPadding=0 cellspacing=2 width="100%">
     
     
    	        <tr><td align=middle class=rowtitle colspan=2>#intranet-invoices.cost_type_Data#</td></tr>
    	        <tr>
    	          <td class=rowodd>#intranet-invoices.cost_type_nr#</td>
    	          <td class=rowodd> 
    	            <input type=text name=invoice_nr size=15 value='@invoice_nr@'>
    	          </td>
    	        </tr>
    	        <tr> 
    	          <td class=roweven>#intranet-invoices.cost_type_date#</td>
    	          <td class=roweven> 
    	            <input type=text name=invoice_date size=15 value='@effective_date@'>
    	          </td>
    	        </tr>
    <if @cost_center_select@ defined>
    	        <tr> 
    	          <td class=roweven>@cost_center_label@</td>
    	          <td class=roweven>
    		  @cost_center_select;noquote@
    	          </td>
    	        </tr>
    </if>
    	        <tr> 
    	          <td class=roweven>#intranet-invoices.Payment_terms#</td>
    	          <td class=roweven> 
    	            <input type=text name=payment_days size=5 value='@payment_days@'>
    	            #intranet-invoices.days#</td>
    	        </tr>
    	        <tr> 
    	          <td class=rowodd>#intranet-invoices.Payment_Method#</td>
    	          <td class=rowodd>@payment_method_select;noquote@</td>
    	        </tr>
     
    	        <tr> 
    	          <td class=roweven> #intranet-invoices.cost_type_template#</td>
    	          <td class=roweven>@template_select;noquote@</td>
    	        </tr>
    	        <tr> 
    	          <td class=rowodd>#intranet-invoices.cost_type_status#</td>
    	          <td class=rowodd>@status_select;noquote@</td>
    	        </tr>
    	        <tr> 
    	          <td class=roweven>#intranet-invoices.cost_type_type#</td>
    	          <td class=roweven>@type_select;noquote@</td>
    	        </tr>
     
            </table>
     
          </td>
          <td></td>
          <td>
            <table border=0 cellspacing=2 cellpadding=0 width="100%">
     
    <if @invoice_or_quote_p@>
    <!-- Let the user select the company. Provider=Internal -->
     
    		<tr>
    		  <td align=center valign=top class=rowtitle colspan=2>#intranet-invoices.Company#</td>
    		</tr>
    		<tr>
    		  <td class=roweven>#intranet-core.Customer#</td>
    		  <td class=roweven>@customer_select;noquote@</td>
    		</tr>
    		<input type=hidden name=provider_id value=@provider_id@>
    </if>
    <else>
     
    		<tr>
    		  <td align=center valign=top class=rowtitle colspan=2>#intranet-invoices.Provider#</td>
    		</tr>
    		<tr>
    		  <td class=roweven>#intranet-invoices.Provider_1#</td>
    		  <td class=roweven>@provider_select;noquote@</td>
    		</tr>
    		<input type=hidden name=customer_id value=@customer_id@>
    </else>
     
     
    		<tr>
    		  <td class=rowodd>@invoice_address_label@</td>
    		  <td class=rowodd>@invoice_address_select;noquote@</td>
    		</tr>
     
    		<tr>
    		  <td class=rowodd>#intranet-core.Contact#</td>
    		  <td class=rowodd>@contact_select;noquote@</td>
    		</tr>
     
    <if @canned_note_enabled_p@>
    		<tr>
    		  <td class=roweven><%= [lang::message::lookup "" intranet-invoices.Canned_Note "Canned Note"] %></td>
    	          <td class=roweven>
    <if 0>
    		    <%= [im_category_select -translate_p 0 -include_empty_p 1 -include_empty_name "-- Please Select --" -plain_p 1 -cache_interval 0 "Intranet Invoice Canned Note" canned_note_id $canned_note_id] %>
     
    </if>
    <else>
    		    <%= [im_category_select_multiple -translate_p 0 "Intranet Invoice Canned Note" canned_note_id $canned_note_id 3] %>
    </else>
    		  </td>
    		</tr>
    </if>
    		<tr>
    		  <td class=roweven>#intranet-invoices.Note#</td>
    	          <td class=roweven>
    		    <textarea name=note rows=6 cols=40 wrap="<%=[im_html_textarea_wrap]%>">@cost_note@</textarea>
    		  </td>
    		</tr>
     
     
            </table>
        </tr>
      </table>
     
    </td></tr>
    <tr><td>
     
      <table width="100%" align=right border=0>
        <tr>
          <td align=right>
     
     	<table border=0 cellspacing=2 cellpadding=1 width="100%">
    	<!-- the list of task sums, distinguised by type and UOM -->
    	@task_sum_html;noquote@
     
    <if @discount_enabled_p@>
            <tr>
              <td> 
              </td>
              <td colspan=99 align=right> 
                <table border=0 cellspacing=1 cellpadding=0>
                  <tr> 
                    <td>#intranet-invoices.Discount# &nbsp;</td>
                    <td><input type=text name=discount_text value="@discount_text@"> </td>
                    <td><input type=text name=discount_perc value="@discount_perc@" size=4> % &nbsp;</td>
                  </tr>
                </table>
              </td>
            </tr>
    </if>
    <if @surcharge_enabled_p@>
            <tr>
              <td> 
              </td>
              <td colspan=99 align=right> 
                <table border=0 cellspacing=1 cellpadding=0>
                  <tr> 
                    <td>#intranet-invoices.Surcharge# &nbsp;</td>
                    <td><input type=text name=surcharge_text value="@surcharge_text@"> </td>
                    <td><input type=text name=surcharge_perc value="@surcharge_perc@" size=4> % &nbsp;</td>
                  </tr>
                </table>
              </td>
            </tr>
    </if>
            <tr>
              <td> 
              </td>
              <td colspan=@vat_colspan@ align=right> 
                <table border=0 cellspacing=1 cellpadding=0>
                  <tr> 
                    <td>#intranet-invoices.VATnbsp#</td>
                    <td><input type=text name=vat value="@vat@" size=4> % &nbsp;</td>
                  </tr>
    <if @tax_enabled_p@>
                  <tr> 
                    <td>#intranet-invoices.TAXnbsp#</td>
                    <td><input type=text name=tax value="@tax@" size=4> % &nbsp;</td>
                  </tr>
    </if>
    <else>
                  <input type=hidden name=tax value="@tax@">
    </else>
                </table>
              </td>
            </tr>
            <tr> 
              <td>&nbsp; </td>
              <td colspan=6 align=right> 
                  <input type=submit name=submit value="@button_text@">
              </td>
            </tr>
     
            </table>
          </td>
        </tr>
      </table>
     
     
    </td></tr>
    </table>
     
    </form>
     
    </div>
     
     
    <div>
     
     
    <if @show_dynfield_tab_p@ eq 1>
    	<formtemplate id="invoices_dynfield"></formtemplate>
    	<input type="button" id="btn_save_dynfields" name="btn_save_dynfields" value="Save"> 
     
    	<script type="text/javascript">
    	var sUrl = ""
    	var postData = ""
     
    	function saveDynfields(p_oEvent) {
    		sUrl = "/intranet-rest/im_invoice/@invoice_id;noquote@"
    		postData = "<?xml version='1.0'?><im_invoice>" + @ajax_post_data;noquote@ + "</im_invoice>";
    		var request = YAHOO.util.Connect.asyncRequest('POST', sUrl, callback, postData); 
    	}
     
    	// Button  
    	var oPushButton2 = new YAHOO.widget.Button("btn_save_dynfields"); 
    	oPushButton2.on("click", saveDynfields); 
     
    	var handleSuccess = function(o){
    		alert("Successfully saved");
    		window.location = "/intranet-invoices/view?invoice_id=" + @invoice_id;noquote@;
    	}
     
    	var handleFailure = function(o){
    		alert("Failure transmitting data, please review data")
    	}	
     
     
    	var callback =
    	{
    	  success:handleSuccess,
    	  failure: handleFailure,
    	  argument: ['foo','bar']
    	};
     
    	</script>
     
    	</div>
    	</div>
    </if>
     
    </div>
    </div>

    Problem:

    • Expense Bundles might have been created with outdated exchange rates.
    • This feature shows the updated amount

    [po35devklaus@project-open-v34 www]$ cvs diff –context bundle-new.tcl
    Index: bundle-new.tcl
    ===================================================================
    RCS file: /home/cvsroot/intranet-expenses/www/bundle-new.tcl,v
    retrieving revision 1.17.4.2
    diff –context -r1.17.4.2 bundle-new.tcl
    *** bundle-new.tcl 17 Feb 2011 15:58:51 -0000 1.17.4.2
    — bundle-new.tcl 25 Feb 2011 13:02:36 -0000
    ***************
    *** 24,29 ****
    — 24,30 —-
    {return_url “/intranet-expenses/index”}
    { form_mode “display” }
    enable_master_p:integer,optional
    + { enable_updated_exchange_rates_p 0 }
    { printer_friendly_p 0 }
    { render_template_id:integer 0 }
    }
    ***************
    *** 226,234 ****
    } else {
    set amount_elems {
    {amount:text(hidden)}
    ! {amount_with_vat:text(calculated_sql),optional {label {Amount
    (inc. VAT)}} {custom {sql {select trim(to_char(amount * (1 + vat / 100), ’99999999999.99′)) from im_costs where cost_id = $bundle_id}}} }
    }
    }

    set elements1 {
    {currency:text(select) {label $currency_label} {options $currency_options} }
    — 227,246 —-
    } else {
    set amount_elems {
    {amount:text(hidden)}
    ! {amount_with_vat:text(calculated_sql),optional {label {Amount
    (inc. VAT) created}} {custom {sql {select trim(to_char(amount * (1 + vat / 100), ’99999999999.99′)) from im_costs where cost_id = $bundle_id}}} }
    }
    }
    +
    + if { $enable_updated_exchange_rates_p } {
    + set amount_elems [lappend amount_elems {amount_with_vat_recalculated:text(calculated_sql),optional {label {Amount
    (inc. VAT) updated}} {custom {sql { \
    + select \
    + sum(coalesce((select round((amount * (1 + vat / 100)) * im_exchange_rate(effective_date::date, currency, 'EUR'):: numeric, 2)),0)) as amount_converted \
    + from \
    + im_costs \
    + where \
    + cost_id in (select expense_id from im_expenses where bundle_id = $bundle_id) \
    + }}}}]
    + }

    set elements1 {
    {currency:text(select) {label $currency_label} {options $currency_options} }
    [po35devklaus@project-open-v34 www]$