|
|
@ -24,6 +24,7 @@ import sys
|
|
|
|
from itertools import islice
|
|
|
|
from itertools import islice
|
|
|
|
from multiprocessing import Process
|
|
|
|
from multiprocessing import Process
|
|
|
|
import transport
|
|
|
|
import transport
|
|
|
|
|
|
|
|
import jsonmerge
|
|
|
|
class void :
|
|
|
|
class void :
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
class Formatters :
|
|
|
|
class Formatters :
|
|
|
@ -70,7 +71,7 @@ class Formatters :
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
|
|
value = [ [prefix]+ self.split(item,'>') for item in row.replace('~','').split(sep)[1:] ]
|
|
|
|
value = [ [prefix]+ self.split(item,'>') for item in row.replace('~','').split(sep)[1:] ]
|
|
|
|
|
|
|
|
|
|
|
|
return value if type(value) == list and type(value[0]) != list else value[0]
|
|
|
|
return value if type(value) == list and type(value[0]) != list else value[0]
|
|
|
|
def get_config(self,config,row):
|
|
|
|
def get_config(self,config,row):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
@ -95,7 +96,6 @@ class Formatters :
|
|
|
|
if _row[0] in config['SIMILAR'] :
|
|
|
|
if _row[0] in config['SIMILAR'] :
|
|
|
|
key = config['SIMILAR'][_row[0]]
|
|
|
|
key = config['SIMILAR'][_row[0]]
|
|
|
|
_info = config[key]
|
|
|
|
_info = config[key]
|
|
|
|
|
|
|
|
|
|
|
|
return _info
|
|
|
|
return _info
|
|
|
|
|
|
|
|
|
|
|
|
def hash(self,value):
|
|
|
|
def hash(self,value):
|
|
|
@ -181,13 +181,16 @@ class Formatters :
|
|
|
|
return x
|
|
|
|
return x
|
|
|
|
class Parser (Process):
|
|
|
|
class Parser (Process):
|
|
|
|
def __init__(self,path):
|
|
|
|
def __init__(self,path):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
:path path of the configuration file (it can be absolute)
|
|
|
|
|
|
|
|
"""
|
|
|
|
Process.__init__(self)
|
|
|
|
Process.__init__(self)
|
|
|
|
self.utils = Formatters()
|
|
|
|
self.utils = Formatters()
|
|
|
|
self.get = void()
|
|
|
|
self.get = void()
|
|
|
|
self.get.value = self.get_map
|
|
|
|
self.get.value = self.get_map
|
|
|
|
self.get.default_value = self.get_default_value
|
|
|
|
self.get.default_value = self.get_default_value
|
|
|
|
_config = json.loads(open(path).read())
|
|
|
|
_config = json.loads(open(path).read())
|
|
|
|
|
|
|
|
self._custom_config = self.get_custom(path)
|
|
|
|
self.config = _config['parser']
|
|
|
|
self.config = _config['parser']
|
|
|
|
self.store = _config['store']
|
|
|
|
self.store = _config['store']
|
|
|
|
|
|
|
|
|
|
|
@ -197,6 +200,27 @@ class Parser (Process):
|
|
|
|
self.emit = void()
|
|
|
|
self.emit = void()
|
|
|
|
self.emit.pre = None
|
|
|
|
self.emit.pre = None
|
|
|
|
self.emit.post = None
|
|
|
|
self.emit.post = None
|
|
|
|
|
|
|
|
def get_custom(self,path) :
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
:path path of the configuration file (it can be absolute)
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
_path = path.replace('config.json','')
|
|
|
|
|
|
|
|
if _path.endswith(os.sep) :
|
|
|
|
|
|
|
|
_path = _path[:-1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_config = {}
|
|
|
|
|
|
|
|
_path = os.sep.join([_path,'custom'])
|
|
|
|
|
|
|
|
if os.path.exists(_path) :
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
files = os.listdir(_path)
|
|
|
|
|
|
|
|
if files :
|
|
|
|
|
|
|
|
fullname = os.sep.join([_path,files[0]])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_config = json.loads ( (open(fullname)).read() )
|
|
|
|
|
|
|
|
return _config
|
|
|
|
|
|
|
|
|
|
|
|
def set_files(self,files):
|
|
|
|
def set_files(self,files):
|
|
|
|
self.files = files
|
|
|
|
self.files = files
|
|
|
|
def get_map(self,row,config,version=None):
|
|
|
|
def get_map(self,row,config,version=None):
|
|
|
@ -247,15 +271,18 @@ class Parser (Process):
|
|
|
|
|
|
|
|
|
|
|
|
value = {key:value} if key not in value else value
|
|
|
|
value = {key:value} if key not in value else value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
if 'syn' in config and value in config['syn'] :
|
|
|
|
if 'syn' in config and value in config['syn'] :
|
|
|
|
value = config['syn'][value]
|
|
|
|
value = config['syn'][value]
|
|
|
|
if type(value) == dict :
|
|
|
|
if type(value) == dict :
|
|
|
|
|
|
|
|
|
|
|
|
object_value = dict(object_value, **value)
|
|
|
|
object_value = dict(object_value, **value)
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
|
|
object_value[key] = value
|
|
|
|
object_value[key] = value
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# we are dealing with a complex object
|
|
|
|
# we are dealing with a complex object
|
|
|
@ -275,26 +302,35 @@ class Parser (Process):
|
|
|
|
return object_value
|
|
|
|
return object_value
|
|
|
|
def apply(self,content,_code) :
|
|
|
|
def apply(self,content,_code) :
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
:file content i.e a segment with the envelope
|
|
|
|
:content content of a file i.e a segment with the envelope
|
|
|
|
:_code 837 or 835 (helps get the appropriate configuration)
|
|
|
|
:_code 837 or 835 (helps get the appropriate configuration)
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
util = Formatters()
|
|
|
|
util = Formatters()
|
|
|
|
# header = default_value.copy()
|
|
|
|
# header = default_value.copy()
|
|
|
|
value = {}
|
|
|
|
value = {}
|
|
|
|
|
|
|
|
|
|
|
|
for row in content[:] :
|
|
|
|
for row in content[:] :
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
row = util.split(row.replace('\n','').replace('~',''))
|
|
|
|
row = util.split(row.replace('\n','').replace('~',''))
|
|
|
|
_info = util.get.config(self.config[_code][0],row)
|
|
|
|
_info = util.get.config(self.config[_code][0],row)
|
|
|
|
|
|
|
|
if self._custom_config and _code in self._custom_config:
|
|
|
|
|
|
|
|
_cinfo = util.get.config(self._custom_config[_code],row)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
_cinfo = {}
|
|
|
|
|
|
|
|
# _info = self.consolidate(row=row,type=_code,config=_info,util=util)
|
|
|
|
|
|
|
|
# print ([row[0],_info])
|
|
|
|
|
|
|
|
# print ()
|
|
|
|
|
|
|
|
# continue
|
|
|
|
|
|
|
|
# _cinfo = util.get.config(self._custom_config[_code],row)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if _info :
|
|
|
|
if _info :
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
|
|
|
|
_info = jsonmerge.merge(_info,_cinfo)
|
|
|
|
tmp = self.get.value(row,_info)
|
|
|
|
tmp = self.get.value(row,_info)
|
|
|
|
|
|
|
|
|
|
|
|
# if 'P1080351470' in content[0] and 'PLB' in row:
|
|
|
|
|
|
|
|
# print (_info)
|
|
|
|
|
|
|
|
# print (row)
|
|
|
|
|
|
|
|
# print (tmp)
|
|
|
|
|
|
|
|
if not tmp :
|
|
|
|
if not tmp :
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
if 'label' in _info :
|
|
|
|
if 'label' in _info :
|
|
|
@ -326,7 +362,9 @@ class Parser (Process):
|
|
|
|
elif 'field' in _info :
|
|
|
|
elif 'field' in _info :
|
|
|
|
|
|
|
|
|
|
|
|
name = _info['field']
|
|
|
|
name = _info['field']
|
|
|
|
value[name] = tmp
|
|
|
|
# value[name] = tmp
|
|
|
|
|
|
|
|
value = jsonmerge.merge(value,{name:tmp})
|
|
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -341,6 +379,7 @@ class Parser (Process):
|
|
|
|
return value if value else {}
|
|
|
|
return value if value else {}
|
|
|
|
|
|
|
|
|
|
|
|
def get_default_value(self,content,_code):
|
|
|
|
def get_default_value(self,content,_code):
|
|
|
|
|
|
|
|
|
|
|
|
util = Formatters()
|
|
|
|
util = Formatters()
|
|
|
|
TOP_ROW = content[1].split('*')
|
|
|
|
TOP_ROW = content[1].split('*')
|
|
|
|
CATEGORY= content[2].split('*')[1].strip()
|
|
|
|
CATEGORY= content[2].split('*')[1].strip()
|
|
|
@ -359,6 +398,8 @@ class Parser (Process):
|
|
|
|
value['payer_id'] = SENDER_ID
|
|
|
|
value['payer_id'] = SENDER_ID
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
value['provider_id'] = SENDER_ID
|
|
|
|
value['provider_id'] = SENDER_ID
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# Let's parse this for default values
|
|
|
|
return value
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
def read(self,filename) :
|
|
|
|
def read(self,filename) :
|
|
|
@ -381,8 +422,14 @@ class Parser (Process):
|
|
|
|
INITIAL_ROWS = file[:4]
|
|
|
|
INITIAL_ROWS = file[:4]
|
|
|
|
if len(INITIAL_ROWS) < 3 :
|
|
|
|
if len(INITIAL_ROWS) < 3 :
|
|
|
|
return None,[{"name":filename,"completed":False}],None
|
|
|
|
return None,[{"name":filename,"completed":False}],None
|
|
|
|
section = 'HL' if INITIAL_ROWS[1].split('*')[1] == 'HC' else 'CLP'
|
|
|
|
# section = 'HL' if INITIAL_ROWS[1].split('*')[1] == 'HC' else 'CLP'
|
|
|
|
_code = '837' if section == 'HL' else '835'
|
|
|
|
# _code = '837' if section == 'HL' else '835'
|
|
|
|
|
|
|
|
# print ([_code,section])
|
|
|
|
|
|
|
|
_code = INITIAL_ROWS[2].split('*')[1].strip()
|
|
|
|
|
|
|
|
# section = 'CLP' if _code == '835' else 'HL'
|
|
|
|
|
|
|
|
section = self.config[_code][0]['SECTION'].strip()
|
|
|
|
|
|
|
|
#
|
|
|
|
|
|
|
|
# adjusting the
|
|
|
|
DEFAULT_VALUE = self.get.default_value(INITIAL_ROWS,_code)
|
|
|
|
DEFAULT_VALUE = self.get.default_value(INITIAL_ROWS,_code)
|
|
|
|
DEFAULT_VALUE['name'] = filename.strip()
|
|
|
|
DEFAULT_VALUE['name'] = filename.strip()
|
|
|
|
#
|
|
|
|
#
|
|
|
@ -390,22 +437,30 @@ class Parser (Process):
|
|
|
|
# index 1 identifies file type i.e CLM for claim and CLP for remittance
|
|
|
|
# index 1 identifies file type i.e CLM for claim and CLP for remittance
|
|
|
|
segment = []
|
|
|
|
segment = []
|
|
|
|
index = 0;
|
|
|
|
index = 0;
|
|
|
|
|
|
|
|
_toprows = []
|
|
|
|
for row in file :
|
|
|
|
for row in file :
|
|
|
|
|
|
|
|
row = row.replace('\r','')
|
|
|
|
|
|
|
|
if not segment and not row.startswith(section):
|
|
|
|
|
|
|
|
_toprows += [row]
|
|
|
|
if row.startswith(section) and not segment:
|
|
|
|
if row.startswith(section) and not segment:
|
|
|
|
|
|
|
|
|
|
|
|
segment = [row]
|
|
|
|
segment = [row]
|
|
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
elif segment and not row.startswith(section):
|
|
|
|
elif segment and not row.startswith(section):
|
|
|
|
|
|
|
|
|
|
|
|
segment.append(row)
|
|
|
|
segment.append(row)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(segment) > 1 and row.startswith(section):
|
|
|
|
if len(segment) > 1 and row.startswith(section):
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# process the segment somewhere (create a thread maybe?)
|
|
|
|
# process the segment somewhere (create a thread maybe?)
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# default_claim = dict({"index":index},**DEFAULT_VALUE)
|
|
|
|
# default_claim = dict({"index":index},**DEFAULT_VALUE)
|
|
|
|
|
|
|
|
# print (_toprows)
|
|
|
|
_claim = self.apply(segment,_code)
|
|
|
|
_claim = self.apply(segment,_code)
|
|
|
|
|
|
|
|
|
|
|
|
# if _claim['claim_id'] == 'P1080351470' :
|
|
|
|
# if _claim['claim_id'] == 'P1080351470' :
|
|
|
|
# print (_claim)
|
|
|
|
# print (_claim)
|
|
|
|
# _claim = dict(DEFAULT_VALUE,**_claim)
|
|
|
|
# _claim = dict(DEFAULT_VALUE,**_claim)
|
|
|
@ -425,12 +480,14 @@ class Parser (Process):
|
|
|
|
claim = self.apply(segment,_code)
|
|
|
|
claim = self.apply(segment,_code)
|
|
|
|
if claim :
|
|
|
|
if claim :
|
|
|
|
claim['index'] = len(claims)
|
|
|
|
claim['index'] = len(claims)
|
|
|
|
|
|
|
|
claim = jsonmerge.merge(claim,self.apply(_toprows,_code))
|
|
|
|
claims.append(dict(DEFAULT_VALUE,**claim))
|
|
|
|
claims.append(dict(DEFAULT_VALUE,**claim))
|
|
|
|
if type(file) != list :
|
|
|
|
if type(file) != list :
|
|
|
|
file.close()
|
|
|
|
file.close()
|
|
|
|
|
|
|
|
|
|
|
|
# x12_file = open(filename.strip(),errors='ignore').read().split('\n')
|
|
|
|
# x12_file = open(filename.strip(),errors='ignore').read().split('\n')
|
|
|
|
except Exception as e:
|
|
|
|
except Exception as e:
|
|
|
|
|
|
|
|
|
|
|
|
logs.append ({"parse":_code,"completed":False,"name":filename,"msg":e.args[0]})
|
|
|
|
logs.append ({"parse":_code,"completed":False,"name":filename,"msg":e.args[0]})
|
|
|
|
return [],logs,None
|
|
|
|
return [],logs,None
|
|
|
|
|
|
|
|
|
|
|
|