It is possible that XML-tables are lacking fields that actually can have content due to limitations of the XML-documentation (the so-called “XSD” which can also be downloaded through the “Import/Export” menu in Exact Online). Exact has made little changes to extend or update the XML API in terms of documentation and functionality over the last five years. However, this limitation does not in any way restrict the uploading of XML. In fact, the use of insert
, update
and delete
on the XML schema is not recommended if possible at all (there are few tables for which a module has been created).
The recommended way, which also opens all capabilities as described in the XSD, is the use of UploadXMLTopics
. The use of UploadXMLTopics
as illustrated in Mass copy pictures across Exact Online articles also has exactly the same functionality as the XML file that can be uploaded via the user interface of Exact Online.
Another example can be found below, which is a simplified version of the transaction mass import on https://get-my-report.com
It reads from an Excel file uploaded through a website, but exceltable
also accepts local files when run on a device. Next, it transforms the data in the needed XML format for Exact Online. Then it uses UploadXMLTopics
to upload the data, whereas the last queries select an overview of the results.
begin
--
-- Load transactions in Exact Online from an uploaded Excel sheet.
--
-- Retrieve transaction lines from Excel source.
--
create or replace table source@inmemorystorage
as
select cast(coalesce(division_code, to_number(:division_code_default)) as int32)
division_code
label "{res:itgen_eol_administration}"
, trim(journal_code)
journal_code
label "{res:itgen_eol_journal_code}"
, entry_number
label "{res:itgen_eol_journal_entry_number}"
, financial_year
label "{res:itgen_eol_financial_year}"
, financial_period
label "{res:itgen_eol_financial_period}"
, trim(description)
description
label "{res:itgen_eol_description}"
, '[GMRIVEIMP:'
|| to_char(cast(coalesce(division_code, to_number(:division_code_default)) as int32))
|| '-'
|| :orig_system_group
|| '-'
|| trim(journal_code)
|| '-'
|| entry_number
-- || '-'
-- Not yet available in exceltable. Needs row_number from ITGEN-3552.
-- || linenumber
|| '] '
|| replace(translate_resources('{res:itgen_gmr_imported_note_par1}'), '{0}', to_char(sysdate))
note
label "{res:itgen_eol_note}"
, entry_date
label "{res:itgen_eol_entry_date}"
, trim(gl_account_code)
gl_account_code
label "{res:itgen_eol_general_ledger_account}"
, trim(cost_center_code)
cost_center_code
label "{res:itgen_eol_cost_center}"
, trim(cost_unit_code)
cost_unit_code
label "{res:itgen_eol_cost_unit}"
, trim(currency_code)
currency_code
label "{res:itgen_eol_currency_code}"
, trim(vat_code)
vat_code
label "{res:itgen_eol_vatcode}"
, trim(account_code)
account_code
label "{res:itgen_eol_account_code}"
, trim(project_code)
project_code
label "{res:itgen_eol_project_code}"
, start_date
label "{res:itgen_eol_start_date}"
, end_date
label "{res:itgen_eol_end_date}"
, amount
label "{res:itgen_eol_amount}"
, null /* Not yet used. */
references
label "{res:itgen_reference}"
, to_char(sysdate, 'YYYYMMDDHH24MISS') file_timestamp
label "{res:itgen_time_stamp}"
from exceltable
( worksheet 'General Ledger Transactions'
passing :upload_file
skip empty rows
skip first 1 rows
columns division_code int64 position 1
, journal_code varchar2 position 2
, entry_number int32 position 3
, financial_year int16 position 4
, financial_period int16 position 5
, description varchar2 position 6
, entry_date date position 7
, gl_account_code varchar2 position 8
, amount number position 9
, cost_center_code varchar2 position 10
, cost_unit_code varchar2 position 11
, currency_code varchar2 position 12
, vat_code varchar2 position 13
, account_code varchar2 position 14
, project_code varchar2 position 15
, start_date date position 16
, end_date date position 17
)
;
set use-http-disk-cache-read@eol false;
set use-http-disk-cache-write@eol false;
set use-http-memory-cache-read@eol false;
set use-http-memory-cache-write@eol false;
--
-- Optional checks removed.
--
--
-- Actual upload.
--
create or replace table sourcelinesxml@inmemorystorage
as
select src.division_code
, src.entry_date
, src.entry_number
, src.journal_code
, src.financial_year
, src.financial_period
, src.journal_code
|| '/'
|| to_char(src.entry_number)
|| ':'
|| to_char(src.financial_year)
|| '-'
|| to_char(src.financial_period)
description
, '<GLTransaction entry="'
|| src.entry_number
|| '">'
|| chr(13)
|| '<Journal code="'
|| src.journal_code
|| '" />'
|| chr(13)
|| '<FinYear number="'
|| src.financial_year
|| '" />'
|| '<FinPeriod number="'
|| src.financial_period
|| '" />'
head
, '<GLTransactionLine>'
|| '<Date>'
|| substr(xmlencode(src.entry_date), 1, 10)
|| '</Date>'
|| '<FinYear number="'
|| src.financial_year
|| '" />'
|| '<FinPeriod number="'
|| src.financial_period
|| '" />'
|| '<GLAccount code="'
|| src.gl_account_code
|| '" />'
|| case
when src.cost_center_code is not null
then '<Costcenter code="'
|| src.cost_center_code
|| '" />'
end
|| case
when src.cost_unit_code is not null
then '<Costunit code="'
|| src.cost_unit_code
|| '" />'
end
|| case
when src.project_code is not null
then '<Project code="'
|| src.project_code
|| '" />'
end
|| case
when src.account_code is not null
then '<Account code="'
|| src.account_code
|| '" />'
end
|| case
when src.description is not null
then xmlelement('Description', src.description, false)
end
|| case
when src.note is not null
then xmlelement('Note', src.note, false)
end
|| case
when src.references is not null
then '<References>'
|| xmlelement('InvoiceNumber', src.references, false)
|| '</References>'
end
|| '<Amount>'
|| xmlelement('Value', src.amount, false)
|| case
when src.currency_code is not null
then '<Currency code="'
|| src.currency_code
|| '" />'
end
|| case
when src.vat_code is not null
then '<VAT code="'
|| src.vat_code
|| '" />'
end
|| '</Amount>'
|| case
when src.start_date is not null
then xmlelement('DeferredFrom', src.start_date, false)
end
|| case
when src.end_date is not null
then xmlelement('DeferredTo', src.end_date, false)
end
|| '</GLTransactionLine>'
line
from source@inmemorystorage src
;
--
create or replace table xmlupload@inmemorystorage
as
select 'GLTransactions' topic
, division_code
, null orig_system_reference
, :orig_system_group orig_system_group
, xmlformat
( '<?xml version="1.0" encoding="utf-8"?>'
|| '<eExact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="eExact-XML.xsd">'
|| xmlcomment(replace(translate_resources('{res:itgen_gmr_for_company_par1}'), '{0}', division_code))
|| xmlcomment(replace(translate_resources('{res:itgen_gmr_orig_system_group_par1}'), '{0}', :orig_system_group))
|| '<GLTransactions>'
|| xml
|| '</GLTransactions>'
|| '</eExact>'
)
filecontents
from ( select division_code
, listagg
( head
|| lines
|| '</GLTransaction>'
, ''
)
xml
from ( select brl.division_code
, brl.head
, listagg(brl.line, '') lines
from sourcelinesxml@inmemorystorage brl
group
by brl.division_code
, brl.head
)
group
by division_code
)
;
--
-- Upload into Exact Online.
--
insert into UploadXMLTopics@eol
( topic
, payload
, division_code
, orig_system_reference
, orig_system_group
, fragment_payload_flag
, fragment_max_size_characters
, fail_on_error
)
select topic
, filecontents
, to_char(division_code)
, orig_system_reference
, orig_system_group
--
-- Try to split into pieces of 25 KB at most.
--
, true fragment_payload_flag
, 25000 fragment_max_size_characters
--
-- Returns error through user interface, not as a HTTP 500 error.
--
, false fail_on_error
from xmlupload@inmemorystorage
order
by division_code
, orig_system_reference
, orig_system_group
;
end;
--
-- Include input in resulting spreadsheet.
--
select /*+ result_set_name("Source") */
*
from source@inmemorystorage
--
-- Results.
--
select /*+ result_set_name("Results") */
uxt.transaction_id
, uxt.successful
, uxt.division_code
, uxt.orig_system_reference
, uxt.orig_system_group
, uxt.date_started_utc
, uxt.date_ended_utc
, substr(uxt.payload, 1, 32767)
payload_32k
label "{res:itgen_eol_payload}"
, substr(uxt.result, 1, 32767)
result_32k
label "{res:itgen_result}"
, substr(uxt.result_errors, 1, 32767)
result_errors_32k
label "{res:itgen_eol_result_errors}"
, substr(uxt.payload_retry_failed, 1, 32767)
payload_retry_failed
label "{res:itgen_eol_payload_retry_failed}"
from UploadXMLTopicFragments@eol uxt
order
by uxt.transaction_id desc