From: blake Date: Fri, 25 Mar 2016 21:42:15 +0000 (-0500) Subject: LP1174498 Payment by billing type breakdown X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=46024ab73101e09fe850516cbd23349aa5fdc7bb;p=working%2FEvergreen.git LP1174498 Payment by billing type breakdown Corrected a situation where account_adjustment payments were not paying the intended billing line items. The new function algorithm attempts to find a billing line item for the exact amount of the payment in the case of account_adjustment payment type. Signed-off-by: blake --- diff --git a/Open-ILS/src/sql/Pg/080.schema.money.sql b/Open-ILS/src/sql/Pg/080.schema.money.sql index 79c8ed5dae..3686841217 100644 --- a/Open-ILS/src/sql/Pg/080.schema.money.sql +++ b/Open-ILS/src/sql/Pg/080.schema.money.sql @@ -689,20 +689,22 @@ CREATE OR REPLACE VIEW money.cashdrawer_payment_view AS LEFT JOIN money.payment_view t ON (p.id = t.id); CREATE TABLE money.materialized_payment_by_billing_type ( - id BIGSERIAL PRIMARY KEY, - xact BIGINT NOT NULL, - payment BIGINT NOT NULL, - billing BIGINT NOT NULL, - payment_ts TIMESTAMPTZ NOT NULL, - billing_ts TIMESTAMPTZ NOT NULL, - amount NUMERIC(8,2) NOT NULL, - payment_type TEXT, - billing_type TEXT, - payment_ou INT, - billing_ou INT, + id BIGSERIAL PRIMARY KEY, + xact BIGINT NOT NULL, + payment BIGINT NOT NULL, + billing BIGINT NOT NULL, + payment_ts TIMESTAMPTZ NOT NULL, + billing_ts TIMESTAMPTZ NOT NULL, + amount NUMERIC(8,2) NOT NULL, + payment_type TEXT, + billing_type TEXT, + payment_ou INT, + billing_ou INT, -- Debug billing_leftover NUMERIC(8,2), -- Debug payment_leftover NUMERIC(8,2), - CONSTRAINT x_p_b_once UNIQUE (xact,payment,billing) +-- Debug used_billings BIGINT[], +-- Debug billing_l INT, + CONSTRAINT x_p_b_once UNIQUE (xact,payment,billing) ); CREATE INDEX p_by_b_payment_ts_idx @@ -715,19 +717,25 @@ CREATE OR REPLACE FUNCTION money.payment_by_billing_type ( ) RETURNS SETOF money.materialized_payment_by_billing_type AS $$ DECLARE - current_result money.materialized_payment_by_billing_type%ROWTYPE; - current_payment money.payment_view%ROWTYPE; - current_billing money.billing%ROWTYPE; - payment_remainder NUMERIC(8,2) := 0.0; - billing_remainder NUMERIC(8,2) := 0.0; - payment_offset INT := 0; - billing_offset INT := 0; - billing_ou INT := 0; - payment_ou INT := 0; + current_result money.materialized_payment_by_billing_type%ROWTYPE; + current_payment money.payment_view%ROWTYPE; + current_billing money.billing%ROWTYPE; + payment_remainder NUMERIC(8,2) := 0.0; + billing_remainder NUMERIC(8,2) := 0.0; + payment_offset INT := 0; + billing_offset INT := 0; + billing_ou INT := 0; + payment_ou INT := 0; fast_forward BOOLEAN := FALSE; maintain_billing_remainder BOOLEAN := FALSE; billing_loop INT := -1; billing_row_count INT := 0; + current_billing_id BIGINT := 0; + billing_id_used BIGINT ARRAY; + billing_l INT := 0; + continuing_payment BOOLEAN := FALSE; + continuing_payment_last_row BOOLEAN := FALSE; + BEGIN /* This algorithm is fairly straight-forward. We take a transaction id @@ -767,7 +775,7 @@ BEGIN ORDER BY payment_ts LOOP - payment_remainder = current_payment.amount; + payment_remainder = current_payment.amount; -- With every new payment row, we need to fast forward -- the billing lines up to the last paid billing row fast_forward := TRUE; @@ -780,73 +788,87 @@ BEGIN payment_ou = billing_ou; END IF; - -- Were we looking at a billing from a previous step in the loop? - IF billing_remainder > 0.0 THEN - current_result.xact = p_xact; - current_result.payment = current_payment.id; - current_result.billing = current_billing.id; - current_result.payment_ts = current_payment.payment_ts; - current_result.billing_ts = current_billing.billing_ts; - current_result.payment_type = current_payment.payment_type; - current_result.billing_type = current_billing.billing_type; - current_result.payment_ou = payment_ou; - current_result.billing_ou = billing_ou; + -- Were we looking at a billing from a previous step in the loop? + IF billing_remainder > 0.0 THEN + current_result.xact = p_xact; + current_result.payment = current_payment.id; + current_result.billing = current_billing.id; + current_result.payment_ts = current_payment.payment_ts; + current_result.billing_ts = current_billing.billing_ts; + current_result.payment_type = current_payment.payment_type; + current_result.billing_type = current_billing.billing_type; + current_result.payment_ou = payment_ou; + current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; - IF billing_remainder >= payment_remainder THEN - current_result.amount = payment_remainder; - billing_remainder = billing_remainder - payment_remainder; - payment_remainder = 0.0; - payment_offset = payment_offset + 1; + IF billing_remainder >= payment_remainder THEN + current_result.amount = payment_remainder; + billing_remainder = billing_remainder - payment_remainder; + payment_remainder = 0.0; + payment_offset = payment_offset + 1; -- If it is equal then we need to close up the billing line and move to the next -- This prevents 0 amounts applied to billing lines IF billing_remainder = payment_remainder THEN billing_remainder = 0.0; - billing_offset = billing_offset + 1; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); ELSE maintain_billing_remainder := TRUE; END IF; - ELSE - current_result.amount = billing_remainder; - payment_remainder = payment_remainder - billing_remainder; - billing_remainder = 0.0; + ELSE + current_result.amount = billing_remainder; + payment_remainder = payment_remainder - billing_remainder; + billing_remainder = 0.0; billing_offset = billing_offset + 1; - END IF; + billing_id_used = array_append( billing_id_used, current_billing_id ); + continuing_payment := TRUE; + END IF; - RETURN NEXT current_result; + RETURN NEXT current_result; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; - END IF; - - CONTINUE WHEN payment_remainder = 0.0; + EXIT WHEN array_length(billing_id_used, 1) = billing_row_count; + END IF; + CONTINUE WHEN payment_remainder = 0.0; + -- next billing, please - + billing_loop := -1; + FOR current_billing IN SELECT * FROM money.billing WHERE xact = p_xact - -- AND NOT voided -- Gotta put the voided billing rows at the bottom (last) ORDER BY voided,billing_ts LOOP - -- Fast forward through the rows until we get to the billing row - -- where we left off - IF fast_forward THEN - billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 - CONTINUE WHEN billing_loop <> billing_offset; + billing_loop = billing_loop + 1; + + -- Skip billing rows that we have already paid + IF billing_id_used @> ARRAY[current_billing.id] THEN CONTINUE; + END IF; + + IF maintain_billing_remainder THEN + CONTINUE WHEN current_billing.id <> current_billing_id; + -- Account adjustment - we expect to pay billing rows that are identical amounts + ELSE IF current_payment.payment_type = 'account_adjustment' THEN + -- Go ahead and allow the row through when it's the last row and we still haven't found one with equal payment amount + CONTINUE WHEN ( ( current_billing.amount <> current_payment.amount ) AND ( billing_loop + 1 <> billing_row_count ) ); + END IF; END IF; -- Keep the old remainder if we were in the middle of a billing row IF NOT maintain_billing_remainder THEN - billing_remainder = current_billing.amount; + billing_remainder = current_billing.amount; END IF; - maintain_billing_remainder := FALSE; - billing_loop := -1; + maintain_billing_remainder := FALSE; fast_forward := FALSE; + current_billing_id := current_billing.id; + continuing_payment := FALSE; current_result.xact = p_xact; current_result.payment = current_payment.id; @@ -859,36 +881,98 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; billing_remainder = billing_remainder - payment_remainder; - IF NOT current_billing.voided THEN - payment_remainder = 0.0; - END IF; + payment_remainder = 0.0; -- If it is equal then we need to close up the billing line and move to the next -- This prevents 0 amounts applied to billing lines IF billing_remainder = payment_remainder THEN billing_remainder = 0.0; - billing_offset = billing_offset + 1; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); END IF; ELSE current_result.amount = billing_remainder; - IF NOT current_billing.voided THEN - payment_remainder = payment_remainder - billing_remainder; - END IF; + payment_remainder = payment_remainder - billing_remainder; + continuing_payment := TRUE; + IF billing_loop + 1 = billing_row_count THEN + -- We have a situation where we are on the last billing row and we are in the middle of a payment row + -- We need to start back at the beginning of the billing rows and pay + continuing_payment_last_row := TRUE; + END IF; billing_remainder = 0.0; billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); END IF; RETURN NEXT current_result; - + IF continuing_payment_last_row THEN + -- This should only occur when the account_adjustment's do not line up exactly with the billing + -- So we are going to pay some other type of billing row with this odd account_adjustment + -- And we need to stay in the current_payment row while doing so + billing_loop := -1; + FOR current_billing IN + SELECT * + FROM money.billing + WHERE xact = p_xact + ORDER BY voided,billing_ts + LOOP + billing_loop = billing_loop + 1; + -- Skip billing rows that we have already paid + IF billing_id_used @> ARRAY[current_billing.id] THEN CONTINUE; END IF; + + billing_remainder = current_billing.amount; + current_billing_id := current_billing.id; + continuing_payment := FALSE; + + current_result.xact = p_xact; + current_result.payment = current_payment.id; + current_result.billing = current_billing.id; + current_result.payment_ts = current_payment.payment_ts; + current_result.billing_ts = current_billing.billing_ts; + current_result.payment_type = current_payment.payment_type; + current_result.billing_type = current_billing.billing_type; + current_result.payment_ou = payment_ou; + current_result.billing_ou = billing_ou; +-- Debug current_result.billing_leftover = billing_remainder; +-- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; + + IF billing_remainder >= payment_remainder THEN + current_result.amount = payment_remainder; + billing_remainder = billing_remainder - payment_remainder; + payment_remainder = 0.0; + -- If it is equal then we need to close up the billing line and move to the next + -- This prevents 0 amounts applied to billing lines + IF billing_remainder = payment_remainder THEN + billing_remainder = 0.0; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); + END IF; + ELSE + current_result.amount = billing_remainder; + payment_remainder = payment_remainder - billing_remainder; + billing_remainder = 0.0; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); + END IF; + + RETURN NEXT current_result; + EXIT WHEN payment_remainder = 0.0; + END LOOP; + + END IF; EXIT WHEN payment_remainder = 0.0; END LOOP; payment_offset = payment_offset + 1; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN array_length(billing_id_used, 1) = billing_row_count; END LOOP; @@ -948,6 +1032,7 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; @@ -972,13 +1057,13 @@ BEGIN current_result.amount = -current_result.amount; RETURN NEXT current_result; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN billing_offset = billing_row_count + 1; END IF; CONTINUE WHEN payment_remainder = 0.0; -- next billing, please - + billing_loop := -1; FOR current_billing IN SELECT * FROM money.billing @@ -986,10 +1071,10 @@ BEGIN AND voided ORDER BY billing_ts LOOP + billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 -- Fast forward through the rows until we get to the billing row -- where we left off - IF fast_forward THEN - billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 + IF fast_forward THEN CONTINUE WHEN billing_loop <> billing_offset; END IF; @@ -999,7 +1084,6 @@ BEGIN END IF; maintain_billing_remainder := FALSE; - billing_loop := -1; fast_forward := FALSE; current_result.xact = p_xact; @@ -1013,6 +1097,7 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; @@ -1040,7 +1125,7 @@ BEGIN payment_offset = payment_offset + 1; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN billing_offset = billing_row_count + 1; END LOOP; @@ -1061,7 +1146,7 @@ DECLARE current_result money.materialized_payment_by_billing_type%ROWTYPE; BEGIN - -- first, we find transactions at specified locations involivng + -- first, we find transactions at specified locations involving -- positve, unvoided payments within the specified range FOR current_transaction IN SELECT DISTINCT x.id diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.money.materialized_payment_by_billing_type b/Open-ILS/src/sql/Pg/upgrade/XXXX.money.materialized_payment_by_billing_type index 1aedfc7d6b..9b1c0f10cc 100644 --- a/Open-ILS/src/sql/Pg/upgrade/XXXX.money.materialized_payment_by_billing_type +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.money.materialized_payment_by_billing_type @@ -4,20 +4,22 @@ SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); CREATE TABLE money.materialized_payment_by_billing_type ( - id BIGSERIAL PRIMARY KEY, - xact BIGINT NOT NULL, - payment BIGINT NOT NULL, - billing BIGINT NOT NULL, - payment_ts TIMESTAMPTZ NOT NULL, - billing_ts TIMESTAMPTZ NOT NULL, - amount NUMERIC(8,2) NOT NULL, - payment_type TEXT, - billing_type TEXT, - payment_ou INT, - billing_ou INT, + id BIGSERIAL PRIMARY KEY, + xact BIGINT NOT NULL, + payment BIGINT NOT NULL, + billing BIGINT NOT NULL, + payment_ts TIMESTAMPTZ NOT NULL, + billing_ts TIMESTAMPTZ NOT NULL, + amount NUMERIC(8,2) NOT NULL, + payment_type TEXT, + billing_type TEXT, + payment_ou INT, + billing_ou INT, -- Debug billing_leftover NUMERIC(8,2), -- Debug payment_leftover NUMERIC(8,2), - CONSTRAINT x_p_b_once UNIQUE (xact,payment,billing) +-- Debug used_billings BIGINT[], +-- Debug billing_l INT, + CONSTRAINT x_p_b_once UNIQUE (xact,payment,billing) ); CREATE INDEX p_by_b_payment_ts_idx @@ -30,19 +32,25 @@ CREATE OR REPLACE FUNCTION money.payment_by_billing_type ( ) RETURNS SETOF money.materialized_payment_by_billing_type AS $$ DECLARE - current_result money.materialized_payment_by_billing_type%ROWTYPE; - current_payment money.payment_view%ROWTYPE; - current_billing money.billing%ROWTYPE; - payment_remainder NUMERIC(8,2) := 0.0; - billing_remainder NUMERIC(8,2) := 0.0; - payment_offset INT := 0; - billing_offset INT := 0; - billing_ou INT := 0; - payment_ou INT := 0; + current_result money.materialized_payment_by_billing_type%ROWTYPE; + current_payment money.payment_view%ROWTYPE; + current_billing money.billing%ROWTYPE; + payment_remainder NUMERIC(8,2) := 0.0; + billing_remainder NUMERIC(8,2) := 0.0; + payment_offset INT := 0; + billing_offset INT := 0; + billing_ou INT := 0; + payment_ou INT := 0; fast_forward BOOLEAN := FALSE; maintain_billing_remainder BOOLEAN := FALSE; billing_loop INT := -1; billing_row_count INT := 0; + current_billing_id BIGINT := 0; + billing_id_used BIGINT ARRAY; + billing_l INT := 0; + continuing_payment BOOLEAN := FALSE; + continuing_payment_last_row BOOLEAN := FALSE; + BEGIN /* This algorithm is fairly straight-forward. We take a transaction id @@ -82,7 +90,7 @@ BEGIN ORDER BY payment_ts LOOP - payment_remainder = current_payment.amount; + payment_remainder = current_payment.amount; -- With every new payment row, we need to fast forward -- the billing lines up to the last paid billing row fast_forward := TRUE; @@ -95,73 +103,87 @@ BEGIN payment_ou = billing_ou; END IF; - -- Were we looking at a billing from a previous step in the loop? - IF billing_remainder > 0.0 THEN - current_result.xact = p_xact; - current_result.payment = current_payment.id; - current_result.billing = current_billing.id; - current_result.payment_ts = current_payment.payment_ts; - current_result.billing_ts = current_billing.billing_ts; - current_result.payment_type = current_payment.payment_type; - current_result.billing_type = current_billing.billing_type; - current_result.payment_ou = payment_ou; - current_result.billing_ou = billing_ou; + -- Were we looking at a billing from a previous step in the loop? + IF billing_remainder > 0.0 THEN + current_result.xact = p_xact; + current_result.payment = current_payment.id; + current_result.billing = current_billing.id; + current_result.payment_ts = current_payment.payment_ts; + current_result.billing_ts = current_billing.billing_ts; + current_result.payment_type = current_payment.payment_type; + current_result.billing_type = current_billing.billing_type; + current_result.payment_ou = payment_ou; + current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; - IF billing_remainder >= payment_remainder THEN - current_result.amount = payment_remainder; - billing_remainder = billing_remainder - payment_remainder; - payment_remainder = 0.0; - payment_offset = payment_offset + 1; + IF billing_remainder >= payment_remainder THEN + current_result.amount = payment_remainder; + billing_remainder = billing_remainder - payment_remainder; + payment_remainder = 0.0; + payment_offset = payment_offset + 1; -- If it is equal then we need to close up the billing line and move to the next -- This prevents 0 amounts applied to billing lines IF billing_remainder = payment_remainder THEN billing_remainder = 0.0; - billing_offset = billing_offset + 1; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); ELSE maintain_billing_remainder := TRUE; END IF; - ELSE - current_result.amount = billing_remainder; - payment_remainder = payment_remainder - billing_remainder; - billing_remainder = 0.0; + ELSE + current_result.amount = billing_remainder; + payment_remainder = payment_remainder - billing_remainder; + billing_remainder = 0.0; billing_offset = billing_offset + 1; - END IF; + billing_id_used = array_append( billing_id_used, current_billing_id ); + continuing_payment := TRUE; + END IF; - RETURN NEXT current_result; + RETURN NEXT current_result; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; - END IF; - - CONTINUE WHEN payment_remainder = 0.0; + EXIT WHEN array_length(billing_id_used, 1) = billing_row_count; + END IF; + CONTINUE WHEN payment_remainder = 0.0; + -- next billing, please - + billing_loop := -1; + FOR current_billing IN SELECT * FROM money.billing WHERE xact = p_xact - -- AND NOT voided -- Gotta put the voided billing rows at the bottom (last) ORDER BY voided,billing_ts LOOP - -- Fast forward through the rows until we get to the billing row - -- where we left off - IF fast_forward THEN - billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 - CONTINUE WHEN billing_loop <> billing_offset; + billing_loop = billing_loop + 1; + + -- Skip billing rows that we have already paid + IF billing_id_used @> ARRAY[current_billing.id] THEN CONTINUE; + END IF; + + IF maintain_billing_remainder THEN + CONTINUE WHEN current_billing.id <> current_billing_id; + -- Account adjustment - we expect to pay billing rows that are identical amounts + ELSE IF current_payment.payment_type = 'account_adjustment' THEN + -- Go ahead and allow the row through when it's the last row and we still haven't found one with equal payment amount + CONTINUE WHEN ( ( current_billing.amount <> current_payment.amount ) AND ( billing_loop + 1 <> billing_row_count ) ); + END IF; END IF; -- Keep the old remainder if we were in the middle of a billing row IF NOT maintain_billing_remainder THEN - billing_remainder = current_billing.amount; + billing_remainder = current_billing.amount; END IF; - maintain_billing_remainder := FALSE; - billing_loop := -1; + maintain_billing_remainder := FALSE; fast_forward := FALSE; + current_billing_id := current_billing.id; + continuing_payment := FALSE; current_result.xact = p_xact; current_result.payment = current_payment.id; @@ -174,36 +196,98 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; billing_remainder = billing_remainder - payment_remainder; - IF NOT current_billing.voided THEN - payment_remainder = 0.0; - END IF; + payment_remainder = 0.0; -- If it is equal then we need to close up the billing line and move to the next -- This prevents 0 amounts applied to billing lines IF billing_remainder = payment_remainder THEN billing_remainder = 0.0; - billing_offset = billing_offset + 1; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); END IF; ELSE current_result.amount = billing_remainder; - IF NOT current_billing.voided THEN - payment_remainder = payment_remainder - billing_remainder; - END IF; + payment_remainder = payment_remainder - billing_remainder; + continuing_payment := TRUE; + IF billing_loop + 1 = billing_row_count THEN + -- We have a situation where we are on the last billing row and we are in the middle of a payment row + -- We need to start back at the beginning of the billing rows and pay + continuing_payment_last_row := TRUE; + END IF; billing_remainder = 0.0; billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); END IF; RETURN NEXT current_result; - + IF continuing_payment_last_row THEN + -- This should only occur when the account_adjustment's do not line up exactly with the billing + -- So we are going to pay some other type of billing row with this odd account_adjustment + -- And we need to stay in the current_payment row while doing so + billing_loop := -1; + FOR current_billing IN + SELECT * + FROM money.billing + WHERE xact = p_xact + ORDER BY voided,billing_ts + LOOP + billing_loop = billing_loop + 1; + -- Skip billing rows that we have already paid + IF billing_id_used @> ARRAY[current_billing.id] THEN CONTINUE; END IF; + + billing_remainder = current_billing.amount; + current_billing_id := current_billing.id; + continuing_payment := FALSE; + + current_result.xact = p_xact; + current_result.payment = current_payment.id; + current_result.billing = current_billing.id; + current_result.payment_ts = current_payment.payment_ts; + current_result.billing_ts = current_billing.billing_ts; + current_result.payment_type = current_payment.payment_type; + current_result.billing_type = current_billing.billing_type; + current_result.payment_ou = payment_ou; + current_result.billing_ou = billing_ou; +-- Debug current_result.billing_leftover = billing_remainder; +-- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.used_billings = billing_id_used; +-- Debug current_result.billing_l = billing_loop; + + IF billing_remainder >= payment_remainder THEN + current_result.amount = payment_remainder; + billing_remainder = billing_remainder - payment_remainder; + payment_remainder = 0.0; + -- If it is equal then we need to close up the billing line and move to the next + -- This prevents 0 amounts applied to billing lines + IF billing_remainder = payment_remainder THEN + billing_remainder = 0.0; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); + END IF; + ELSE + current_result.amount = billing_remainder; + payment_remainder = payment_remainder - billing_remainder; + billing_remainder = 0.0; + billing_offset = billing_offset + 1; + billing_id_used = array_append( billing_id_used, current_billing_id ); + END IF; + + RETURN NEXT current_result; + EXIT WHEN payment_remainder = 0.0; + END LOOP; + + END IF; EXIT WHEN payment_remainder = 0.0; END LOOP; payment_offset = payment_offset + 1; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN array_length(billing_id_used, 1) = billing_row_count; END LOOP; @@ -263,6 +347,7 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; @@ -287,13 +372,13 @@ BEGIN current_result.amount = -current_result.amount; RETURN NEXT current_result; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN billing_offset = billing_row_count + 1; END IF; CONTINUE WHEN payment_remainder = 0.0; -- next billing, please - + billing_loop := -1; FOR current_billing IN SELECT * FROM money.billing @@ -301,10 +386,10 @@ BEGIN AND voided ORDER BY billing_ts LOOP + billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 -- Fast forward through the rows until we get to the billing row -- where we left off - IF fast_forward THEN - billing_loop = billing_loop + 1; -- first iteration billing_loop=0, it starts at -1 + IF fast_forward THEN CONTINUE WHEN billing_loop <> billing_offset; END IF; @@ -314,7 +399,6 @@ BEGIN END IF; maintain_billing_remainder := FALSE; - billing_loop := -1; fast_forward := FALSE; current_result.xact = p_xact; @@ -328,6 +412,7 @@ BEGIN current_result.billing_ou = billing_ou; -- Debug current_result.billing_leftover = billing_remainder; -- Debug current_result.payment_leftover = payment_remainder; +-- Debug current_result.billing_l = billing_loop; IF billing_remainder >= payment_remainder THEN current_result.amount = payment_remainder; @@ -355,7 +440,7 @@ BEGIN payment_offset = payment_offset + 1; -- Done paying the billing rows when we run out of rows to pay (out of bounds) - EXIT WHEN billing_offset = billing_row_count+1; + EXIT WHEN billing_offset = billing_row_count + 1; END LOOP; @@ -376,7 +461,7 @@ DECLARE current_result money.materialized_payment_by_billing_type%ROWTYPE; BEGIN - -- first, we find transactions at specified locations involivng + -- first, we find transactions at specified locations involving -- positve, unvoided payments within the specified range FOR current_transaction IN SELECT DISTINCT x.id