Thanks for response.
The flow is as follows:
-
Create GL Journal Group
a. Erp.Bo.GLJrnGrrpSvc - GetNewGLJrnGrp
b. Erp.Bo.GLJrnGrrpSvc - Update
-
Create the GL Journal Header
a. Erp.Bo.GLJournalEntrySvc - GetNewGLJrnHedTran
b. Erp.Bo.GLJournalEntrySvc - PreUpdate
c. Erp.Bo.GLJournalEntrySvc - Update
-
Create the GL Journal Detail - a Manual Journals
a. Erp.Bo.GLJournalEntrySvc - GetNewGLJrnDtlMnl ( Trace show a call to ChangeGlAcct1() but there is no need here as none of my GL Account will trigger anything)
b. Erp.Bo.GLJournalEntrySvc - Update
I’m rolling my own classes below (as I don’t need the hundreds properties to create a basic entry).
I’m expecting back from 3a either s GLJrnDtlMnl object (index 0) which will be simply sent back to Update to actually create the records. But I have hundreds of empty records and no idea on how to delete. They aren’t yet saved as database record so I have no SysRowID I can simply delete against.
Below is python code. More to proto-type and diagnose (it aint pretty).
Looking to build into a C# solution as part of an Excel Addin.
I’m dangerous enough to understand how this could works but yet good enough to do this well.
Mostly hardcoded but only to get a single row loaded then will be made more dynamic.
from json import JSONDecodeError
import requests
import urllib.parse
import os
from base64 import b64encode
from config import logger
import time
import jsons
class Epicor(object):
companies = ['aaaaa', 'bbbbb, 'ccccc, 'dddddd']
api_headers = {'X-API-Key' : os.getenv('EPICOR_API'),
'Authorization' : f'Basic {os.getenv("EPICOR_AUTH")}',
'accept' : 'application/json',
'Content-Type' : 'application/json'}
dev_url = "https://xxxxxxxx.epicorsaas.com/xxxxpilot/api/v2/odata"
live_url = "https://xxxxxxxx.epicorsaas.com/xxxx201/api/v2/odata"
# Authorization token: we need to base 64 encode it
# and then decode it to acsii as python 3 stores it as a byte string
def basic_auth(self, username, password):
token = b64encode(f"{username}:{password}".encode('utf-8')).decode("ascii")
return f'Basic {token}'
def __init__(self, live=False, company=None, username=None, password=None):
self.base_url = Epicor.live_url if live else Epicor.dev_url
self.service_url = None
self.servce = None
self.company = company
auth = self.basic_auth(os.getenv("EPICOR_USER"), os.getenv("EPICOR_PASS"))
self.api_headers['Authorization'] = auth
# if username:
# auth = self.basic_auth(username, password)
# self.api_headers['Authorization'] = auth
def post2(self, company, service_url, service, data):
# response = requests.post(f"{self.base_url}/{self.company}/{self.service_url}/{self.service}", headers=Epicor.api_headers , data=jsons.dumps(data))
response = requests.post(f"{self.base_url}/{company}/{service_url}/{service}", headers=Epicor.api_headers , json=data)
if response.status_code in (200, 201):
pass
elif response.status_code in (400, 401, 404):
print ("Error of either 400, 401, 404")
print (f"Error message json:\n{response.content}")
print (f"Error message json:\n{response}")
# breakpoint()
elif response.status_code in (500, 501):
print (f"Error message json:\n{response}")
print ("Check closely format of input - numbers as string, dates as properly formatted ISO date strings, etc and json properly formats. Check for an array of objects (and not just an object)")
print("Breaking...")
breakpoint()
return response
from Epicor2 import Epicor
import jsons
class GLJrnGrp(object):
data = { 'Company' : "aaaaa",
'GroupID' : "AABBCC",
'BookMode' : 'S',
'BookID' : "MAIN",
'CurrencyCode' : "AUD",
'RateGrpCode' : "MAIN",
# JEDate : "2024-05-31"
'FiscalYear' : 2024,
'FiscalPeriod' : 11,
'JournalCode' : "MJ",
'FiscalCalendarID' : "MASTER",
'COACode' : "MAIN",
'Posted' : False,
'RowMod' : 'A'
}
def __init__(self):
pass
class GLJrnHed(object):
data = { 'Company' : 'aaaaa',
'FiscalCalendar' : 'MASTER',
'FiscalYear' : 2024,
'FiscalPeriod' : 11,
'JournalNum' : 0,
'Description' : 'Journal Header Load',
'JEDate' : '2024-05-31T00:00:00.000Z',
'GroupID' : 'AABBCC',
'CurrencyCode': 'AUD',
'EnteredBy' : 'Sam Benson',
'JournalCode' : 'MJ',
'BookID' : 'MAIN',
'TaxHandling' : '1',
'TotDebit' : 0,
'TotCredit' : 0,
# 'SysRevID' : None,
# 'SysRowID' : None,
'RateGrpCode' : 'MAIN',
'RowMod' : ''
}
class GLJrnDtlMnl(object):
data = {
'Company' : 'aaaaa',
'GroupID' : 'AABBCC',
'JEDate' : '2024-05-31T00:00:00.000Z',
'FiscalYear' : 2024,
'FiscalPeriod' : 11,
'JournalNum' : '',
'JournalLine' : 0,
'Description' : 'Journal Line 1',
'TransAmt' : 110,
'Posted' : False,
'SourceModule' : 1,
'COACode' : 'MAIN',
'CommentText' : 'A Comments',
'GLAccount' : '11510-1004',
'SegValue1' : '11510',
'SegValue2' : '1004',
'BookID' : 'MAIN',
'DocTransAmt' : 0,
'CurrencyCode' : 'AUD',
'DebitAmount' : 110,
'CreditAmount' : 0,
'TotDebit' : 110,
'TotCredit' : 0,
'TaxableAmtBookCurr' : 'AUD',
'TaxableAmtCurr' : 'AUD',
'TaxableAmtInBookCurr' : 110,
'TaxableAmtInTranCurr' : 110,
'TaxableLine' : '',
'TaxLiability' : 'AUST',
'TaxLine' : False,
'RowMod' : 'A',
'TaxRate' : '',
'TaxType' : '',
'ReportingModule' : '',
'TaxPointDate' : '',
}
def make_group():
group = GLJrnGrp().data
load = { 'ds' : { "GLJrnGrp" : [{}]}} # , 'Company' : group.Company, 'FiscalPeriod' : group.FiscalPeriod, 'FiscalYear' : group.FiscalYear, 'JEDate' : group.JEDate }
resp = epicor.post2("aaaaa", "Erp.BO.GLJrnGrpSvc", "GetNewGLJrnGrp", load).json()
update = resp['parameters']['ds']
update['GLJrnGrp'][1]['GroupID'] = group['GroupID']
# update['GLJrnGrp'][1]['GroupID'] = group['GroupID']
resp = epicor.post2("aaaaa", "Erp.BO.GLJrnGrpSvc", "Update", {'ds' : { 'GLJrnGrp' : [update['GLJrnGrp'][1]]}})
return resp
def make_gl_journal_headers():
header = GLJrnHed().data
header['RowMod'] = 'A'
response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "GetNewGlJrnHedTran", { 'ds' : {'GLJrnHed' : [header]}, "GroupID" : 'AABBCC'}).json();
preupdate = {'ds' :{ 'GLJrnHed' : [header] } };
response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "PreUpdate", preupdate).json();
update = {'ds' :{ 'GLJrnHed' : [response['parameters']['ds']['GLJrnHed'][0]]} };
response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "Update", update).json();
return response
def make_gl_journal_line(header):
line = { 'ds' : { 'GLJrnHed' : [header]}, 'bookID' : 'MAIN', 'fiscalYear' : 2024, 'fiscalPeriod' : 11, 'fiscalYearSuffix' : '', 'journalCode' : 'MJ', 'journalNum' : header[0]['JournalNum'], 'journalLine' : 0}
breakpoint()
response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "GetNewGLJrnDtlMnl", line).json();
# line = { 'ds' : { 'GLJrnHed' : [response['parameters']['ds']['GLJrnHed'][0]] , 'GLJrnDtlMnl' : [response['parameters']['ds']['GLJrnDtlMnl'][0]]}, 'iLineNum' : response['parameters']['ds']['GLJrnDtlMnl'][0]['JournalLine']}
# breakpoint()
# response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "ChangeGlAcct1", line).json();
print("After GetNewGLJrnDtlMnl")
breakpoint()
with open('response.txt', 'wt') as f:
f.write(str(response))
# temp = GLJrnDtlMnl().data
# temp['JournalNum'] = header[0]['JournalNum']
# preupdate = {'ds' :{ 'GLJrnHed' : header , 'GLJrnDtlMnl' : [temp] }}
# response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "PreUpdate", preupdate).json();
update = {'ds' :{ 'GLJrnHed' : [response['parameters']['ds']['GLJrnHed'][0]], 'GLJrnDtlMnl' : [response['parameters']['ds']['GLJrnDtlMnl'][0]]} }
breakpoint()
response = epicor.post2("aaaaa", "Erp.BO.GLJournalEntrySvc", "Update", update).json();
breakpoint()
return response
if __name__ == "__main__":
epicor = Epicor(False, "aaaaa")
# resp = make_group()
resp = make_gl_journal_headers()
resp = make_gl_journal_line(resp['parameters']['ds']['GLJrnHed'])
print(resp)
breakpoint()
print("Debug")
Cheers