summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LedgerSMB/Form.pm2
-rw-r--r--LedgerSMB/Sysconfig.pm1
-rw-r--r--UI/payments/payment1.html14
-rw-r--r--UI/payments/payment2.html26
-rw-r--r--scripts/payment.pl81
-rw-r--r--sql/modules/Payment.sql28
6 files changed, 117 insertions, 35 deletions
diff --git a/LedgerSMB/Form.pm b/LedgerSMB/Form.pm
index b8cd8f70..1d61ac09 100644
--- a/LedgerSMB/Form.pm
+++ b/LedgerSMB/Form.pm
@@ -89,7 +89,7 @@ sub new {
my $argstr = shift;
- if ($ENV{CONTENT_LENGTH} > $LedgerSMB::Sysconfig::max_post_size; ) {
+ if ($ENV{CONTENT_LENGTH} > $LedgerSMB::Sysconfig::max_post_size) {
print "Status: 413\n Request entity too large\n\n";
die "Error: Request entity too large\n";
}
diff --git a/LedgerSMB/Sysconfig.pm b/LedgerSMB/Sysconfig.pm
index 58267be8..1d93ce8f 100644
--- a/LedgerSMB/Sysconfig.pm
+++ b/LedgerSMB/Sysconfig.pm
@@ -7,7 +7,6 @@ package LedgerSMB::Sysconfig;
use LedgerSMB::Form;
use Config::Std;
use DBI qw(:sql_types);
-
binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';
diff --git a/UI/payments/payment1.html b/UI/payments/payment1.html
index 1df90592..d928dd33 100644
--- a/UI/payments/payment1.html
+++ b/UI/payments/payment1.html
@@ -17,11 +17,15 @@
<form name="search" method="post" action="payment.pl">
<?lsmb PROCESS elements.html # Include form elements helper. -?>
-<?lsmb login.type = 'hidden' ; PROCESS input element_data=login -?>
-<?lsmb accountclass.type = 'hidden'; PROCESS input element_data=accountclass -?>
-<?lsmb type.type = "hidden";
- PROCESS input element_data=type;
- -?>
+<?lsmb login.type = 'hidden' ; INCLUDE input element_data=login -?>
+<?lsmb accountclass.type = 'hidden'; INCLUDE input element_data=accountclass -?>
+<?lsmb # The first_load field is required on payment2.html to initialize discounts the first time, on each subsequent update it wont exist-?>
+<?lsmb INCLUDE input element_data={
+ name => 'first_load',
+ id => 'first_load',
+ type => 'hidden',
+ value => 'on'} ?>
+<?lsmb type.type = "hidden"; INCLUDE input element_data=type; -?>
<table width="100%">
<tr id="top-bar" class="listtop">
<th id="top-bar-header" class="listtop"><label id="top-bar-header-label"><?lsmb text('Receipts') ?></th>
diff --git a/UI/payments/payment2.html b/UI/payments/payment2.html
index e2824349..58a997d6 100644
--- a/UI/payments/payment2.html
+++ b/UI/payments/payment2.html
@@ -157,12 +157,19 @@ onLoad="maximize_minimize_on_load('div_topay_state', 'UI/payments/img/down.gif',
<td><?lsmb row.invoice_date ?></td>
<td><?lsmb row.amount ?></td>
<td><?lsmb row.paid ?></td>
+<<<<<<< .mine
<td><?lsmb row.discount ?></td>
+ <td align="center"><input name="<?lsmb "optional_discount_$row.invoice.id" -?>" id="<?lsmb
+ "optional_discount_$row.invoice.id" -?>" type="checkbox" class="checkbox"<?lsmb IF
+ row.optional_discount OR first_load -?> checked <?lsmb END -?> ></td>
+=======
+ <td><?lsmb row.discount ?></td>
+>>>>>>> .r2199
<td><?lsmb row.due ?></td>
<?lsmb IF defaultcurrency.text != curr.value ?>
<td><?lsmb row.exchange_rate ?></td>
- <td><?lsmb row.due_fx ?></td>
- <td><div id="<?lsmb "div_topay_invoice_$i" ?>"><?lsmb row.topay ?></div></td>
+ <td><?lsmb row.due ?></td>
+ <td><div id="<?lsmb "div_topay_invoice_$i" ?>"><?lsmb row.due_fx ?></div></td>
<?lsmb END ?>
<?lsmb #This should be computed and updated to the div using ?>
<td><?lsmb row.topay_fx.id = row.topay_fx.name ;INCLUDE input element_data=row.topay_fx;
@@ -290,11 +297,24 @@ onLoad="maximize_minimize_on_load('div_topay_state', 'UI/payments/img/down.gif',
<option value="<?lsmb item -?>"><?lsmb item -?></option>
<?lsmb END -?>
</select>
- <input name="overpayment_source2_<?lsmb overpayment_item ?>" id="overpayment_source2_<?lsmb overpayment_item ?>" />
+ <input name="overpayment_source2_<?lsmb overpayment_item -?>" id="overpayment_source2_<?lsmb overpayment_item -?>"/>
<input type="hidden" name="overpayment_qty" id="overpayment_qty" value="<?lsmb overpayment_item ?>" />
</td>
+<<<<<<< .mine
+ <td align="center"><input name="overpayment_memo_<?lsmb overpayment_item -?>" id="overpayment_memo_<?lsmboverpayment_item ?>" /></td>
+ <td align="center">
+ <input
+ name="overpayment_topay_<?lsmb overpayment_item -?>"
+ id="overpayment_topay_<?lsmboverpayment_item ?>"
+ value="<?lsmb IF unhandled_overpayment.value > 0 -?>
+ <?lsmb unhandled_overpayment.value -?>
+ <?lsmb END -?>"
+ />
+ </td>
+=======
<td align="center"><input name="overpayment_memo_<?lsmb overpayment_item -?>" id="overpayment_memo_<?lsmboverpayment_item ?>" /></td>
<td align="center"><input name="overpayment_topay_<?lsmb overpayment_item -?>" id="overpayment_topay_<?lsmboverpayment_item ?>" /></td>
+>>>>>>> .r2199
<td align="center"><input type="checkbox" name="overpayment_checkbox_<?lsmb overpayment_item -?>"/></td>
</tr>
<tr class="listsubtotal">
diff --git a/scripts/payment.pl b/scripts/payment.pl
index 986cd764..dd3a309d 100644
--- a/scripts/payment.pl
+++ b/scripts/payment.pl
@@ -555,6 +555,7 @@ my @array_options;
my @currency_options;
my $exchangerate;
# LETS GET THE CUSTOMER/VENDOR INFORMATION
+
($Payment->{entity_credit_id}, $Payment->{company_name}) = split /--/ , $request->{'vendor-customer'};
# WE NEED TO RETRIEVE A BILLING LOCATION, THIS IS HARDCODED FOR NOW... Should we change it?
@@ -579,7 +580,8 @@ my @account_options = $Payment->list_accounting();
# LETS GET THE POSSIBLE SOURCES
my @sources_options = $Payment->get_sources(\%$locale);
# WE MUST PREPARE THE ENTITY INFORMATION
-@array_options = $Payment->get_vc_info();
+#@array_options = $Payment->get_vc_info();# IS THIS WORKING?
+
# LETS BUILD THE CURRENCIES INFORMATION
# FIRST, WE NEED TO KNOW THE DEFAULT CURRENCY
my $default_currency = $Payment->get_default_currency();
@@ -595,6 +597,7 @@ my @column_headers = ({text => $locale->text('Invoice')},
{text => $locale->text('Total').$default_currency_text},
{text => $locale->text('Paid').$default_currency_text},
{text => $locale->text('Discount').$default_currency_text},
+ {text => $locale->text('Apply Disc')},
{text => $locale->text('Amount Due').$default_currency_text},
{text => $locale->text('To pay').$default_currency_text}
);
@@ -642,27 +645,46 @@ my @column_headers = ({text => $locale->text('Invoice')},
my @invoice_data;
my @topay_state; # WE WILL USE THIS TO HELP UI TO DETERMINE WHAT IS VISIBLE
@array_options = $Payment->get_open_invoices();
-
+my $unhandled_overpayment;
for my $ref (0 .. $#array_options) {
if ( !$request->{"checkbox_$array_options[$ref]->{invoice_id}"}) {
# SHOULD I APPLY DISCCOUNTS?
-
+ $request->{"optional_discount_$array_options[$ref]->{invoice_id}"} = $request->{first_load}? "on": $request->{"optional_discount_$array_options[$ref]->{invoice_id}"};
+
# LETS SET THE EXCHANGERATE VALUES
my $due_fx; my $topay_fx_value;
if ("$exchangerate") {
$topay_fx_value = $due_fx = "$array_options[$ref]->{due}"/"$exchangerate" - "$array_options[$ref]->{discount}"/"$exchangerate";
+ if ($request->{"optional_discount_$array_options[$ref]->{invoice_id}"}) {
+ $topay_fx_value = $due_fx = $due_fx - "$array_options[$ref]->{discount}"/"$exchangerate";
+ }
} else {
$topay_fx_value = $due_fx = "N/A";
}
+# We need to check for unhandled overpayment, see the post function for details
+# First we will see if the discount should apply?
+ my $temporary_discount = 0;
+ if (($request->{"optional_discount_$array_options[$ref]->{invoice_id}"})&&($due_fx <= $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} + $array_options[$ref]->{discount}/"$exchangerate")) {
+ $temporary_discount = "$array_options[$ref]->{discount}"/"$exchangerate";
+
+ }
+# We need to compute the unhandled_overpayment, notice that all the values inside the if already have
+# the exchangerate applied
+ if ( $due_fx < $request->{"topay_fx_$array_options[$ref]->{invoice_id}"}) {
+ # We need to store all the overpayments so we can use it on the screen
+ $unhandled_overpayment = $unhandled_overpayment + $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} - $due_fx ;
+ $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} = $due_fx;
+ }
push @invoice_data, { invoice => { number => $array_options[$ref]->{invnumber},
id => $array_options[$ref]->{invoice_id},
href => 'ar.pl?id='."$array_options[$ref]->{invoice_id}"
},
invoice_date => "$array_options[$ref]->{invoice_date}",
amount => "$array_options[$ref]->{amount}",
- due => "$array_options[$ref]->{due}" - "$array_options[$ref]->{discount}",
+ due => $request->{"optional_discount_$array_options[$ref]->{invoice_id}"}? "$array_options[$ref]->{due}" - "$array_options[$ref]->{discount}": "$array_options[$ref]->{due}",
paid => "$array_options[$ref]->{amount}" - "$array_options[$ref]->{due}",
- discount => "$array_options[$ref]->{discount}",
+ discount => $request->{"optional_discount_$array_options[$ref]->{invoice_id}"} ? "$array_options[$ref]->{discount}" : 0 ,
+ optional_discount => $request->{"optional_discount_$array_options[$ref]->{invoice_id}"},
exchange_rate => "$exchangerate",
due_fx => $due_fx, # This was set at the begining of the for statement
topay => "$array_options[$ref]->{due}" - "$array_options[$ref]->{discount}",
@@ -738,7 +760,10 @@ if (${LedgerSMB::Sysconfig::latex}) {
push @format_options, {value => 2, text => "PDF" }, {value => 3, text => "POSTSCRIPT" };
}
# LETS BUILD THE SELECTION FOR THE UI
+# Notice that the first data inside this selection is the firs_load, this
+# will help payment2.html to know wether it is beeing called for the first time
my $select = {
+ first_load => $request->{first_load},
stylesheet => $request->{_user}->{stylesheet},
header => { text => $request->{type} eq 'receipt' ? $locale->text('Receipt') : $locale->text('Payment') },
type => { name => 'type',
@@ -774,7 +799,7 @@ my $select = {
vendorcustomer => { name => 'vendor-customer',
value => $request->{'vendor-customer'}
},
-
+ unhandled_overpayment => { name => 'unhandledoverpayment', value => $unhandled_overpayment } ,
vc => { name => $Payment->{company_name}, # We will assume that the first Billing Information as default
address => [ {text => $vc_options[0]->{'line_one'}},
{text => $vc_options[0]->{'line_two'}},
@@ -808,6 +833,7 @@ eval {$template->render($select) };
}
+
=pod
=item post_payment
@@ -824,7 +850,7 @@ my ($request) = @_;
my $locale = $request->{_locale};
my $Payment = LedgerSMB::DBObject::Payment->new({'base' => $request});
# LETS GET THE CUSTOMER/VENDOR INFORMATION
-($Payment->{entity_id}, $Payment->{company_name}) = split /--/ , $request->{'vendor-customer'};
+($Payment->{entity_credit_id}, $Payment->{company_name}) = split /--/ , $request->{'vendor-customer'};
# LETS GET THE DEPARTMENT INFO
# WE HAVE TO SET $dbPayment->{department_id} in order to process
if ($request->{department}) {
@@ -849,10 +875,11 @@ $Payment->{approved} = 'true';
# Variable definition
#
# We use the prefix op to refer to the overpayment variables.
-my $overpayment; # This variable might be fuzzy, we are using it to handle invalid data
- # i.e. a user set an overpayment qty inside an invoice.
+my $unhandled_overpayment = 0; # This variable might be fuzzy, we are using it to handle invalid data
+ # i.e. a user set an overpayment qty inside an invoice.
my @array_options;
my @amount;
+my @discount;
my @cash_account_id;
my @source;
my @transaction_id;
@@ -865,33 +892,53 @@ my @op_account_id;
# We need the invoices in order to process the income data, this is done this way
# since the data we have isn't indexed in any way.
#
-
+# Ok, we want to use the disccount information in order to do some accounting movements,
+# we will process it with the same logic for a regular payment, and see where does this leave us.
+@array_options = $Payment->get_entity_credit_account();# We need to know the disccount account
+my $discount_account_id = $array_options[0]->{discount};
@array_options = $Payment->get_open_invoices();
for my $ref (0 .. $#array_options) {
if ( !$request->{"checkbox_$array_options[$ref]->{invoice_id}"}) {
+ # First i have to determine if discounts will apply
+ # we will assume that a discount should apply only
+ # if this is the last payment of an invoice
+ my $temporary_discount = 0;
+ if (($request->{"optional_discount_$array_options[$ref]->{invoice_id}"})&&("$array_options[$ref]->{due}"/"$request->{exrate}" <= $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} + $array_options[$ref]->{discount})) {
+ $temporary_discount = $array_options[$ref]->{discount};
+ }
#
# The prefix cash is to set the movements of the cash accounts,
# same names are used for ap/ar accounts w/o the cash prefix.
#
- # Maybe i should move this to another sub, so i can call it from payment2 as well :). D.M.
- if ($array_options[$ref]->{amount} < $request->{"topay_$array_options[$ref]->{invoice_id}"} ) {
- # THERE IS AN OVERPAYMENT!, we should store it and see if we can use it on the UI
- $overpayment = $overpayment + $request->{"topay_$array_options[$ref]->{invoice_id}"} - $array_options[$ref]->{amount};
- $request->{"topay_$array_options[$ref]->{invoice_id}"} = $request->{"topay_$array_options[$ref]->{invoice_id}"};
+ if ( "$array_options[$ref]->{due}"/"$request->{exrate}" < $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} + $temporary_discount ) {
+ # We need to store all the overpayments so we can use it on a new payment2 screen
+ $unhandled_overpayment = $unhandled_overpayment + $request->{"topay_fx_$array_options[$ref]->{invoice_id}"} + $temporary_discount - $array_options[$ref]->{amount} ;
+
}
+ if ($request->{"optional_discount_$array_options[$ref]->{invoice_id}"}) {
+ push @amount, $array_options[$ref]->{discount};
+ push @cash_account_id, $discount_account_id;
+ push @source, $locale->text('Applied discount');
+ push @transaction_id, $array_options[$ref]->{invoice_id};
+ }
push @amount, $request->{"topay_fx_$array_options[$ref]->{invoice_id}"}; # We'll use this for both cash and ap/ar accounts
push @cash_account_id, $request->{"optional_pay_$array_options[$ref]->{invoice_id}"} ? $request->{"account_$array_options[$ref]->{invoice_id}"} : $request->{account};
push @source, $request->{"source1_$array_options[$ref]->{invoice_id}"}.' '.$request->{"source2_$array_options[$ref]->{invoice_id}"}; # We'll use this for both source and ap/ar accounts
push @transaction_id, $array_options[$ref]->{invoice_id};
}
}
+# Check if there is an unhandled overpayment and run payment2 as needed
+
+if ($unhandled_overpayment) {
+&payment2($request);
+return 0;
+}
#
# Now we need the overpayment information.
#
# We will use the prefix op to indicate it is an overpayment information.
#
# note: I love the for's C-like syntax.
-
for (my $i=1 ; $i <= $request->{overpayment_qty}; $i++) {
if (!$request->{"overpayment_checkbox_$i"}) { # Is overpayment marked as deleted ?
if ( $request->{"overpayment_topay_$i"} ) { # Is this overpayment an used field?
@@ -909,7 +956,6 @@ for (my $i=1 ; $i <= $request->{overpayment_qty}; $i++) {
}
}
}
-
# Finally we store all the data inside the LedgerSMB::DBObject::Payment object.
$Payment->{cash_account_id} = $Payment->_db_array_scalars(@cash_account_id);
$Payment->{amount} = $Payment->_db_array_scalars(@amount);
@@ -935,5 +981,6 @@ for (my $i=1 ; $i <= $request->{overpayment_qty}; $i++) {
}
+
eval { do "scripts/custom/payment.pl"};
1;
diff --git a/sql/modules/Payment.sql b/sql/modules/Payment.sql
index 8f0317e5..6e935b81 100644
--- a/sql/modules/Payment.sql
+++ b/sql/modules/Payment.sql
@@ -1,13 +1,24 @@
+
+CREATE TYPE payment_vc_info AS (
+ id int,
+ name text,
+ entity_class int,
+ discount int
+);
+
+
CREATE OR REPLACE FUNCTION payment_get_entity_accounts
(in_account_class int,
in_vc_name text,
in_vc_idn int)
- returns SETOF entity AS
+ returns SETOF payment_vc_info AS
$$
- DECLARE out_entity entity%ROWTYPE;
+ DECLARE out_entity payment_vc_info;
+
+
BEGIN
FOR out_entity IN
- SELECT ec.id, cp.legal_name as name, e.entity_class, e.created
+ SELECT ec.id, cp.legal_name as name, e.entity_class, ec.discount_account_id
FROM entity e
JOIN entity_credit_account ec ON (ec.entity_id = e.id)
JOIN company cp ON (cp.entity_id = e.id)
@@ -110,6 +121,7 @@ BEGIN
SELECT id, invnumber, transdate, amount, entity_id,
2 AS invoice_class, paid, curr,
entity_credit_account, department_id
+
FROM ar
) a
JOIN (SELECT trans_id, chart_id, sum(CASE WHEN in_account_class = 1 THEN amount
@@ -137,7 +149,8 @@ BEGIN
AND (a.amount <= in_amountto
OR in_amountto IS NULL)
AND (a.department_id = in_department_id
- OR in_department_id IS NULL)
+ OR in_department_id IS NULL)
+ AND due <> 0
GROUP BY a.invnumber, a.transdate, a.amount, discount, ac.due, a.id, c.discount_terms
LOOP
RETURN NEXT payment_inv;
@@ -554,7 +567,7 @@ BEGIN
INSERT INTO acc_trans (chart_id, amount,
trans_id, transdate, approved, source)
VALUES (in_cash_account_id[out_count],
- CASE WHEN in_account_class = 2 THEN in_amount[out_count]
+ CASE WHEN in_account_class = 1 THEN in_amount[out_count]
ELSE in_amount[out_count]* - 1
END,
in_transaction_id[out_count], in_datepaid, coalesce(in_approved, true),
@@ -576,7 +589,7 @@ BEGIN
INSERT INTO acc_trans (chart_id, amount,
trans_id, transdate, approved, source)
VALUES (var_account_id,
- CASE WHEN in_account_class = 2 THEN in_amount[out_count] * -1
+ CASE WHEN in_account_class = 1 THEN in_amount[out_count] * -1
ELSE in_amount[out_count]
END,
in_transaction_id[out_count], in_datepaid, coalesce(in_approved, true),
@@ -740,7 +753,6 @@ CREATE TYPE payment_location_result AS (
class text
);
-
--
-- payment_get_vc_info has the same arch as company__list_locations, except for the filtering capabilities
-- This should be unified on the API when we get things working - David Mora
@@ -748,7 +760,7 @@ CREATE TYPE payment_location_result AS (
CREATE OR REPLACE FUNCTION payment_get_vc_info(in_entity_credit_id int, in_location_class_id int)
RETURNS SETOF payment_location_result AS
$$
-DECLARE out_row RECORD;
+DECLARE out_row payment_location_result;
BEGIN
FOR out_row IN
SELECT l.id, l.line_one, l.line_two, l.line_three, l.city,