Expense Reporting EFT – Easy as ABC

 

 

 

 

 

 

Technical Assistance Documentation

Atlanta OAUG

May 21, 1999

Presented By: Allen Webb, The Kaylor Group, Inc.

 

 

 

Table of Contents

Sample EFT PL/SQL Script *

Sample Remittance Alert SQL Script *

 

 

Sample EFT PL/SQL Script

/****************************************************************************/

-- *

-- Program Name : XXXAPACH.sql *

-- *

-- Programming *

-- Language : PL/SQL *

-- *

-- Purpose : This program is used to extract and format *

-- AP EFT Payment Information to be formatted for *

-- NACHA transmission to XYZ Bank *

-- *

-- Tables Accessed : AP_SELECTED_INVOICES *

-- AP_SELECTED_INVOICE_CHECKS *

-- AP_INVOICE_SELECTION_CRITERIA *

-- PO_VENDORS_ALL *

-- *

-- Input Parameters: CHECKRUN_NAME *

-- *

-- Output file(s): None *

-- *

-- *

/****************************************************************************/

set serverout on

set pagesize 60

whenever sqlerror exit 3;

/* truncate table apdev.XXXap_nacha_interface; */

truncate table apcust.XXXap_nacha_interface;

/******************************************************************************/

/*************************** VARIABLE DECLARATIONS ************************/

/******************************************************************************/

declare

/***************************************************************************/

/**************************** File Header Record ******************************/

/***************************************************************************/

fh_record_type_code varchar2(1) := '1';

fh_priority_code varchar2(2) := '01';

fh_immediate_destination varchar2(10) := null;

fh_immediate_origin varchar2(10) := 'XXXXXXXXXX';

fh_transmission_date varchar2(6) := null;

fh_transmission_time varchar2(4) := null;

fh_file_id_modifier varchar2(1) := null;

fh_record_size varchar2(3) := '094';

fh_blocking_factor varchar2(2) := '10';

fh_format_code varchar2(1) := '1';

fh_destination varchar2(23) := 'NationsBank - FL';

fh_origin varchar2(18) := 'SAMPLE CORPORATION';

fh_reference_code varchar2(8) := 'AP EFT';

/****************************************************************************/

/************************* Company Batch Header Record ************************/

/***************************************************************************/

ch_record_type_code varchar2(1) := '5';

ch_service_class_code varchar2(3) := '200';

ch_company_name varchar2(18) := 'SAMPLE CORPORATION';

ch_company_disc varchar2(20) := 'AP EXPENSE';

ch_company_id varchar2(10) := null;

ch_entry_class varchar2(3) := 'PPD';

ch_company_entry_desc varchar2(10) := 'AP EXPENSE';

ch_company_desc_date varchar(6) := null;

ch_company_entry_date varchar(6) := null;

ch_settlement_date_jul varchar2(3) := ' ';

ch_originator_status varchar2(1) := '1';

ch_originating_dfi_id varchar2(8) := null;

ch_batch_number varchar2(7) := '0000001';

/**************************************************************************/

/****************************** Detail Entry Record **************************/

/*************************************************************************/

de_record_type_code varchar2(1) := '6';

de_transaction_code varchar2(2) := null;

de_individual_bank_id varchar2(8) := null;

de_check_digit varchar2(1) := null;

de_bank_acct_number varchar2(17) := null;

de_amount varchar2(10) := null;

de_individual_id varchar2(15) := null;

de_individual_name varchar2(22) := null;

de_bank_disc varchar2(2) := ' ';

de_addenda_rec_ind varchar2(1) := '0';

de_trace_number varchar2(15) := null;

/***************************************************************************/

/************************* Company Batch Control Record ***********************/

/***************************************************************************/

cc_record_type_code varchar2(1) := '8';

cc_service_class varchar2(3) := '200';

cc_entry_count varchar2(6) := null;

cc_entry_hash varchar2(10) := null;

cc_total_debits varchar2(12) := null;

cc_total_credits varchar2(12) := null;

cc_company_id varchar2(10) := null;

cc_filler1 varchar2(19) := ' ';

cc_filler2 varchar2(6) := ' ';

cc_originating_fin varchar2(8) := null;

cc_batch_number varchar2(7) := '0000001';

/**************************************************************************/

/*************************** File Batch Control Record ************************/

/*************************************************************************/

fc_record_type_code varchar2(1) := '9';

fc_batch_count varchar2(6) := '000001';

fc_block_count varchar2(6) := null;

fc_entry_count varchar2(8) := null;

fc_entry_hash varchar2(10) := null;

fc_total_debits varchar2(12) := null;

fc_total_credits varchar2(12) := null;

fc_reserved varchar2(39) := ' ';

/******************************************************************************/

l_company_identifier varchar2(13) := 'CO IDENTIFIER';

l_amount_paid number := null;

l_checkrun_name varchar2(30) := '&1';

dummy_date date;

f_check_id number(15) := null;

f_vendor_id number(15) := null;

f_vendor_site_id number(15) := null;

l_vendor_num varchar2(30) := null;

l_vendor_name varchar2(80) := null;

l_check_amount number := null;

l_check_date varchar2(6) := null;

l_bank_account_num varchar2(30) := null;

l_bank_account_type varchar2(25) := null;

l_bank_num varchar2(25) := null;

l_nb_account_num varchar2(30) := null;

l_nb_transit_num varchar2(30) := null;

l_transmission_date varchar2(6) := null;

l_transmission_time varchar2(4) := null;

l_validate_count number := null;

l_rec_count number := 0;

l_rec_seq number := 0;

l_tot_rec_count number := 0;

l_entry_count number := 0;

l_entry_hash number := 0;

l_total_debits number := 0;

l_total_credits number := 0;

vin varchar2(8) := null;

vout varchar2(8) := null;

p_procedure_name varchar2(50) := null;

p_debug_text varchar2(300) := null;

p_debug_ref varchar2(80) := null;

p_debug_code varchar2(10) := null;

p_debug_mesg varchar2(50) := null;

p_debug_mode varchar2(1) := '';

error_record exception;

/***************************************************************************/

/**************************** CURSOR DECLARATIONS **********************/

/***************************************************************************/

/***************************************************************************/

/* Get check Info */

/***************************************************************************/

cursor chk_curs is

select t1.selected_check_id,

t1.vendor_id,

t1.vendor_site_id,

t1.vendor_num,

t1.check_amount,

t1.vendor_name,

t1.bank_account_num,

t1.bank_account_type,

t1.bank_num /*TRANSIT NUM*/

from ap_selected_invoice_checks t1

where t1.checkrun_name = l_checkrun_name

and t1.ok_to_pay_flag = 'Y'

order by t1.check_number;

chk_rec chk_curs%rowtype;

/****************************************************************************/

/************************ PROCEDURE DECLARATIONS ***********************/

/***************************************************************************/

/****************************************************************************/

/* Abort Processing of the Record */

/***************************************************************************/

procedure abort_record is

begin

raise error_record;

end abort_record;

/****************************************************************************/

/* Display Debug Messages */

/***************************************************************************/

procedure print_debug is

begin

dbms_output.put_line('*** ERROR ****************************************');

dbms_output.put_line('Debug Proc: '||p_procedure_name);

dbms_output.put_line('Debug Rec: '||to_char(f_check_id));

dbms_output.put_line('Debug Code: '||p_debug_code);

dbms_output.put_line('Debug Text: '||p_debug_text);

dbms_output.put_line('Debug Ref: '||p_debug_ref);

abort_record;

end print_debug;

/****************************************************************************/

/* Debug Process Flow */

/**************************************************************************/

procedure display_process is

begin

if p_debug_mode = 'D' then

dbms_output.put_line(p_procedure_name);

end if;

end display_process;

/****************************************************************************/

/* Reset transaction Variables */

/**************************************************************************/

procedure reset_vars is

begin

p_procedure_name := 'BEG reset_vars';

display_process;

p_debug_text := null;

p_debug_ref := null;

p_debug_code := null;

p_debug_mesg := null;

l_rec_count := 0;

l_rec_seq := 0;

p_procedure_name := 'END reset_vars';

display_process;

end reset_vars;

/****************************************************************************/

/* Validate Bank Information */

/***************************************************************************/

procedure validate_bank_info is

begin

p_procedure_name := 'BEG validate_bank_info';

display_process;

if length(l_nb_transit_num) <> 9

then

p_debug_code := 'XXX00015';

p_debug_text := 'Nations Bank Transit# <> 9 characters in length';

p_debug_ref := l_nb_transit_num;

print_debug;

end if;

if length(l_bank_num) <> 9

then

p_debug_code := 'XXX00016';

p_debug_text := 'Employee Bank Transit# <> 9 characters in length';

p_debug_ref := l_bank_num;

print_debug;

end if;

if l_bank_account_type not in ('S','C')

then

p_debug_code := 'XXX00017';

p_debug_text := 'Employee Bank Account Type <> Savings or Checking';

p_debug_ref := l_bank_num;

print_debug;

end if;

p_procedure_name := 'END validate_bank_info';

display_process;

end validate_bank_info;

 

/****************************************************************************/

/* Calculate Check Digit */

/**************************************************************************/

procedure calculate_check_digit

(value_in in varchar2,

value_out out varchar2)

is

i integer := 0;

total_weight integer := 0;

digit integer := null;

next_multiple integer := 0;

begin

for i in 1..8

loop

digit := substr(value_in,i,1);

if i in (1,4,7)

then

total_weight := total_weight + digit * 3;

elsif i in (2,5,8)

then

total_weight := total_weight + digit * 7;

elsif i in (3,6)

then

total_weight := total_weight + digit * 1;

end if;

end loop;

 

next_multiple := round(total_weight,-1);

if next_multiple < total_weight

then

next_multiple := next_multiple + 10;

end if;

value_out := ltrim(rtrim(to_char(next_multiple - total_weight)));

end calculate_check_digit;

/****************************************************************************/

/* Validate Payment Batch Status */

/***************************************************************************/

procedure validate_payment_batch is

begin

p_procedure_name := 'BEG validate_payment_batch';

display_process;

select count(t1.rowid)

into l_validate_count

from ap_invoice_selection_criteria t1,

ap_check_stocks t2

where t1.payment_method_lookup_code = 'EFT'

and t1.check_stock_id = t2.check_stock_id

and t2.name = 'XXX: EFT'

and t2.inactive_date is null

and t1.status in ('BUILT','FORMATTING')

and t1.checkrun_name = l_checkrun_name;

if l_validate_count = 0

then

p_debug_code := 'ERR00005';

p_debug_text := 'Payment Batch Selected not available for processing';

p_debug_ref := l_checkrun_name;

print_debug;

end if;

p_procedure_name := 'END validate_payment_batch';

display_process;

end validate_payment_batch;

/****************************************************************************/

/* Get Check Date and Bank Account */

/**************************************************************************/

procedure get_check_date_bank_acct is

begin

p_procedure_name := 'BEG get_check_date_bank_acct';

display_process;

select to_char(t1.check_date,'YYMMDD') check_date,

to_char(sysdate,'YYMMDD') transmission_date,

to_char(sysdate,'HH24MM') transmission_time,

t2.bank_account_num nb_account_num,

t3.bank_num nb_transit_num

into l_check_date,

l_transmission_date,

l_transmission_time,

l_nb_account_num,

l_nb_transit_num

from ap_invoice_selection_criteria t1,

ap_bank_accounts_all t2,

ap_bank_branches t3

where t1.checkrun_name = l_checkrun_name

and t2.bank_branch_id = t3.bank_branch_id

and t1.bank_account_name = t2.bank_account_name;

 

p_procedure_name := 'END get_check_date_bank_acct';

display_process;

exception

when no_data_found then

p_debug_code := 'ERR00003';

p_debug_text := 'Error getting Check Date and Bank Account';

p_debug_ref := to_char(f_vendor_id);

print_debug;

when error_record then

raise;

when others then

p_debug_code := to_char(sqlcode);

p_debug_text := substr(sqlerrm,1,50);

print_debug;

end get_check_date_bank_acct;

 

/****************************************************************************/

/* Insert File Header Record */

/**************************************************************************/

procedure process_fh_rec is

begin

p_procedure_name := 'BEG process_fh_rec';

display_process;

l_rec_seq := 0;

l_tot_rec_count := l_tot_rec_count + 1;

fh_immediate_destination := concat(' ',l_nb_transit_num);

fh_immediate_origin := ' '||substr(fh_immediate_origin,2,9);

fh_transmission_date := l_transmission_date;

fh_transmission_time := l_transmission_time;

select to_char(XXXap_nacha_file_id_s.nextval)

into fh_file_id_modifier

from dual;

if fh_file_id_modifier is null

then

fh_file_id_modifier := '0';

end if;

 

insert into XXXap_nacha_interface

(

checkrun_name,

record_type_code,

record_sequence,

record_layout

)

values

(

l_checkrun_name,

fh_record_type_code,

l_rec_seq,

fh_record_type_code ||

fh_priority_code ||

fh_immediate_destination ||

fh_immediate_origin ||

fh_transmission_date ||

fh_transmission_time ||

fh_file_id_modifier ||

fh_record_size ||

fh_blocking_factor ||

fh_format_code ||

rpad(fh_destination,23, ' ') ||

rpad(fh_origin,23,' ') ||

rpad(fh_reference_code,8,' ')

);

p_procedure_name := 'END process_fh_rec';

display_process;

end process_fh_rec;

/****************************************************************************/

/* Insert Company Header Record */

/**************************************************************************/

procedure process_ch_rec is

begin

p_procedure_name := 'BEG process_ch_rec';

display_process;

l_rec_seq := 0;

l_tot_rec_count := l_tot_rec_count + 1;

ch_company_id := l_company_identifier;

ch_company_desc_date := l_check_date;

ch_company_entry_date := l_check_date;

ch_originating_dfi_id := substr(l_nb_transit_num,1,8);

 

 

insert into XXXap_nacha_interface

(

checkrun_name,

record_type_code,

record_sequence,

record_layout

)

values

(

l_checkrun_name,

ch_record_type_code,

l_rec_count,

ch_record_type_code ||

ch_service_class_code ||

rpad(ch_company_name,16,' ') ||

rpad(ch_company_disc,20,' ') ||

ch_company_id ||

ch_entry_class ||

rpad(ch_company_entry_desc,10,' ') ||

ch_company_desc_date ||

ch_company_entry_date ||

ch_settlement_date_jul ||

ch_originator_status ||

ch_originating_dfi_id ||

ch_batch_number

);

p_procedure_name := 'END process_ch_rec';

display_process;

end process_ch_rec;

/****************************************************************************/

/* Insert Detail Entry Record */

/***************************************************************************/

procedure process_de_rec is

begin

p_procedure_name := 'BEG process_de_rec';

display_process;

l_rec_count := l_rec_count + 1;

l_tot_rec_count := l_tot_rec_count + 1;

 

if l_check_amount >= 0

then

if l_bank_account_type = 'Savings'

then

de_transaction_code := '32';

else

de_transaction_code := '22';

end if;

end if;

 

if l_check_amount < 0

then

if l_bank_account_type = 'Savings'

then

de_transaction_code := '37';

else

de_transaction_code := '27';

end if;

end if;

l_entry_count := l_entry_count + l_rec_count;

l_entry_hash := l_entry_hash + to_number(substr(l_bank_num,1,8));

if l_check_amount < 0

then

l_total_debits := l_total_debits + l_check_amount;

else

l_total_credits := l_total_credits + abs(l_check_amount);

end if;

de_individual_bank_id := substr(l_bank_num,1,8);

/* not being calculated - assume Payroll has correct check digit entered */

/* calculate_check_digit(substr(l_bank_num,1,8),vout); */

/* de_check_digit := vout; */

de_check_digit := substr(l_bank_num,9,1);

de_bank_acct_number := substr(l_bank_account_num,1,17);

de_amount := to_char(abs(l_check_amount),'FM00000000V00');

de_individual_id := substr(l_vendor_num,1,15);

de_individual_name := substr(l_vendor_name,1,22);

de_trace_number := substr(l_nb_transit_num,1,8)||

to_char(l_rec_count,'FM0000000');

 

 

insert into XXXap_nacha_interface

(

checkrun_name,

record_type_code,

record_sequence,

record_layout

)

values

(

l_checkrun_name,

de_record_type_code,

l_rec_count,

de_record_type_code ||

de_transaction_code ||

de_individual_bank_id ||

de_check_digit ||

rpad(de_bank_acct_number,17,' ') ||

de_amount ||

rpad(de_individual_id,15,' ') ||

rpad(de_individual_name,22,' ') ||

de_bank_disc ||

de_addenda_rec_ind ||

de_trace_number

);

p_procedure_name := 'END process_de_rec';

display_process;

end process_de_rec;

/****************************************************************************/

/* Insert Company Control Record */

/**************************************************************************/

procedure process_cc_rec is

begin

p_procedure_name := 'BEG process_cc_rec';

display_process;

l_rec_seq := 0;

l_tot_rec_count := l_tot_rec_count + 1;

cc_entry_count := to_char(l_rec_count, 'FM000000');

cc_total_credits := to_char(l_total_credits,'FM0000000000V00');

cc_total_debits := to_char(l_total_debits, 'FM0000000000V00');

cc_entry_hash := to_char(l_entry_hash, 'FM0000000000');

cc_company_id := l_company_identifier;

cc_originating_fin := substr(l_nb_transit_num,1,8);

 

 

insert into XXXap_nacha_interface

(

checkrun_name,

record_type_code,

record_sequence,

record_layout

)

values

(

l_checkrun_name,

cc_record_type_code,

l_rec_seq,

cc_record_type_code ||

cc_service_class ||

cc_entry_count ||

cc_entry_hash ||

cc_total_debits ||

cc_total_credits ||

cc_company_id ||

lpad(cc_filler1,19,' ') ||

lpad(cc_filler2,6,' ') ||

cc_originating_fin ||

cc_batch_number

);

p_procedure_name := 'END process_cc_rec';

display_process;

end process_cc_rec;

/****************************************************************************/

/* Insert File Control Record */

/***************************************************************************/

procedure process_fc_rec is

begin

p_procedure_name := 'BEG process_fc_rec';

display_process;

l_rec_seq := 0;

l_tot_rec_count := l_tot_rec_count + 1;

fc_entry_count := to_char(l_rec_count, 'FM00000000');

fc_total_credits := to_char(l_total_credits,'FM0000000000V00');

fc_total_debits := to_char(l_total_debits, 'FM0000000000V00');

fc_entry_hash := to_char(l_entry_hash, 'FM0000000000');

fc_block_count := to_char(ceil(l_tot_rec_count / 10),'FM000000');

 

insert into XXXap_nacha_interface

(

checkrun_name,

record_type_code,

record_sequence,

record_layout

)

values

(

l_checkrun_name,

fc_record_type_code,

l_rec_seq,

fc_record_type_code ||

fc_batch_count ||

fc_block_count ||

fc_entry_count ||

fc_entry_hash ||

fc_total_debits ||

fc_total_credits ||

lpad(fc_reserved,39,' ')

);

p_procedure_name := 'END process_fc_rec';

display_process;

end process_fc_rec;

/****************************************************************************/

/* Process EFT Payments */

/**************************************************************************/

procedure process_eft is

begin

p_procedure_name := 'BEG process_eft';

display_process;

open chk_curs;

loop

fetch chk_curs into chk_rec;

exit when chk_curs%notfound;

begin

f_check_id := chk_rec.selected_check_id;

f_vendor_id := chk_rec.vendor_id;

f_vendor_site_id := chk_rec.vendor_site_id;

l_vendor_num := chk_rec.vendor_num;

l_vendor_name := chk_rec.vendor_name;

l_check_amount := chk_rec.check_amount;

l_bank_account_num := chk_rec.bank_account_num;

l_bank_account_type := chk_rec.bank_account_type;

l_bank_num := chk_rec.bank_num;

 

 

/*

dbms_output.put_line('NB Transit#: '||l_nb_transit_num);

dbms_output.put_line('NB Account#: '||l_nb_account_num);

dbms_output.put_line('EFT Date: '||l_check_date);

dbms_output.put_line('EFT Amount: '||to_char(l_check_amount));

dbms_output.put_line('Bank Transit#: '||l_bank_num);

dbms_output.put_line('Bank Account#: '||l_bank_account_num);

dbms_output.put_line('Bank AcctType: '||l_bank_account_type);

dbms_output.put_line('Vendor Number: '||l_vendor_num);

dbms_output.put_line('Vendor Name: '||l_vendor_name);

*/

validate_bank_info;

process_de_rec;

exception

when error_record then

raise;

when others then

p_debug_code := to_char(sqlcode);

p_debug_text := substr(sqlerrm,1,50);

print_debug;

end;

end loop;

close chk_curs;

p_procedure_name := 'END process_eft';

display_process;

end process_eft;

/******************************************************************************/

/************************** MAIN PROCESSING BLOCK *************************/

/****************************************************************************/

begin

dbms_output.enable(1000000);

reset_vars;

validate_payment_batch;

get_check_date_bank_acct;

process_fh_rec;

process_ch_rec;

process_eft;

process_cc_rec;

process_fc_rec;

 

exception

when error_record then

dbms_output.put_line('************************************************');

dbms_output.put_line('*** ERROR: Process is Terminating ***');

dbms_output.put_line('************************************************');

dbms_output.put_line('*** Refer to previous Debug Text to resolve ***');

dbms_output.put_line('*** the error. ***');

dbms_output.put_line('*** Ignore next message - used to force the ***');

dbms_output.put_line('*** termination of the SQL Process ***');

dbms_output.put_line('************************************************');

select to_date('abcde') into dummy_date from dual;

when others then

p_debug_code := to_char(sqlcode);

p_debug_text := substr(sqlerrm,1,50);

print_debug;

end;

/

commit;

exit;

 

 

 

 

Sample Remittance Alert SQL Script

select

t2.bank_account_name bank_account_name,

t1.bank_account_num bank_account_num,

t1.amount deposit_amount,

t1.check_date deposit_date,

t7.email_address email_address,

t1.vendor_name employee_name,

t3.amount ilamt,

t3.expenditure_item_date ildate,

substr(t3.description,1,35) ildesc,

'XXX Remmitance Advice' remmitance_title

into

&bank_account_name,

&bank_account_num,

&deposit_amount,

&deposit_date,

&email_address,

&employee_name,

&ilamt,

&ildate,

&ildesc,

&remmitance_title

from

ap_checks_all t1,

po_vendor_sites_all t2,

ap_invoice_distributions_all t3,

ap_invoice_payments t4,

po_vendors t6,

hr_employees t7

where

t1.payment_method_lookup_code = 'EFT'

and t1.status_lookup_code = 'NEGOTIABLE'

and t1.check_id = t4.check_id

and t3.invoice_id = t4.invoice_id

and t6.employee_id = t7.employee_id

and t1.vendor_site_id = t2.vendor_site_id

and t6.vendor_id = t2.vendor_id

and translate(t7.email_address,' ','*') not like '%*%'

and t7.email_address is not null

and t1.creation_date >

to_date(:DATE_LAST_CHECKED,'DD-MON-YYYY HH24:MI:SS')

order by

t2.bank_account_name,

t1.bank_account_num,

t1.amount,

t1.check_date,

t7.email_address ,

t1.vendor_name,

t3.expenditure_item_date ,

t3.amount ,

substr(t3.description,1,35);