for all required records in a set. Added a controller class but decided to put stuff in __init__ instead, at least for now. Added a DateField which converts datetime.date into the proper string format for EFW2 files (hopefully), this should still be tested next week.
143 lines
4.1 KiB
Python
143 lines
4.1 KiB
Python
import decimal, datetime
|
|
|
|
class ValidationError(Exception):
|
|
pass
|
|
|
|
class Field(object):
|
|
creation_counter = 0
|
|
|
|
def __init__(self, name=None, max_length=0, required=True, uppercase=True):
|
|
self.name = name
|
|
self._value = None
|
|
self.max_length = max_length
|
|
self.required = required
|
|
self.uppercase = uppercase
|
|
self.creation_counter = Field.creation_counter
|
|
Field.creation_counter += 1
|
|
|
|
def validate(self):
|
|
raise NotImplemented
|
|
|
|
def get_data(self):
|
|
raise NotImplemented
|
|
|
|
def __setvalue(self, value):
|
|
self._value = value
|
|
|
|
def __getvalue(self):
|
|
return self._value
|
|
|
|
value = property(__getvalue, __setvalue)
|
|
|
|
def read(self, fp):
|
|
if fp.tell() + self.max_length <= fp.len:
|
|
data = fp.read(self.max_length)
|
|
return self.parse(data)
|
|
return None
|
|
|
|
def parse(self, s):
|
|
self.value = s.strip()
|
|
|
|
|
|
class TextField(Field):
|
|
def validate(self):
|
|
if self.value == None and self.required:
|
|
raise ValidationError("value required")
|
|
if len(self.value) > self.max_length:
|
|
raise ValidationError("value is too long")
|
|
|
|
def get_data(self):
|
|
value = self.value or ""
|
|
if self.uppercase:
|
|
value = value.upper()
|
|
return value.ljust(self.max_length).encode('ascii')
|
|
|
|
|
|
class StateField(TextField):
|
|
def __init__(self, name=None, required=True):
|
|
return super(StateField, self).__init__(name=name, max_length=2, required=required)
|
|
|
|
|
|
class EmailField(TextField):
|
|
def __init__(self, name=None, required=True, max_length=None):
|
|
return super(EmailField, self).__init__(name=name, max_length=max_length,
|
|
required=required, uppercase=False)
|
|
|
|
class NumericField(TextField):
|
|
def validate(self):
|
|
super(NumericField, self).validate()
|
|
try:
|
|
int(self.value)
|
|
except ValueError:
|
|
raise ValidationError("field contains non-numeric characters")
|
|
|
|
def get_data(self):
|
|
value = self.value or ""
|
|
return value.zfill(self.max_length)
|
|
|
|
def parse(self, s):
|
|
self.value = int(s)
|
|
|
|
|
|
class StaticField(TextField):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(StaticField, self).__init__(name=name, required=required,
|
|
max_length=len(value))
|
|
self._value = value
|
|
|
|
def parse(self, s):
|
|
pass
|
|
|
|
class BlankField(TextField):
|
|
def get_data(self):
|
|
return " " * self.max_length
|
|
|
|
def parse(self, s):
|
|
pass
|
|
|
|
class BooleanField(Field):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(BooleanField, self).__init__(name=name, required=required, max_length=1)
|
|
self._value = value
|
|
|
|
def validate(self):
|
|
pass
|
|
|
|
def get_data(self):
|
|
return '1' if self._value else '0'
|
|
|
|
def parse(self, s):
|
|
self.value = (s == '1')
|
|
|
|
class MoneyField(Field):
|
|
def validate(self):
|
|
if self.value == None and self.required:
|
|
raise ValidationError("value required")
|
|
if len(str(int((self.value or 0)*100))) > self.max_length:
|
|
raise ValidationError("value is too long")
|
|
|
|
def get_data(self):
|
|
return str(int((self.value or 0)*100)).encode('ascii').zfill(self.max_length)
|
|
|
|
def parse(self, s):
|
|
self.value = decimal.Decimal(s) * decimal.Decimal('0.01')
|
|
|
|
class DateField(TextField):
|
|
def __init__(self, name=None, required=True, value=None):
|
|
super(TextField, self).__init__(name=name, required=required, max_length=8)
|
|
if isinstance(value, datetime.date):
|
|
self._value = value
|
|
elif value:
|
|
self._value = datetime.date(*[int(x) for x in value[4:8], value[0:2], value[2:4]])
|
|
else:
|
|
self._value = None
|
|
|
|
def get_data(self):
|
|
if self._value:
|
|
return self._value.strftime('%m%d%Y')
|
|
return '0' * self.max_length
|
|
|
|
def parse(self, s):
|
|
self.value = datetime.date(*[int(x) for x in s[4:8], s[0:2], s[2:4]])
|
|
|
|
|