Package Camelot :: Package camelot :: Package model :: Module type_and_status |
[frames] | no frames]

# Source Code for Module Camelot.camelot.model.type_and_status

      1  '''
      2
      3  Created on Sep 25, 2009
      4
      5  @author: Erik De Rijcke
      6
      7  '''
      8  import datetime
      9
     10  from elixir.entity import Entity, EntityMeta
     11
     12  from sqlalchemy.types import Date, Unicode
     13  from sqlalchemy.sql import and_
     14
     15  from elixir.fields import Field
     16  from elixir.options import using_options
     17  from elixir.relationships import ManyToOne, OneToMany
     18
     19  from camelot.model.authentication import end_of_times
     20  from camelot.view.elixir_admin import EntityAdmin
     21  from camelot.types import Code, Enumeration
     22
     23  #
     24  # Global dict keeping track of which status class is used for which class
     25  #
     26  __status_classes__ = {}
     27
     28 -def get_status_class(cls_name):
     29      """
     30      :param cls_name: an Entity class name
     31      :return: the status class used for this entity
     32      """
     33      return __status_classes__[cls_name]
     34
     35 -def create_type_3_status_mixin(status_attribute):
     36      """Create a class that can be subclassed to provide a class that
     37      has a type 3 status with methods to manipulate and review its status
     38      :param status_attribute: the name of the type 3 status attribute
     39      """
     40
     41      class Type3StatusMixin(object):
     42
     43          @property
     44          def current_status(self):
     45              classified_by = None
     46              today = datetime.date.today()
     47              for status_history in self.status:
     48                  if status_history.status_from_date<=today and status_history.status_thru_date>=today:
     49                      classified_by = status_history.classified_by
     50              return classified_by
     51
     52          def change_status(self, new_status, status_from_date=None, status_thru_date=end_of_times()):
     53              from sqlalchemy import orm
     54              if not status_from_date:
     55                  status_from_date = datetime.date.today()
     56              mapper = orm.class_mapper(self.__class__)
     57              status_property = mapper.get_property('status')
     58              status_type = status_property._get_target().class_
     59              old_status = status_type.query.filter( and_( status_type.status_for == self,
     60                                                           status_type.status_from_date <= status_from_date,
     61                                                           status_type.status_thru_date >= status_from_date ) ).first()
     62              if old_status != None:
     63                  old_status.thru_date = datetime.date.today() - datetime.timedelta( days = 1 )
     64                  old_status.status_thru_date = status_from_date - datetime.timedelta( days = 1 )
     65              new_status = status_type(    status_for = self,
     66                                           classified_by = new_status,
     67                                           status_from_date = status_from_date,
     68                                           status_thru_date = status_thru_date,
     69                                           from_date = datetime.date.today(),
     70                                           thru_date = end_of_times() )
     71              if old_status:
     72                  self.query.session.flush( [old_status] )
     73              self.query.session.flush( [new_status] )
     74
     75      return Type3StatusMixin
     76
     77 -def type_3_status( statusable_entity, metadata, collection, verbose_entity_name = None, enumeration=None ):
     78      '''
     79      Creates a new type 3 status related to the given entity
     80      :statusable_entity: A string referring to an entity.
     81      :enumeration: if this parameter is used, no status type Entity is created, but the status type is
     82      described by the enumeration.
     83      '''
     84      t3_status_name = statusable_entity + '_status'
     85      t3_status_type_name = statusable_entity + '_status_type'
     86
     87
     88      if not enumeration:
     89
     90          class Type3StatusTypeMeta( EntityMeta ):
     91              def __new__( cls, classname, bases, dictionary ):
     92                  return EntityMeta.__new__( cls, t3_status_type_name,
     93                                       bases, dictionary )
     94              def __init__( self, classname, bases, dictionary ):
     95                  EntityMeta.__init__( self, t3_status_type_name,
     96                                        bases, dictionary )
     97
     98          class Type3StatusType( Entity, ):
     99              using_options( tablename = t3_status_type_name.lower(), metadata=metadata, collection=collection )
    100              __metaclass__ = Type3StatusTypeMeta
    101
    102              code = Field( Code( parts = ['>AAAA'] ), index = True,
    103                                 required = True, unique = True )
    104              description = Field( Unicode( 40 ), index = True )
    105
    106              def __unicode__( self ):
    107                  return 'Status type: %s : %s' % ( '.'.join( self.code ), self.description )
    108
    109              class Admin( EntityAdmin ):
    110                  list_display = ['code', 'description']
    111                  verbose_name = statusable_entity + ' Status Type'
    112                  if verbose_entity_name is not None:
    113                      verbose_name = verbose_entity_name + ' Status Type'
    114
    115      class Type3StatusMeta( EntityMeta ):
    116          def __new__( cls, classname, bases, dictionary ):
    117              return EntityMeta.__new__( cls, t3_status_name,
    118                                         bases, dictionary )
    119          def __init__( self, classname, bases, dictionary ):
    120              EntityMeta.__init__( self, t3_status_name,
    121                                   bases, dictionary )
    122
    123      class Type3Status( Entity, ):
    124          """
    125          Status Pattern
    126          .. attribute:: status_datetime For statuses that occur at a specific point in time
    127          .. attribute:: status_from_date For statuses that require a date range
    128          .. attribute:: from_date When a status was enacted or set
    129          """
    130          using_options( tablename = t3_status_name.lower(), metadata=metadata, collection=collection )
    131          __metaclass__ = Type3StatusMeta
    132
    133          status_datetime = Field( Date, required = False )
    134          status_from_date = Field( Date, required = False )
    135          status_thru_date = Field( Date, required = False )
    136          from_date = Field( Date, required = True, default = datetime.date.today )
    137          thru_date = Field( Date, required = True, default = end_of_times )
    138
    139          status_for = ManyToOne( statusable_entity, #required = True,
    140                                   ondelete = 'cascade', onupdate = 'cascade' )
    141
    142          if not enumeration:
    143              classified_by = ManyToOne( t3_status_type_name, required = True,
    144                                         ondelete = 'cascade', onupdate = 'cascade' )
    145          else:
    146              classified_by = Field(Enumeration(enumeration), required=True, index=True)
    147
    148          class Admin( EntityAdmin ):
    149              verbose_name = statusable_entity + ' Status'
    150              verbose_name_plural = statusable_entity + ' Statuses'
    151              list_display = ['status_from_date', 'status_thru_date', 'classified_by']
    152              verbose_name = statusable_entity + ' Status'
    153              if verbose_entity_name is not None:
    154                  verbose_name = verbose_entity_name + ' Status'
    155
    156          def __unicode__( self ):
    157              return u'Status'
    158
    159      __status_classes__[statusable_entity] = Type3Status
    160
    161      return t3_status_name
    162
    163 -def entity_type( typable_entity, metadata, collection, verbose_entity_name = None ):
    164      '''
    165      Creates a new type related to the given entity.
    166      .. typeable_entity:: A string referring to an entity.
    167      '''
    168      type_name = typable_entity + '_type'
    169
    170      class TypeMeta( EntityMeta ):
    171          def __new__( cls, classname, bases, dictionary ):
    172              return EntityMeta.__new__( cls, type_name,
    173                                         bases, dictionary )
    174          def __init__( self, classname, bases, dictionary ):
    175              EntityMeta.__init__( self, type_name,
    176                                   bases, dictionary )
    177
    178      class Type( Entity ):
    179          using_options( tablename = type_name.lower(), metadata=metadata, collection=collection )
    180          __metaclass__ = TypeMeta
    181
    182          type_description_for = OneToMany( typable_entity )
    183          description = Field( Unicode( 48 ), required = True )
    184
    185          class Admin( EntityAdmin ):
    186              verbose_name = typable_entity + ' Type'
    187              list_display = ['description', ]
    188              verbose_name = typable_entity + ' Type'
    189              if verbose_entity_name is not None:
    190                  verbose_name = verbose_entity_name + ' Type'
    191
    192          def __unicode__( self ):
    193              return u'Type: %s' % ( self.description )
    194
    195      return type_name
    196