Commit 5c4af97a authored by Frank Bergmann's avatar Frank Bergmann

This commit was generated by cvs2svn to track changes on a CVS vendor

branch.
parents c8839bb6 18447b4b
-- /packages/intranet-invoices/sql/oracle/intranet-invoices-backup.sql
--
-- Copyright (C) 2004 Project/Open
-- Copyright (C) 2003-2004 Project/Open
--
-- This program is free software. You can redistribute it
-- and/or modify it under the terms of the GNU General
-- Public License as published by the Free Software Foundation;
-- either version 2 of the License, or (at your option)
-- any later version. This program is distributed in the
-- hope that it will be useful, but WITHOUT ANY WARRANTY;
-- without even the implied warranty of MERCHANTABILITY or
-- FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU General Public License for more details.
-- All rights reserved. Please check
-- http://www.project-open.com/license/ for details.
--
-- @author frank.bergmann@project-open.com
-- @author frank.bergmann@project-open.com
-- 100 im_projects
-- 101 im_project_roles
......@@ -303,15 +296,15 @@ delete from im_views where view_id = 193;
insert into im_views (view_id, view_name, view_sql
) values (193, 'im_project_invoice_map', '
SELECT
pg.group_name as project_name,
p.project_name,
i.invoice_nr
FROM
im_project_invoice_map m,
user_groups pg,
acs_rels r,
project p,
im_invoices i
WHERE
m.project_id = pg.group_id
and m.invoice_id = i.invoice_id
r.object_id_one = p.project_id
and r.object_id_two = i.invoice_id
');
......
-- /package/intranet-invoices/sql/oracle/intranet-invoices-create.sql
--
-- Invoices module for Project/Open
-- Copyright (c) 2003-2004 Project/Open
--
-- (c) 2003 Frank Bergmann (fraber@fraber.de)
-- All rights reserved. Please check
-- http://www.project-open.com/license/ for details.
--
-- @author frank.bergmann@project-open.com
-- Invoices module for Project/Open
--
-- Defines:
-- im_invoices Invoice biz object container
-- im_invoice_items Invoice lines
-- im_projects_invoices_map Maps projects -> invoices
-- im_prices List of prices with defaults
--
-- An invoice basically is a container of im_invoice_lines.
......@@ -166,26 +170,22 @@ end im_invoices_audit_tr;
/
show errors
-----------------------------------------------------------
-- Invoice Items
--
-- - Invoice items reflect the very fuzzy structure of invoices,
-- that may contain basicly everything that fits in one line
-- and has a price.
-- - Invoice items are generated typically from im_tasks, plus
-- a invoice price, derived(!) from the price list.
-- However, all elements (number of units, price, description)
-- need to be human editable.
--
-- Tasks and Invoice Items are similar because they both represent
-- substructures of an invoice or a project. However, im_tasks
-- are supposed to be more strongly formalized (type, status, ...),
-- while Invoice Items contain the actually billed price and
-- represent the dirty reality.
-- - Invoice items can created manually or generated from
-- "invoicable items" such as im_trans_tasks or similar.
-- All fields (number of units, price, description) need to be
-- human editable because invoicing is so messy...
--
-- Invoicable Tasks and Invoice Items are similar because they
-- both represent substructures of a project or an invoice.
-- However, im_trans_tasks are more formalized (type, status, ...),
-- while Invoice Items contain free text fields, only _derived_
-- from im_trans_tasks and prices. Dirty business world... :-(
create sequence im_invoice_items_seq start with 1;
create table im_invoice_items (
......@@ -225,27 +225,15 @@ create table im_invoice_items (
-- particularly if it is a big project.
--
-- So there is a N:M relation between these two, and we
-- need a mapping table. Also, this table allows us to
-- need a mapping table. This table allows us to
-- avoid inserting a "invoice_id" column in the im_projects
-- table, thus reducing the dependency between the "core"
-- module and the "invoices" module, allowing for example
-- for several different invoices modules.
--
create table im_project_invoice_map (
project_id integer not null
constraint im_proj_inv_map_project
references im_projects,
invoice_id integer not null
constraint im_proj_inv_map_invoice
references im_invoices
);
-- keep the project-invoice-map clean!
create unique index im_project_invoice_map_idx on im_project_invoice_map (
project_id,
invoice_id
);
-- 040403 fraber: We are now using acs_rels instead of
-- im_project_invoice_map:
-- acs_rels: object_id_one=project_id, object_id_two=invoice_id
------------------------------------------------------
......@@ -301,80 +289,6 @@ where category_type = 'Intranet Invoice Payment Method';
-- Procedures
--
-- Calculate a match value between a price list item and an invoice_item
-- The higher the match value the better the fit.
create or replace function im_calculate_price_relevancy (
v_price_customer_id IN integer, v_item_customer_id IN integer,
v_price_task_type_id IN integer, v_item_task_type_id IN integer,
v_price_subject_area_id IN integer, v_item_subject_area_id IN integer,
v_price_target_language_id IN integer, v_item_target_language_id IN integer,
v_price_source_language_id IN integer, v_item_source_language_id IN integer
)
RETURN number IS
match_value number;
BEGIN
match_value := 0;
if v_price_task_type_id = v_item_task_type_id then
match_value := match_value + 4;
end if;
if not(v_price_task_type_id is null) and v_price_task_type_id != v_item_task_type_id then
match_value := match_value - 4;
end if;
if v_price_source_language_id = v_item_source_language_id then
match_value := match_value + 3;
end if;
if not(v_price_source_language_id is null) and v_price_source_language_id != v_item_source_language_id then
match_value := match_value - 10;
end if;
if v_price_target_language_id = v_item_target_language_id then
match_value := match_value + 2;
end if;
if not(v_price_target_language_id is null) and v_price_target_language_id != v_item_target_language_id then
match_value := match_value - 10;
end if;
if v_price_subject_area_id = v_item_subject_area_id then
match_value := match_value + 1;
end if;
if not(v_price_subject_area_id is null) and v_price_subject_area_id != v_item_subject_area_id then
match_value := match_value - 10;
end if;
if v_price_customer_id = v_item_customer_id then
match_value := (match_value + 6)*2;
end if;
if v_price_customer_id = 17 then
match_value := match_value + 1;
end if;
if v_price_customer_id != 17 and v_price_customer_id != v_item_customer_id then
match_value := match_value -10;
end if;
return match_value;
END;
/
show errors;
-- Calculate the price for a task_type/customer
create or replace function im_invoice_calculate_price (
v_customer_id IN integer,
v_project_id IN integer,
v_task_type_id IN integer,
v_task_uom_id IN integer
)
RETURN number IS
BEGIN
if v_task_uom_id = 320 then
return 30.00;
end if;
if v_task_uom_id = 324 then
return 0.085;
end if;
return 1.000;
END;
/
show errors;
-- What currency to use?
create or replace function im_invoice_calculate_currency (v_customer_id IN integer)
RETURN varchar IS
BEGIN
......@@ -635,14 +549,27 @@ begin
plugin_name => 'Project Invoice Component',
package_name => 'intranet-invoices',
page_url => '/intranet/projects/view',
location => 'right',
location => 'left',
sort_order => 10,
component_tcl =>
'im_invoices_project_component $project_id'
);
end;
/
-- Show the invoice component in customers page
--
declare
v_plugin integer;
begin
v_plugin := im_component_plugin.new (
plugin_name => 'Customer Invoice Component',
package_name => 'intranet-invoices',
page_url => '/intranet/customers/view',
location => 'left',
sort_order => 10,
component_tcl =>
'im_table_with_title "Invoices" \
[im_invoice_component \
$user_id \
$project_id
]'
'im_invoices_customer_component $customer_id'
);
end;
/
......
-- Copyright (C) 1999-2004 ArsDigita, Frank Bergmann and others
-- /packages/intranet-invoices/sql/oracle/intranet-invoices-drop.sql
--
-- This program is free software. You can redistribute it
-- and/or modify it under the terms of the GNU General
-- Public License as published by the Free Software Foundation;
-- either version 2 of the License, or (at your option)
-- any later version. This program is distributed in the
-- hope that it will be useful, but WITHOUT ANY WARRANTY;
-- without even the implied warranty of MERCHANTABILITY or
-- FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU General Public License for more details.
-- Copyright (C) 2003-2004 Project/Open
--
-- All rights reserved. Please check
-- http://www.project-open.com/license/ for details.
--
-- @author frank.bergmann@project-open.com
BEGIN
......@@ -18,7 +15,7 @@ END;
/
commit;
delete from im_project_invoice_map;
delete from acs_rels r where r.object_id_two in (select invoice_id from im_invoices;)
delete from im_invoice_items;
delete from im_invoices;
......@@ -30,7 +27,6 @@ drop sequence im_prices_seq;
drop sequence im_invoices_seq;
drop sequence im_invoice_items_seq;
drop table im_project_invoice_map;
drop table im_invoice_items;
drop table im_invoices_audit;
......
# /tcl/intranet-invoice.tcl
# /packages/intranet-invoicing/tcl/intranet-invoice.tcl
#
# Copyright (C) 2003-2004 Project/Open
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
ad_library {
Bring together all "components" (=HTML + SQL code)
related to Invoices
@author fraber@fraber.de
@creation-date 27 June 2003
@author frank.bergann@project-open.com
}
ad_proc -public im_invoices_navbar { default_letter base_url next_page_url prev_page_url export_var_list } {
Returns rendered HTML code for a horizontal sub-navigation
bar for /intranet-invoices/.
......@@ -81,7 +84,7 @@ select
to_char(sysdate, 'YYYY_MM')||'_'||
trim(to_char(1+max(i.nr),'0000')) as invoice_nr
from
(select substr(invoice_nr,9,4) as nr from im_invoices_active
(select substr(invoice_nr,9,4) as nr from im_invoices
where substr(invoice_nr, 1,7)=to_char(sysdate, 'YYYY_MM')
UNION
select '0000' as nr from dual
......@@ -97,12 +100,28 @@ where
ascii(substr(i.nr,4,1)) < 58
"
set invoice_nr [db_string next_invoice_nr $sql -default ""]
ns_log Notice "im_next_invoice_nr: invoice_nr=$invoice_nr"
return $invoice_nr
}
ad_proc im_invoice_component { {customer_id ""} {project_id ""} } {
ad_proc im_invoices_customer_component { customer_id } {
Returns a HTML table containing a list of invoices for a particular
customer.
} {
return [im_invoices_base_component $customer_id ""]
}
ad_proc im_invoices_project_component { project_id } {
Returns a HTML table containing a list of invoices for a particular
particular project.
} {
return [im_invoices_base_component "" $project_id]
}
ad_proc im_invoices_base_component { {customer_id ""} {project_id ""} } {
Returns a HTML table containing a list of invoices for a particular
customer or a particular project.
} {
......@@ -172,7 +191,7 @@ order by
db_foreach recent_invoices $invoices_sql {
append invoice_html "
<tr$bgcolor([expr $ctr % 2])>
<td><A href=/intranet/invoices/view?invoice_id=$invoice_id>$invoice_nr</A></td>
<td><A href=/intranet-invoices/view?invoice_id=$invoice_id>$invoice_nr</A></td>
<td>$calculated_due_date</td>
<td>$invoice_amount $invoice_currency</td>
<td>$payment_amount $payment_currency</td>
......@@ -187,7 +206,7 @@ order by
append invoice_html "
<tr$bgcolor([expr $ctr % 2])>
<td colspan=$colspan>
<A HREF=/intranet/invoices/index?status_id=0&[export_url_vars status_id customer_id project_id]>
<A HREF=/intranet-invoices/index?status_id=0&[export_url_vars status_id customer_id project_id]>
more invoices...
</A>
</td>
......@@ -200,6 +219,29 @@ order by
<td colspan=$colspan align=center>
<I>No invoices yet for this project</I>
</td>
</tr>\n"
incr ctr
}
if {"" != $customer_id} {
append invoice_html "
<tr>
<td colspan=$colspan align=left>
<A href=/intranet-invoices/new?customer_id=$customer_id>
Create a new invoice from scratch
</A>
</td>
</tr>\n"
}
if {"" != $project_id} {
append invoice_html "
<tr>
<td colspan=$colspan align=left>
<A href=/intranet-invoices/new?project_id=$project_id>
Create a new invoice for this project
</A>
</td>
</tr>\n"
}
......@@ -207,7 +249,8 @@ order by
return $invoice_html
}
ad_proc im_invoice_select { select_name { default "" } { status "" } { exclude_status "" } } {
ad_proc im_invoices_select { select_name { default "" } { status "" } { exclude_status "" } } {
Returns an html select box named $select_name and defaulted to
$default with a list of all the invoices in the system. If status is
......
# /www/intranet/invoices/invoice-action.tcl
# /packages/intranet-invoices/www/invoice-action.tcl
#
# Copyright (C) 2003-2004 Project/Open
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
ad_page_contract {
Purpose: Takes commands from the /intranet/invoices/index
......@@ -6,6 +12,7 @@ ad_page_contract {
@param return_url the url to return to
@param group_id group id
@author frank.bergmann@project-open.com
} {
return_url:optional
del_invoice:multiple,optional
......@@ -74,8 +81,8 @@ switch $submit {
"
set delete_map_sql "
delete from im_project_invoice_map m
where m.invoice_id in $invoice_where_list
delete from acs_rels r
where r.object_id_two in $invoice_where_list
"
set delete_invoices_sql "
......
# /packages/intranet-invoices/www/new-2.tcl
#
# Copyright (C) 2003-2004 Project/Open
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
ad_page_contract {
Purpose: Save invoice changes and set the invoice status to "Created"
or higher.
@author frank.bergmann@project-open.com
} {
invoice_id:integer
{ customer_id:integer 0 }
{ provider_id:integer 0 }
invoice_nr
invoice_date
{ invoice_type_id 700 }
payment_days:integer
payment_method_id:integer
invoice_template_id:integer
vat
tax
item_sort_order:array
item_name:array
item_units:array
item_uom_id:integer,array
item_type_id:integer,array
item_project_id:integer,array
item_rate:array
item_currency:array
{ return_url "/intranet-invoices/" }
}
# ---------------------------------------------------------------
# Defaults & Security
# ---------------------------------------------------------------
set user_id [ad_maybe_redirect_for_registration]
if {![im_permission $user_id view_invoices]} {
ad_return_complaint "Insufficient Privileges" "
<li>You don't have sufficient privileges to see this page."
}
set invoice_status_created [db_string invoice_status "select invoice_status_id from im_invoice_status where upper(invoice_status)='CREATED'"]
set invoice_status_in_process [db_string invoice_status "select category_id from im_categories where category_type='Intranet Invoice Status' and upper(category)='IN PROCESS'"]
set project_status_invoiced [db_string project_status "select category_id from im_categories where category_type='Intranet Project Status' and upper(category)='INVOICED'"]
set customer_internal [db_string customer_internal "select customer_id from im_customers where lower(customer_path) = 'internal'" -default 0]
if {!$customer_internal} {
ad_return_complaint 1 "<li>Unable to find 'Internal' customer with path 'internal'. <br>Maybe somebody has change the path of the customer?"
return
}
if {!$provider_id} { set provider_id $customer_internal }
if {!$customer_id} { set customer_id $customer_internal }
# ---------------------------------------------------------------
# 0. Update invoice base data
# ---------------------------------------------------------------
set invoice_exists_p [db_string invoice_count "select count(*) from im_invoices where invoice_id=:invoice_id"]
if {!$invoice_exists_p} {
db_dml create_invoice "
INSERT INTO im_invoices (
invoice_id,
invoice_nr,
customer_id,
provider_id,
invoice_date,
payment_days,
payment_method_id,
invoice_template_id,
vat,
tax,
invoice_status_id,
invoice_type_id,
last_modified,
last_modifying_user,
modified_ip_address
) VALUES (
:invoice_id,
:invoice_nr,
:customer_id,
:provider_id,
:invoice_date,
:payment_days,
:payment_method_id,
:invoice_template_id,
:vat,
:tax,
:invoice_status_created,
:invoice_type_id,
sysdate,
:user_id,
'[ad_conn peeraddr]'
)"
} else {
db_dml update_im_invoices "
UPDATE im_invoices
SET
invoice_nr=:invoice_nr,
invoice_date=:invoice_date,
payment_days=:payment_days,
payment_method_id=:payment_method_id,
invoice_template_id=:invoice_template_id,
vat=:vat,
tax=:tax
WHERE
invoice_id=:invoice_id
"
}
# ---------------------------------------------------------------
# 1. Create the new "im_invoice_items"
# ---------------------------------------------------------------
# Delete the old items
db_dml delete_invoice_items "
DELETE from im_invoice_items
WHERE invoice_id=:invoice_id
"
set item_list [array names item_name]
foreach nr $item_list {
set name $item_name($nr)
set units $item_units($nr)
set uom_id $item_uom_id($nr)
set type_id $item_type_id($nr)
set project_id $item_project_id($nr)
set rate $item_rate($nr)
set currency $item_currency($nr)
set sort_order $item_sort_order($nr)
ns_log Notice "item($nr, $name, $units, $uom_id, $project_id, $rate, $currency)"
# Insert only if it's not an empty line from the edit screen
if {"" != [string trim $name] || 0 != $units} {
set item_id [db_nextval "im_invoice_items_seq"]
set insert_invoice_items_sql "
INSERT INTO im_invoice_items (
item_id, item_name, project_id, invoice_id, item_units, item_uom_id,
price_per_unit, currency, sort_order, item_type_id, item_status_id, description
) VALUES (
:item_id, :name, :project_id, :invoice_id, :units, :uom_id,
:rate, :currency, :sort_order, :type_id, null, ''
)"
db_dml insert_invoice_items $insert_invoice_items_sql
}
}
# ---------------------------------------------------------------
# Update the invoice status from "In Process" to "Created"
# ---------------------------------------------------------------
# only if
db_dml update_invoice_status "
UPDATE im_invoices set invoice_status_id=:invoice_status_created
WHERE
invoice_id=:invoice_id
and invoice_status_id=:invoice_status_in_process
"
db_release_unused_handles
ad_returnredirect "/intranet-invoices/view?invoice_id=$invoice_id"
# /www/intranet/invoices/new.tcl
# /packages/intranet-invoices/www/new.tcl
#
# Copyright (C) 2003-2004 Project/Open
#
# All rights reserved. Please check
# http://www.project-open.com/license/ for details.
# ---------------------------------------------------------------
# 1. Page Contract
......@@ -7,16 +12,16 @@
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-4.tcl, which takes the final
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".
@author frank.bergmann@project-open.com
@cvs-id index.tcl,v 3.24.2.9 2000/09/22 01:38:44 kevin Exp
} {
{ include_task:multiple "" }
{ invoice_id:integer ""}
{ customer_id:integer 0}
{ project_id:integer ""}
{ invoice_currency "EUR"}
{ return_url "/intranet-invoice/"}
}
......@@ -47,6 +52,22 @@ set bgcolor(0) " class=roweven"
set bgcolor(1) " class=rowodd"
set required_field "<font color=red size=+1><B>*</B></font>"
# Tricky case: Sombebody has called this page from a project
# So we need to find out the customer of the project and create
# an invoice from scratch, invoicing all project elements.
#
# However, invoices are created in very different ways in
# each business sector:
# - Translation: Sum up the im_trans_tasks and determine the
# price from im_translation_prices.
# - IT: Create invoices from scratch, from hours or from
# (monthly|quarterly|...) service fees
#
if {"" != $project_id} {
set customer_id [db_string customer_id "select customer_id from im_projects where project_id=:project_id"]
}
# ---------------------------------------------------------------
# 3. Gather invoice data
# a: if the invoice already exists
......@@ -382,7 +403,7 @@ ns_log Notice "new: before joining the parts together"
set page_body "
[im_invoices_navbar "none" "/intranet/invoices/index" "" "" [list]]
<form action=new-4 method=POST>
<form action=new-2 method=POST>
[export_form_vars invoice_id return_url]
<!-- Invoice Data and Customer Tables -->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment