pax_global_header 0000666 0000000 0000000 00000000064 14560726663 0014531 g ustar 00root root 0000000 0000000 52 comment=201f7e511b74d82a36d4343c22f3bd2416e8231b
intranet-timesheet2-invoices-master/ 0000775 0000000 0000000 00000000000 14560726663 0020076 5 ustar 00root root 0000000 0000000 intranet-timesheet2-invoices-master/README.md 0000664 0000000 0000000 00000020651 14560726663 0021361 0 ustar 00root root 0000000 0000000 # ]po[ Timesheet Invoices
This package is part of ]project-open[, an open-source enterprise project management system.
For more information about ]project-open[ please see:
* [Documentation Wiki](https://www.project-open.com/en/)
* [V5.0 Download](https://sourceforge.net/projects/project-open/files/project-open/V5.0/)
* [Installation Instructions](https://www.project-open.com/en/list-installers)
About ]po[ Timesheet Invoices :
The Timesheet Invoices Package forms the bridge between the internal record keeping of timesheets, and the preparation of billable invoices to ship to the customer. It transforms the timesheets kept for each client company, and each project being labored on for that client company into an invoice. Parameters can be specified throughout the creation process on whether to include or exclude certain tasks within a project on the invoice, and to further modify the billing schemes per task.
Saves invoice changes and set the invoice status to "Created".<br> Please note that there are different forms to create invoices for example in the intranet-timesheet2-invoicing module of the intranet-server-hosting module.
/intranet/companies/upload-prices-2.tcl Read a .csv-file with header titles exactly matching the data model and insert the data into im_timesheet_prices
[_ intranet-core.Note]:
[lang::message::lookup "" intranet-timesheet2-invoices.From_and_Through_overlap_bla "
From and Through dates are time points at 0:00 midnight of their specific date,
which is equivlent to say that the from date is inclusive and the through date is exclusive.
Sequential prices should have first.through = second.from,
for example 2024-01-01 to 2025-01-01 and 2025-01-01 to 2026-01-01."]
[_ intranet-timesheet2-invoices.Upload_prices]
[_ intranet-timesheet2-invoices.lt_for_this_company_via_]
[lang::message::lookup "" intranet-timesheet2-invoices.All_existing_prices_will_be_deleted "All existing prices for this company will be deleted."]
"
return $price_list_html
}
# ------------------------------------------------------
# The list of hours per project
# ------------------------------------------------------
ad_proc im_timesheet_invoicing_project_hierarchy {
{ -include_task "" }
-select_project:required
-start_date:required
-end_date:required
{ -filter_status_id "" }
-invoice_hour_type:required
} {
Returns a formatted HTML table representing the list of subprojects
and their logged hours.
} {
set bgcolor(0) " class=roweven"
set bgcolor(1) " class=rowodd"
set default_material_id [im_material_default_material_id]
set default_material_name [db_string matname "select acs_object__name(:default_material_id)"]
set max_project_name_length [parameter::get_from_package_key -package_key intranet-timesheet2-invoices -parameter "InvoiceFromTimesheetTasksProjectNameMaxSize" -default 40]
set show_project_nr_p [parameter::get_from_package_key -package_key intranet-timesheet2-invoices -parameter "InvoiceFromTimesheetTasksShowProjectNrP" -default 0]
set project_nr_table_header_row ""
if {$show_project_nr_p} {
set project_nr_table_header_row "
"
set planned_checked ""
set billable_checked ""
set reported_checked ""
set interval_checked ""
set new_checked ""
set unbilled_checked ""
switch $invoice_hour_type {
planned { set planned_checked " checked" }
billable { set billable_checked " checked" }
reported { set reported_checked " checked" }
interval { set interval_checked " checked" }
new { set new_checked " checked" }
unbilled { set unbilled_checked " checked" }
}
set invoice_radio_disabled ""
if {"" != $invoice_hour_type} {
set invoice_radio_disabled "disabled"
} else {
set planned_checked " checked"
}
# Show a line with with the selected invoicing type
set select_row_colspan 3
if {$show_project_nr_p} { incr select_row_colspan }
set extra_where ""
if {"" ne $filter_status_id} {
set extra_where "and children.project_status_id in ([join [im_sub_categories $filter_status_id] ","])"
}
append task_table_rows "
Please select the type of hours to use:
"
set sql "
select
parent.project_id as parent_id,
parent.project_nr as parent_nr,
parent.project_name as parent_name,
children.project_id,
substring(children.project_name for :max_project_name_length) as project_name,
children.project_nr,
(select count(*) from im_projects childchild where childchild.parent_id = children.project_id) as children_count,
im_category_from_id(children.project_status_id) as project_status,
im_category_from_id(children.project_type_id) as project_type,
tree_level(children.tree_sortkey) - tree_level(parent.tree_sortkey) as level,
t.task_id,
round(t.planned_units * 100) / 100.0 as planned_units,
round(t.billable_units * 100) / 100.0 as billable_units,
t.uom_id,
m.material_name,
m.material_billable_p,
im_category_from_id(t.uom_id) as uom_name,
(select sum(h.hours) from im_hours h where h.project_id = children.project_id) as all_reported_hours,
(select sum(h.days) from im_hours h where h.project_id = children.project_id) as all_reported_days,
(select sum(h.hours) from im_hours h where
h.project_id = children.project_id
and h.day >= to_timestamp(:start_date, 'YYYY-MM-DD')
and h.day < to_timestamp(:end_date, 'YYYY-MM-DD')
) as hours_in_interval,
(select sum(h.days) from im_hours h where
h.project_id = children.project_id
and h.day >= to_timestamp(:start_date, 'YYYY-MM-DD')
and h.day < to_timestamp(:end_date, 'YYYY-MM-DD')
) as days_in_interval,
(select sum(h.hours) from im_hours h where
h.project_id = children.project_id
and h.invoice_id is null
) as unbilled_hours,
(select sum(h.days) from im_hours h where
h.project_id = children.project_id
and h.invoice_id is null
) as unbilled_days
from
im_projects parent,
im_projects children
LEFT OUTER JOIN im_timesheet_tasks t ON (children.project_id = t.task_id)
LEFT OUTER JOIN im_materials m ON (t.material_id = m.material_id)
where
children.tree_sortkey between parent.tree_sortkey and tree_right(parent.tree_sortkey)
and parent.project_id in ([join $select_project ","])
$extra_where
order by
parent.project_name,
children.tree_sortkey
"
# ad_return_complaint 1 "
$sql
"
set ctr 0
set colspan 11
set old_parent_id 0
db_foreach select_tasks $sql {
if {"" == $material_name} { set material_name $default_material_name }
# insert intermediate headers for every project
if {$old_parent_id != $parent_id} {
append task_table_rows "
$parent_nr: $parent_name
\n"
set old_parent_id $parent_id
}
set indent ""
for {set i 0} {$i < $level} {incr i} {
append indent " "
}
set task_checked ""
set task_disabled ""
if {0 == [llength $include_task]} {
# Called from the Wizard Page - enabled tasks according to the task's material.
if {"f" != $material_billable_p} {
set task_checked "checked"
}
} else {
# View from the Invoice page - disable the checkbox (because it is not editable anymore).
if {[lsearch $include_task $project_id] > -1} {
set task_checked "checked"
}
set task_disabled "disabled"
}
# Super-Task? Units in super-tasks are not counted
if {$children_count > 0} {
set planned_units ""
set billable_units ""
}
if {"" == $uom_id} { set uom_id [im_uom_hour] }
switch $uom_id {
321 {
# Day
set all_reported_units $all_reported_days
set units_in_interval $days_in_interval
set unbilled_units $unbilled_days
}
320 {
# Hour
set all_reported_units $all_reported_hours
set units_in_interval $hours_in_interval
set unbilled_units $unbilled_hours
}
default {
set all_reported_units "-"
set units_in_interval "-"
set unbilled_units "-"
}
}
if {[string length $project_name] == $max_project_name_length} { set project_name "${project_name}..." }
set project_nr_table_row ""
if {$show_project_nr_p} {
set project_nr_table_row "
<%= [lang::message::lookup "" intranet-timesheet2-invoices.Timesheet_Invoicing_Wizard_help "
This wizard allows you to create a '@target_cost_type@' financial
document from project data in four different ways:"] %>
<%= [lang::message::lookup "" intranet-timesheet2-invoices.Planned_Units_help "Planned Units: Estimated number of hours for each task, as specified during project planning."] %>
<%= [lang::message::lookup "" intranet-timesheet2-invoices.Billable_Units_help "Billable Units: Billable number of hours for each task. Tends to be equal to Planned Units."] %>
<%= [lang::message::lookup "" intranet-timesheet2-invoices.All_Reported_Hours_help "All Reported Hours: All timesheet hours logged by anybody since the creation of the task or project."] %>
<%= [lang::message::lookup "" intranet-timesheet2-invoices.Reported_Units_Interval_help "Reported Units in Interval: Hours logged between 'Start Date' and 'End Date' (see filter above)."] %>
intranet-timesheet2-invoices-master/www/invoices/new-2.tcl 0000664 0000000 0000000 00000017123 14560726663 0024201 0 ustar 00root root 0000000 0000000 # /packages/intranet-timesheet2-invoices/www/new-2.tcl
#
# Copyright (c) 2003-2008 ]project-open[
#
# All rights reserved. Please check
# https://www.project-open.com/license/ for details.
# ---------------------------------------------------------------
# 1. Page Contract
# ---------------------------------------------------------------
ad_page_contract {
Receives a list of projects and displays all Tasks of these projects,
ordered by project, allowing the user to modify the "billable units".
Provides a button to advance to "new-3.tcl".
@author frank.bergmann@poject-open.com
} {
{ select_project:multiple }
invoice_currency
target_cost_type_id:integer
{ cost_center_id:integer 0}
{ start_date "" }
{ end_date "" }
{ filter_status_id "" }
{ return_url ""}
}
# ---------------------------------------------------------------
# 2. Defaults & Security
# ---------------------------------------------------------------
# User id already verified by filters
set user_id [auth::require_login]
set current_user_id $user_id
set current_url [im_url_with_query]
set page_focus "im_header_form.keywords"
set view_name "invoice_tasks"
set page_title "New Timesheet Invoice"
set context_bar [im_context_bar $page_title]
set bgcolor(0) " class=roweven"
set bgcolor(1) " class=rowodd"
set required_field "*"
if {![im_permission $user_id add_invoices]} {
ad_return_complaint "[_ intranet-timesheet2-invoices.lt_Insufficient_Privileg]" "
[_ intranet-timesheet2-invoices.lt_You_dont_have_suffici]"
}
# 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 && ($cost_center_id eq "" || $cost_center_id == 0)} {
ad_returnredirect [export_vars -base "/intranet-invoices/new-cost-center-select" {
{pass_through_variables {cost_type_id customer_id provider_id project_id invoice_currency create_invoice_from_template select_project source_cost_type_id target_cost_type_id start_date end_date}}
select_project
cost_type_id
source_cost_type_id
target_cost_type_id
customer_id
provider_id
project_id
invoice_currency
cost_center_id
start_date
end_date
create_invoice_from_template
{return_url $current_url}
}]
}
set target_cost_type [im_category_from_id $target_cost_type_id]
set allowed_cost_type [im_cost_type_write_permissions $current_user_id]
if {$target_cost_type_id ni $allowed_cost_type} {
ad_return_complaint "Insufficient Privileges" "
You can't create documents of type \#$target_cost_type_id."
ad_script_abort
}
if {[info exists select_project]} {
set project_id $select_project
if {[llength $select_project] > 1} {
set project_id [lindex $select_project 0]
}
set project_name [db_string project_name "select project_name from im_projects where project_id = :project_id" -default ""]
if {"" != $project_name} {
append page_title " for Project '$project_name'"
}
}
# ---------------------------------------------------------------------
# Sub-Navbar
# ---------------------------------------------------------------------
# Choose the right subnavigation bar
#
if {[llength $select_project] != 1} {
set sub_navbar [im_costs_navbar "none" "/intranet/invoicing/index" "" "" [list]]
} else {
# Setup the subnavbar
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]
}
# ---------------------------------------------------------------
# Check start- and end_date
# ---------------------------------------------------------------
# Check that Start & End-Date have correct format
if {"" != $start_date && ![regexp {[0-9][0-9][0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]} $start_date]} {
ad_return_complaint 1 "Start Date doesn't have the right format.
Current value: '$start_date'
Expected format: 'YYYY-MM-DD'"
}
if {"" != $end_date && ![regexp {[0-9][0-9][0-9][0-9]\-[0-9][0-9]\-[0-9][0-9]} $end_date]} {
ad_return_complaint 1 "End Date doesn't have the right format.
Current value: '$end_date'
Expected format: 'YYYY-MM-DD'"
}
set days_in_past 30
db_1row todays_date "
select
to_char(sysdate::date - :days_in_past::integer, 'YYYY') as start_year,
to_char(sysdate::date - :days_in_past::integer, 'MM') as start_month,
to_char(sysdate::date - :days_in_past::integer, 'DD') as start_day
from dual
"
if {"" == $start_date} {
set start_date "$start_year-$start_month-01"
}
set days_in_future "45 days"
db_1row end_date "
select
to_char(to_date(:start_date, 'YYYY-MM-DD') + :days_in_future::interval, 'YYYY') as end_year,
to_char(to_date(:start_date, 'YYYY-MM-DD') + :days_in_future::interval, 'MM') as end_month,
to_char(to_date(:start_date, 'YYYY-MM-DD') + :days_in_future::interval, 'DD') as end_day
from dual
"
if {"" == $end_date} {
set end_date "$end_year-$end_month-01"
}
# ---------------------------------------------------------------
# 3. Check the consistency of the select project and get client_id
# ---------------------------------------------------------------
# check that all projects are from the same client
set clients [db_list clients "
select distinct company_id
from im_projects
where project_id in ([join $select_project ","])
"]
if {[llength $clients] > 1} {
ad_return_complaint "[_ intranet-timesheet2-invoices.lt_You_have_selected_mul]" "
[_ intranet-timesheet2-invoices.lt_You_have_selected_mul_1]
[_ intranet-timesheet2-invoices.lt_Please_backup_and_res]"
return
}
# now we know that all projects are from a single company:
set company_id [lindex $clients 0]
# ---------------------------------------------------------------
# Format the Filter
# ---------------------------------------------------------------
set form_id "filter"
set object_type "im_project"
set action_url [export_vars -base [ns_conn url] {}]
set form_mode "edit"
set start_date_l10n "[lang::message::lookup "" intranet-timesheet2-invoices.Start_Date "Start Date"]"
set end_date_l10n "[lang::message::lookup "" intranet-timesheet2-invoices.End_Date "End Date"]"
ad_form \
-name $form_id \
-action $action_url \
-mode $form_mode \
-method GET \
-export {select_project target_cost_type_id invoice_currency cost_center_id } \
-form {
{start_date:text(text),optional {label $start_date_l10n}}
{end_date:text(text),optional {label $end_date_l10n}}
{filter_status_id:text(im_category_tree),optional {label "[_ intranet-timesheet2-tasks.Status]"} {custom {category_type "Intranet Project Status" translate_p 1}}}
}
template::element::set_value $form_id start_date $start_date
template::element::set_value $form_id end_date $end_date
# ---------------------------------------------------------------
# Get the list of tasks
# ---------------------------------------------------------------
set task_table_rows [im_timesheet_invoicing_project_hierarchy \
-select_project $select_project \
-start_date $start_date \
-end_date $end_date \
-filter_status_id $filter_status_id \
-invoice_hour_type "" \
]
intranet-timesheet2-invoices-master/www/invoices/new-3-postgresql.xql 0000664 0000000 0000000 00000002064 14560726663 0026423 0 ustar 00root root 0000000 0000000
postgresql7.2
select
c.*,
o.*,
c.default_invoice_template_id as template_id,
im_email_from_user_id(c.accounting_contact_id) as company_contact_email,
im_name_from_user_id(c.accounting_contact_id) as company_contact_name,
c.company_name,
c.company_path,
c.company_path as company_short_name,
cc.country_name
from
im_companies c
LEFT JOIN
im_offices o ON c.main_office_id=o.office_id
LEFT JOIN
country_codes cc ON o.address_country_code=cc.iso
where
c.company_id = :company_id
intranet-timesheet2-invoices-master/www/invoices/new-3.adp 0000664 0000000 0000000 00000015117 14560726663 0024165 0 ustar 00root root 0000000 0000000
@page_title;literal@@context_bar;literal@finance@sub_navbar;literal@