pyaccuwage/fields.py
Binh Van Nguyen 5781cbf335 Finished up most of the record order validation and also checking
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.
2011-05-07 15:19:48 -05:00

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]])