Exact Online import GLTransactions with automatic reconciliation - accounting

I am using our query tool to generate XML files for the topic GLTransactions of the XML API of Exact Online. The input for these files are XML Audit Files coming from Twinfield (XAF 3.1 format).
Since Exact Online has a mixed ledger and lots of constraints, it is not possible to directly load the bank entries. Instead, the bank transactions are posted into a separate General Ledger account of Exact Online with a separate journal as a first step when loading the XML Audit Files from Twinfield.
In the next step, the contents in Exact Online of the reserved General Ledger account are posted in the banking journal. Exact Online itself generates the other half as associated transaction lines for the banking general ledger.
The query used to generate the bank entries is:
create or replace table bank#inmemorystorage
as
select case
when substr(tle.description, 1, instr(tle.description, '/') - 1) = 'BNK'
then '20'
when substr(tle.description, 1, instr(tle.description, '/') - 1) = 'BNK2'
then '21'
else '??'
end
txn_journalcode
, txn.financialyear txn_financialyear
, txn.financialperiod txn_financialperiod
, txn.entrynumber txn_entrynumber
, txn.date txn_date
, tle.date tle_date
, tle.linenumber tle_linenumber
, substr(tle.description, instr(tle.description, '/') + 1, instr(tle.description, ':') - instr(tle.description, '/') - 1) tle_glaccountcode_target
, substr(tle.description, instr(tle.description, ':') + 2) tle_description
, trim(tle.accountcode) tle_accountcode
, tle.glaccountcode glaccountcode_source
, tle.amountdc tle_amountdc
, tle.vatcode tle_vatcode
, tle.yourref tle_yourref
from exactonlinerest..transactionlines tle
join exactonlinerest..transactions txn
on tle.entryid = txn.entryid
where tle.glaccountcode like '290%'
and substr(tle.description, instr(tle.description, '/') + 1, instr(tle.description, ':') - instr(tle.description, '/') - 1) not like '11%' /* Not a bank account. */
order
by tle.entrynumber
, tle.linenumber
select 'GLTransactions\99-Interim-empty.xml'
filename
, stg.fileprefix
|| chr(13)
|| '<GLTransactions>'
|| xml
|| chr(13)
|| '</GLTransactions>'
|| stg.filepostfix
filecontents
from ( select listagg
( chr(13)
|| '<GLTransaction entry="'
|| txn_entrynumber
|| '">'
|| chr(13)
|| '<Journal code="'
|| txn_journalcode
|| '" />'
|| chr(13)
|| '<Date>'
|| substr(xmlencode(txn_date), 1, 10)
|| '</Date>'
|| chr(13)
|| xml
|| chr(13)
|| '</GLTransaction>'
, ''
) xml
from ( select txn_date
, txn_journalcode
, txn_financialyear
, txn_financialperiod
, txn_entrynumber
, listagg
( chr(13)
|| '<GLTransactionLine type="40" linetype="0" line="'
|| tle_linenumber
|| '" offsetline="1" status="20">'
|| chr(13)
|| '<Date>'
|| substr(xmlencode(tle_date), 1, 10)
|| '</Date>'
|| chr(13)
|| '<FinYear number="'
|| txn_financialyear
|| '" />'
|| chr(13)
|| '<FinPeriod number="'
|| txn_financialperiod
|| '" />'
|| chr(13)
|| '<GLAccount code="'
|| case
when tle_glaccountcode_target = '1560'
then '2902' /* Separate interim GL account, Twinfield does not provide separated. */
else xmlencode(tle_glaccountcode_target)
end
|| '" />'
|| case
when tle_description is not null
then chr(13)
|| '<Description>'
|| xmlencode(tle_description)
|| '</Description>'
end
|| case
when tle_accountcode is not null
then chr(13)
|| '<Account code="'
|| xmlencode(tle_accountcode)
|| '" />'
end
|| chr(13)
|| '<Amount>'
|| '<Currency code="EUR" />'
|| '<Value>'
|| -1 * tle_amountdc
|| '</Value>'
|| case
when tle_glaccountcode_target like '4%'
then '<VAT code="GB" />' /* GB = No VAT. */
else ''
end
|| '</Amount>'
|| chr(13)
|| '</GLTransactionLine>'
, ''
)
xml
from bank#inmemorystorage
group
by txn_date
, txn_journalcode
, txn_financialyear
, txn_financialperiod
, txn_entrynumber
)
)
join settings#inmemorystorage stg
on 1=1
In the column tle_yourref in bank#inmemorystorage there is a comma-separated list of associated sales/purchase invoices.
When manually entering the General Ledger transaction on the bank journal, the contents of your ref are populated by the reconciliation window. However, when I export the XML file from Exact Online with transactions, the your ref is missing.
At this moment I seem uncapable to automatically reconcile through an XML or REST API of Exact Online these transactions in the bank journal.
As a workaround you can select each individual account in Reconciliation window (they practically all amount to EUR 0) and then choose Automatic reconciliation. But there are too many accounts to do it with each conversion from Twinfield to Exact Online.
Is there an alternative way to associate invoices with the bank transactions through an API (REST or XML) of Exact Online?

If there is a 1 on 1 relation between the invoice and the payment (so only 1 invoice and 1 payment) you can use <References><InvoiceNumber>put invoice entrynumber here</InvoiceNumber></References> in the bank entry to have it automatically reconciled.
Another possibility is to create an XML file with the topic MatchSets (see documentation) to have it matched afterwards.

Additionally, you can also say:
<References><EntryNumber>10000012</EntryNumber><InvoiceNumber>FAC0001</InvoiceNumber></References>
This always works when the relation is 1=1.
If you specify only the invoice number the matching often fails silently.

Related

Why does output of & operator with any logic operation doesn't give any output in Ruby?

puts "Hello World"
scores = {"biology" => ['unit_test','final_exam'],
"maths" => ['quiz','class_participation','final_exam']
}
x = (scores["biology"] & %w[flying_test])
puts "result of x && scores[\"biology\"].any? => #{x && scores["biology"].any?}"# Why does this return true?
y = scores["maths"] & %w[quiz]
z = scores["maths"].any?
puts "result of scores[\"maths\"] & %w[quiz] => #{y}" # returns true
puts "result of scores[\"maths\"].any? => #{z}" # return true
puts "result of y && z => #{y && z}"
puts "******"
puts "Clubbing all conditions, returns no output, why? it is actually evluates to (true || true), right"
puts ( (scores["biology"].any? && (scores["biology"] & %w[flying_test])) ||
(scores["maths"].any? && (scores["maths"] & %w[quiz])) )
# But when above two sub-conditions are swapped puts print the value as true
puts "$$$$$$$"
puts ((scores["biology"] & %w[flying_test]) && scores["biology"].any?) ||
((scores["maths"] & %w[quiz]) && scores["maths"].any?)
puts "cross check"
# puts (1 == 1).any?
https://onlinegdb.com/YBmzutZOj - you can execute here
what are you actually trying to do with your "&"?
simplifying examples:
puts ( scores["biology"] & %w[flying_test] )
are you trying to check that the object exists, and only return the object, ala:
if scores["biology"].include?('flying_test')
or are you trying to do an addition:
scores["biology"] + %w[flying_test]
or return your list if there are no scores?
scores["biology"] || %w[flying_test]
...
or is it that you want to include the "&" as part of the test of what to return:
puts (scores['biology'].any? && scores['biology'].include?('flying_test') && %w[flying_test]) ||
(scores['maths'].any? && scores['maths'].include?('quiz') && %w[quiz])
or possibly, more like (closer to your style of coding):
puts (scores["biology"] & %w[flying_test]).any? && (scores["biology"] & %w[flying_test]) ||
scores["maths"] & %w[quiz]
?
&& returns the second operand, if both operands are truthy, and in ruby the empty list is truthy.
In your particular case, x = (scores["biology"] & %w[flying_test]) evaluates to the empty list [], so x && scores["biology"].any? actually evaluates to [] && true, so true.
Also, in
puts ( (scores["biology"].any? && (scores["biology"] & %w[flying_test])) ||
(scores["maths"].any? && (scores["maths"] & %w[quiz])) )
the first operand also evaluates to an empty list, so the entire || operation evaluates to the empty list []. Doing a puts [] results in a no output being generated.

How to leave out empty values in queries?

I'm trying to place these values into one column, but sometimes there is no value for 'County'. How can I make it that It doesn't show up as Name_of_town, , Postcode?
SQL> select SuppName || ', ' || Street || ', ' || Town || ', ' || County || ', ' || PostCode AS "Supplier Address"
2 from Suppliers
3 ORDER BY 1;
This is what I currently get back from the query. (Example of ',' by itself is on the first query result)
Supplier Address
--------------------------------------------------------------------------------
Business Systems Ltd., 155 Stradleigh Place, London, , E10 6LL
Fastorder Stationers, Riverside View, Newport, Gwent, NP1 7XJ
I.T. Supplies (Wales), 3 Marlborough Ave., Cardiff, , CF1 1IT
Legal Services Ltd., Westway Road, London, , N8 8PA
Office Matters, 20 Berrick Street, Bridgend, Mid Glam., CF38 3BB
TKG Tools Ltd., 7 High Street, Swansea, , SA7 2WG
It seems like Oracle's NVL is the way to go. It will replavce null values with a string of your choosing. I am assuming when you say there is no value for County, that field contains null. Otherwice oracle REPLACE would work.
NVL
Try this:
select SuppName || ', ' || Street || ', ' || Town || ', ' || NVL(County, 'No_County') || ', ' || PostCode AS "Supplier Address"
from Suppliers
ORDER BY 1;

Using dynamic table name in db2

Currently in my project development need of generating the record count based on certain criteria where the table names are stored in separate table.For instance say xx table stores the table name under the column name is tableInfo.
I've written the stored procedure in such a way that
DECLARE FGCURSOR CURSOR FOR SELECT tableInfo FROM xx WHERE col1='PO';
OPEN FGCURSOR;
FETCH FROM FGCURSOR INTO FILEGROUPMEM;
WHILE SQLCODE <> 100
DO
SET COUNTVal = 'SELECT COUNT(*) FROM ' || FILEGROUPMEM || ' WHERE ICLS= ' || CLASS || ' AND IVEN= ' || VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= ' || COLOR || ' AND ISIZ= ' || SIZE ;
IF(COUNTVal >= 1) THEN
RETURN 1;
END IF;
FETCH FROM FGCURSOR INTO FILEGROUPMEM;
END WHILE;
CLOSE FGCURSOR;
Getting the exception on executing the procedure saying that
Message: [SQL0420] Character in CAST argument not valid. Cause . . . .
. : A character in the argument for the CAST function was not
correct. Recovery . . . : Change the result data type to one that
recognizes the characters in the CAST argument, or change the argument
to contain a valid representation of a value for the result data type.
Try the request again.
This line is not correct:
SET COUNTVal = 'SELECT COUNT(*) FROM ' || FILEGROUPMEM || ' WHERE ICLS= ' || CLASS || ' AND IVEN= ' || VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= ' || COLOR || ' AND ISIZ= ' || SIZE ;
To use it the way you are trying, you'd have to use a static SQL statement like so
exec sql SELECT COUNT(*) INTO :COUNTVal
FROM MYTBL
WHERE ICLS= :CLASS AND IVEN= :VENDOR AND ISTY= :STYLE
AND ICLR= :COLOR AND ISIZ= :SIZE;
However, while a static statement can use variables, the table name in the FROM clause can not be variable.
Thus you have to prepare and use a dynamic statement. Unfortunately, SELECT INTO can not be used in a dynamic statement. VALUES INTO can be used dynamically.
set wSqlStmt = 'VALUES ( SELECT COUNT(*) FROM ' || FILEGROUPMEM
|| ' WHERE ICLS= ' || CLASS || ' AND IVEN= '
|| VENDOR || ' AND ISTY= ' || STYLE || ' AND ICLR= '
|| COLOR || ' AND ISIZ= ' || SIZE ||') INTO ?';
exec sql PREPARE S1 FROM :wSqlStmt;
exec sql EXECUTE S1 USING COUNTVal;
WARNING the above code could be subject to SQL Injection attacks. To protect against SQL injection, dynamic SQL should use parameter markers instead of concatenating input directly to a statement. While you can't use a parameter marker for the table name, you can for the rest of the variables like so:
set wSqlStmt = 'VALUES ( SELECT COUNT(*) FROM ' || FILEGROUPMEM
|| ' WHERE ICLS= ? AND IVEN= ? '
|| ' AND ISTY= ? AND ICLR= ?'
|| ' AND ISIZ= ?) INTO ?';
exec SQL PREPARE S1 FROM :wSqlStmt;
exec SQL EXECUTE S1 USING :CLASS, :VENDOR, :STYLE, :COLOR, :SIZE, :COUNTVal;

Oracle Stored Procedure update rows if records exist

I have following Oracle stored procedure. Either subcode or stylecode is passed in. Currently it is update rows if value is not null. I want to add logic so that make update only if rows are exists on the table, if not, I like to print message like "The subcode xxxx doesn't exists" or "The stylecode xxxx doesn't exists". I don't think merge into works here.
create or replace PROCEDURE "REMOVE_PRICES"
(
RESULT OUT VARCHAR2
, STYLECODE_ IN NUMBER
, SUBCODE_ IN NUMBER
) AS
BEGIN
IF (SUBCODE_ is null AND STYLECODE_ is null)
THEN
raise_application_error(-20005, 'ERROR: Please provide either SUBCODE or STYLECODE!');
END IF;
IF SUBCODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE subcode=SUBCODE_;
RESULT := SQL%ROWCOUNT || ' price for subcode ' || SUBCODE_ || ' is removed';
ELSIF STYLECODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE stylecode=STYLECODE_;
RESULT := SQL%ROWCOUNT || ' price for stylecode ' || STYLECODE_ || ' is removed';
END IF;
END REMOVE_PRICES;
You can't only choose to do the update if it will affect rows unless you query with the same conditions first, doing a count; and you could still have a race condition with other sessions that means the data could change between the select and the update, unless you lock the rows. Which all seems a bit excessive and costly.
You can just check the value of SQL%ROWCOUNT and show that message if it is zero, or your current message otherwise:
IF SUBCODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE subcode=SUBCODE_;
IF SQL%ROWCOUNT = 0 then
RESULT := 'The subcode ' || SUBCODE || ' does not exist';
ELSE
RESULT := SQL%ROWCOUNT || ' price for subcode ' || SUBCODE_ || ' is removed';
END IF;
ELSIF STYLECODE_ IS NOT NULL THEN
UPDATE prices
SET type = null
WHERE stylecode=STYLECODE_;
IF SQL%ROWCOUNT = 0 then
RESULT := 'The stylecode ' || STYLECODE || ' does not exist';
ELSE
RESULT := SQL%ROWCOUNT || ' price for stylecode ' || STYLECODE_ || ' is removed';
END IF;
END IF;

Run time error 438: (wks.cells(i, 1))

I am attempting to paste information from a spreadsheet to a form in my Access database but I get an error at the Do Until IsEmpty(wks.Cells(i, 1)) line. I am using Access 2010.
Option Compare Database
Private Sub Cmd_Mass_Upload_Click()
If MsgBox("ARE YOU SURE YOU WANT TO UPDATE RECORDS?", vbOKCancel, "CONFIRM MASS UPDATE") = vbOK Then
Dim wks
Dim db As Database
Dim rsCheckDuplicate As Recordset
Dim rsUpdateCC As Recordset
Dim strSQLCheckDuplicate As String
Dim strUpdateCC As String
Dim succesfullyUpdated As Integer
succesfullyUpdated = 0
i = 1
'If Me.Ctl2003 = True Then
Set wks = Me.upLoadSpreadsheet2010
'End If
'If Me.Ctl2010 = True Then
' Set wks = Me.upLoadSpreadsheet2010
'End If
Do Until IsEmpty(wks.Cells(i, 1))
i = i + 1
Loop
Set db = CurrentDb
If i > 1 Then
For j = 1 To i - 1
strSQLCheckDuplicate = "SELECT TBL_OPEN_VOUCHERS.[VOUCHER NUMBER], TBL_OPEN_VOUCHERS.[INVOICE NUMBER] " & _
"FROM TBL_OPEN_VOUCHERS " & _
"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "') AND ((TBL_OPEN_VOUCHERS.[INVOICE NUMBER])='" & wks.Cells(j, 2) & "'));"
'"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "'));"
Set rsCheckDuplicate = db.OpenRecordset(strSQLCheckDuplicate)
If rsCheckDuplicate.EOF Then
MsgBox "Voucher number " & wks.Cells(j, 1) & " not available in local system!"
Else
rsCheckDuplicate.MoveLast
rsCheckDuplicate.MoveFirst
If rsCheckDuplicate.RecordCount > 1 Then
MsgBox "Voucher number " & wks.Cells(j, 1) & " has multiple entries in local system! Please update manually!"
End If
If Len(wks.Cells(j, 3)) = 6 Then
strUpdateCC = "UPDATE TBL_OPEN_VOUCHERS SET TBL_OPEN_VOUCHERS.[CHARGE TO] = '" & wks.Cells(j, 3) & "', TBL_OPEN_VOUCHERS.COMMENTS_NOTES = '" & Form_FRM_MAIN.USER.Caption & ": PART OF MASS UPLOAD ON " & Now() & "' " & _
"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "') AND ((TBL_OPEN_VOUCHERS.[INVOICE NUMBER])='" & wks.Cells(j, 2) & "'));"
'"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "'));"
DoCmd.RunSQL strUpdateCC
succesfullyUpdated = succesfullyUpdated + 1
Else
MsgBox "Please check Cost Center"
End If
End If
Next
End If
Set wks = Nothing
MsgBox "Successfully uploaded " & succesfullyUpdated & " of " & i - 1 & " records!"
End If
End Sub
Private Sub Command7_Click()
On Error GoTo Err_Command7_Click
DoCmd.Close
Exit_Command7_Click:
Exit Sub
Err_Command7_Click:
MsgBox Err.Description
Resume Exit_Command7_Click
End Sub
Private Sub Ctl2003_Click()
If Me.Ctl2003 = False Then Me.Ctl2010 = True
If Me.Ctl2003 = True Then Me.Ctl2010 = False
End Sub
Private Sub Ctl2010_Click()
If Me.Ctl2010 = True Then Me.Ctl2003 = False
If Me.Ctl2010 = False Then Me.Ctl2003 = True
End Sub
What was the actual error message you were getting?
Have you tried creating a connection to the spreadsheet as a linked table, then treating the spreadsheet as a table?
Your code doesn't specify the datatype of the "wks" object, so the code doesn't know it is a spreadsheet.
Here's the approach I'd use:
Link the spreadsheet as a linked table (External Data, Import Excel Spreadsheet, Link to the DataSource.) This will create a "table" in access which is linked to a spreadsheet that is in a nominated location.
Use a query to identify records that are in your linked table but not in your local table (select s.* from upLoadSpreadsheet2010 s left outer join tbl_open_vouchers v on s.somekeycolumnidontknowthenameof = v.[voucher number] and s.someotherkeycolumn = v.[Invoice Number] where v.[voucher number] is null)
Open the query in your code, iterate through it, and do you thing, or better still create an Append query to do the job for you without any code at all.
The only challenge then is ensure the excel spreadsheet is in the right place at the right time. New spreadsheet? Just put it in the same place as the last spreadsheet and run the process again.

Resources