Skip to content

Commit fbb8fa3

Browse files
theangryangelBlommaertsEdwin
authored andcommitted
WIP
1 parent 9fa2004 commit fbb8fa3

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed

wip.py

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
from typing import Callable, List, Optional, Tuple, Union
2+
3+
4+
from pydifact.segmentcollection import Interchange
5+
from pydifact.segments import Segment, SegmentProvider
6+
7+
8+
9+
interchange = Interchange.from_str("""UNA:+.?*'
10+
UNB+UNOA:4+5021376940009:14+1111111111111:14+200421:1000+0001+ORDERS'
11+
UNH+1+ORDERS:D:01B:UN:EAN010'
12+
BGM+220+123456+9'
13+
DTM+137:20150410:102'
14+
DTM+2:20150710:102'
15+
FTX+DIN+++DELIVERY INSTRUCTIONS DESCRIPTION'
16+
NAD+BY+5021376940009::9'
17+
NAD+SU+1111111111111::9'
18+
RFF+IA:123456'
19+
NAD+ST+++Mr John Smith+The Bungalow:Hastings Road+Preston+:::Lancashire+SW1A 1AA'
20+
CTA+LB+:Mr John Smith'
21+
COM+01772 999999:TE'
22+
COM+johnsmith@gmail.com:EM'
23+
CUX+2:GBP:9'
24+
TDT+20+++++SD'
25+
LIN+1++121354654:BP'
26+
IMD+F++:::TPRG item description'
27+
QTY+21:2'
28+
MOA+203:200.00'
29+
PRI+AAA:100.00'
30+
RFF+LI:1'
31+
LIN+1++121354654:BP'
32+
IMD+F++:::TPRG item description'
33+
QTY+21:2'
34+
MOA+203:200.00'
35+
PRI+AAA:100.00'
36+
RFF+LI:1'
37+
UNS+S'
38+
CNT+2:1'
39+
UNT+32+1'
40+
UNZ+1+0001'""")
41+
42+
import itertools
43+
import collections
44+
45+
46+
class BiDirectionalIterator(object):
47+
def __init__(self, collection):
48+
self.collection = collection
49+
self.index = 0
50+
51+
def next(self):
52+
try:
53+
result = self.collection[self.index]
54+
self.index += 1
55+
except IndexError:
56+
raise StopIteration
57+
return result
58+
59+
def prev(self):
60+
self.index -= 1
61+
if self.index < 0:
62+
raise StopIteration
63+
return self.collection[self.index]
64+
65+
def __iter__(self):
66+
return self
67+
68+
69+
class AbstractComponent:
70+
"""Abstract EDIFact Component, used as a base for Components, SegmentGroup, SegmentLoop"""
71+
def __init__(self, **kwargs):
72+
self.mandatory = kwargs.get("mandatory", False)
73+
74+
def _from_segment_iter(self, messages):
75+
raise NotImplementedError()
76+
77+
78+
class Component(AbstractComponent, Segment):
79+
"""
80+
EDIFact Component.
81+
A simple wrapper for Segment
82+
"""
83+
def __init__(
84+
self,
85+
tag: str,
86+
*elements,
87+
**kwargs
88+
):
89+
AbstractComponent.__init__(self, **kwargs)
90+
Segment.__init__(self, tag, *elements)
91+
92+
def _from_segment_iter(self, iterator):
93+
segment = iterator.next()
94+
95+
if self.tag == segment.tag:
96+
self.elements = segment.elements
97+
return
98+
99+
if self.mandatory:
100+
raise Exception("Missing %s, found %s" % (self.tag, segment))
101+
102+
iterator.prev()
103+
104+
105+
class SegmentGroupMetaClass(type):
106+
"""
107+
Metaclass to maintain an ordered list of components.
108+
Required for compatibility with Python 3.5. In 3.6 the
109+
properties of a class are strictly ordered.
110+
"""
111+
@classmethod
112+
def __prepare__(cls, name, bases):
113+
return collections.OrderedDict()
114+
115+
def __new__(cls, name, bases, classdict):
116+
result = type.__new__(cls, name, bases, dict(classdict))
117+
exclude = set(dir(type))
118+
119+
result.__components__ = []
120+
121+
for k, v in classdict.items():
122+
if k not in exclude and isinstance(v, AbstractComponent):
123+
result.__components__.append(k)
124+
return result
125+
126+
127+
class SegmentGroup(AbstractComponent, metaclass=SegmentGroupMetaClass):
128+
"""
129+
Describes a static group of Components
130+
"""
131+
def _from_segment_iter(self, isegment):
132+
i = 0
133+
134+
icomponent = iter(self.__components__)
135+
136+
try:
137+
while True:
138+
component_name = next(icomponent)
139+
component = getattr(self, component_name)
140+
component._from_segment_iter(isegment)
141+
except StopIteration:
142+
pass
143+
144+
def from_message(self, message):
145+
imessage = BiDirectionalIterator(message.segments)
146+
self._from_segment_iter(imessage)
147+
148+
def to_message(self):
149+
raise NotImplementedError()
150+
151+
def __str__(self):
152+
res = []
153+
for component_name in iter(self.__components__):
154+
component = getattr(self, component_name)
155+
res.append(str(component))
156+
return "\n".join(res)
157+
158+
159+
class SegmentLoop(AbstractComponent):
160+
"""
161+
Describes a repeating SegmentGroup
162+
"""
163+
def __init__(self, component, **kwargs):
164+
super(SegmentLoop, self).__init__(**kwargs)
165+
self.min = kwargs.get("min", 0)
166+
self.max = kwargs.get("max", 0)
167+
168+
if self.mandatory and self.min < 1:
169+
self.min = 1
170+
171+
if self.max < self.min:
172+
self.max = self.min
173+
174+
self.__component__ = component
175+
self.value = []
176+
177+
def _from_segment_iter(self, isegment):
178+
i = 0
179+
while i < self.max:
180+
181+
try:
182+
component = self.__component__()
183+
component._from_segment_iter(isegment)
184+
self.value.append(component)
185+
except BaseException:
186+
isegment.prev()
187+
if self.mandatory and i < self.min:
188+
raise Exception("Missing %s" %
189+
(self.__component__.__name__))
190+
break
191+
192+
i += 1
193+
194+
if i < self.min:
195+
raise Exception("minimum required not met")
196+
197+
def __str__(self):
198+
res = []
199+
for v in self.value:
200+
res.append(str(v))
201+
return "{} = {}".format(
202+
self.__component__.__name__,
203+
str(res)
204+
)
205+
206+
207+
class OrderLine(SegmentGroup):
208+
line_id = Component("LIN", mandatory=True)
209+
description = Component("IMD", mandatory=True)
210+
quantity = Component("QTY", mandatory=True)
211+
moa = Component("MOA")
212+
pri = Component("PRI")
213+
rff = Component("RFF", mandatory=True)
214+
215+
216+
217+
218+
class Order(SegmentGroup):
219+
purchase_order_id = Component("BGM", mandatory=True)
220+
date = Component("DTM", mandatory=True)
221+
delivery_date = Component("DTM", mandatory=True)
222+
delivery_instructions = Component("FTX", mandatory=True)
223+
supplier_id_gln = Component("NAD", mandatory=True)
224+
supplier_id_tprg = Component("NAD", mandatory=True)
225+
ref = Component("RFF", mandatory=True)
226+
ship_to = Component("NAD", mandatory=True)
227+
228+
ship_to_contact = Component("CTA", mandatory=True)
229+
ship_to_phone = Component("COM", mandatory=True)
230+
ship_to_email = Component("COM", mandatory=True)
231+
cux = Component("CUX", mandatory=True)
232+
tdt = Component("TDT", mandatory=True)
233+
234+
lines = SegmentLoop(
235+
OrderLine,
236+
max=99,
237+
mandatory=True
238+
)
239+
240+
uns = Component("UNS", mandatory=True)
241+
cnt = Component("CNT", mandatory=True)
242+
243+
244+
TYPE_TO_PARSER_DICT = {
245+
"ORDERS": Order
246+
}
247+
248+
249+
for message in interchange.get_messages():
250+
cls = TYPE_TO_PARSER_DICT.get(message.type)
251+
if not cls:
252+
raise NotImplementedError("Unsupported message type '{}'".format(message.type))
253+
254+
obj = cls()
255+
obj.from_message(message)
256+
print(str(obj))

0 commit comments

Comments
 (0)