class SetupRule(AuditModel): ''' A rule that is part of a setup matrix. ''' # Database fields setupmatrix = models.ForeignKey( SetupMatrix, verbose_name=_('setup matrix'), related_name='rules' ) priority = models.IntegerField(_('priority')) fromsetup = models.CharField( _('from setup'), max_length=settings.NAMESIZE, blank=True, null=True, help_text=_("Name of the old setup (wildcard characters are supported)") ) tosetup = models.CharField( _('to setup'), max_length=settings.NAMESIZE, blank=True, null=True, help_text=_("Name of the new setup (wildcard characters are supported)") ) duration = DurationField( _('duration'), max_digits=settings.MAX_DIGITS, decimal_places=0, null=True, blank=True, help_text=_("Duration of the changeover") ) cost = models.DecimalField( _('cost'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("Cost of the conversion") ) def __str__(self): return "%s - %s" % (self.setupmatrix.name, self.priority) class Meta(AuditModel.Meta): ordering = ['priority'] db_table = 'setuprule' unique_together = (('setupmatrix', 'priority'),) verbose_name = _('setup matrix rule') verbose_name_plural = _('setup matrix rules')
def add_extra_model_fields(sender, **kwargs): model_path = "%s.%s" % (sender.__module__, sender.__name__) for field_name, label, fieldtype in _register.get(model_path, []): if fieldtype == 'string': field = models.CharField(label, max_length=300, null=True, blank=True, db_index=True) elif fieldtype == 'boolean': field = models.NullBooleanField(label, null=True, blank=True, db_index=True) elif fieldtype == 'number': field = models.DecimalField(label, max_digits=15, decimal_places=4, null=True, blank=True, db_index=True) elif fieldtype == 'integer': field = models.IntegerField(label, null=True, blank=True, db_index=True) elif fieldtype == 'date': field = models.DateField(label, null=True, blank=True, db_index=True) elif fieldtype == 'datetime': field = models.DateTimeField(label, null=True, blank=True, db_index=True) elif fieldtype == 'duration': field = DurationField(label, null=True, blank=True, db_index=True) elif fieldtype == 'time': field = models.TimeField(label, null=True, blank=True, db_index=True) else: raise ImproperlyConfigured("Invalid attribute type '%s'." % fieldtype) field.contribute_to_class(sender, field_name)
class Resource(AuditModel, HierarchyModel): # Types of resources types = ( ('default', _('Default')), ('infinite', _('Infinite')), ) # Database fields description = models.CharField(_('description'), max_length=settings.DESCRIPTIONSIZE, null=True, blank=True) category = models.CharField(_('category'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) subcategory = models.CharField(_('subcategory'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) type = models.CharField(_('type'), max_length=20, null=True, blank=True, choices=types, default='default') maximum = models.DecimalField(_('maximum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, default="1.00", null=True, blank=True, help_text=_('Size of the resource')) maximum_calendar = models.ForeignKey( Calendar, verbose_name=_('maximum calendar'), null=True, blank=True, help_text=_('Calendar defining the resource size varying over time')) location = models.ForeignKey(Location, verbose_name=_('location'), null=True, blank=True, db_index=True) cost = models.DecimalField( _('cost'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("Cost for using 1 unit of the resource for 1 hour")) maxearly = DurationField( _('max early'), max_digits=settings.MAX_DIGITS, decimal_places=0, null=True, blank=True, help_text= _('Time window before the ask date where we look for available capacity' )) setupmatrix = models.ForeignKey( SetupMatrix, verbose_name=_('setup matrix'), null=True, blank=True, db_index=True, help_text=_('Setup matrix defining the conversion time and cost')) setup = models.CharField( _('setup'), max_length=settings.NAMESIZE, null=True, blank=True, help_text=_('Setup of the resource at the start of the plan')) # Methods def __unicode__(self): return self.name def save(self, *args, **kwargs): if self.type == 'infinite': # These fields are not relevant for infinite resources self.maximum = None self.maximum_calendar_id = None self.maxearly = None # Call the real save() method super(Resource, self).save(*args, **kwargs) class Meta(AuditModel.Meta): db_table = 'resource' verbose_name = _('resource') verbose_name_plural = _('resources') ordering = ['name']
class Buffer(AuditModel, HierarchyModel): # Types of buffers types = ( ('default', _('Default')), ('infinite', _('Infinite')), ('procure', _('Procure')), ) # Fields common to all buffer types description = models.CharField(_('description'), max_length=settings.DESCRIPTIONSIZE, null=True, blank=True) category = models.CharField(_('category'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) subcategory = models.CharField(_('subcategory'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) type = models.CharField(_('type'), max_length=20, null=True, blank=True, choices=types, default='default') location = models.ForeignKey(Location, verbose_name=_('location'), null=True, blank=True, db_index=True) item = models.ForeignKey(Item, verbose_name=_('item'), db_index=True, null=True) onhand = models.DecimalField(_('onhand'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, default="0.00", null=True, blank=True, help_text=_('current inventory')) minimum = models.DecimalField(_('minimum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, default="0.00", null=True, blank=True, help_text=_('Safety stock')) minimum_calendar = models.ForeignKey( Calendar, verbose_name=_('minimum calendar'), null=True, blank=True, help_text=_('Calendar storing a time-dependent safety stock profile')) producing = models.ForeignKey( Operation, verbose_name=_('producing'), null=True, blank=True, related_name='used_producing', help_text=_('Operation to replenish the buffer')) carrying_cost = models.DecimalField( _('carrying cost'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text= _("Cost of holding inventory in this buffer, expressed as an annual percentage of the item price." )) # Extra fields for procurement buffers leadtime = DurationField( _('leadtime'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_('Leadtime for supplier of a procure buffer')) fence = DurationField( _('fence'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_('Frozen fence for creating new procurements')) min_inventory = models.DecimalField( _('min_inventory'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_( 'Inventory level that triggers replenishment of a procure buffer')) max_inventory = models.DecimalField( _('max_inventory'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_( 'Inventory level to which a procure buffer is replenished')) min_interval = DurationField( _('min_interval'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_( 'Minimum time interval between replenishments of a procure buffer') ) max_interval = DurationField( _('max_interval'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_( 'Maximum time interval between replenishments of a procure buffer') ) size_minimum = models.DecimalField( _('size_minimum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_('Minimum size of replenishments of a procure buffer')) size_multiple = models.DecimalField( _('size_multiple'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_( 'Replenishments of a procure buffer are a multiple of this quantity' )) size_maximum = models.DecimalField( _('size_maximum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_('Maximum size of replenishments of a procure buffer')) def __unicode__(self): return self.name def save(self, *args, **kwargs): if self.type == 'infinite' or self.type == 'procure': # Handle irrelevant fields for infinite and procure buffers self.producing = None if self.type != 'procure': # Handle irrelevant fields for non-procure buffers self.leadtime = None self.fence = None self.min_inventory = None self.max_inventory = None self.min_interval = None self.max_interval = None self.size_minimum = None self.size_multiple = None self.size_maximum = None super(Buffer, self).save(*args, **kwargs) class Meta(AuditModel.Meta): db_table = 'buffer' verbose_name = _('buffer') verbose_name_plural = _('buffers') ordering = ['name']
class Operation(AuditModel): # Types of operations types = ( ('fixed_time', _('fixed_time')), ('time_per', _('time_per')), ('routing', _('routing')), ('alternate', _('alternate')), ) # Database fields name = models.CharField(_('name'), max_length=settings.NAMESIZE, primary_key=True) type = models.CharField(_('type'), max_length=20, null=True, blank=True, choices=types, default='fixed_time') description = models.CharField(_('description'), max_length=settings.DESCRIPTIONSIZE, null=True, blank=True) category = models.CharField(_('category'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) subcategory = models.CharField(_('subcategory'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True) location = models.ForeignKey(Location, verbose_name=_('location'), null=True, blank=True, db_index=True) fence = DurationField( _('release fence'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text= _("Operationplans within this time window from the current day are expected to be released to production ERP" )) pretime = DurationField( _('pre-op time'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text= _("A delay time to be respected as a soft constraint before starting the operation" )) posttime = DurationField( _('post-op time'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text= _("A delay time to be respected as a soft constraint after ending the operation" )) sizeminimum = models.DecimalField( _('size minimum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, default='1.0', help_text=_("A minimum quantity for operationplans")) sizemultiple = models.DecimalField( _('size multiple'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("A multiple quantity for operationplans")) sizemaximum = models.DecimalField( _('size maximum'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("A maximum quantity for operationplans")) cost = models.DecimalField(_('cost'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("Cost per operationplan unit")) duration = DurationField(_('duration'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("A fixed duration for the operation")) duration_per = DurationField( _('duration per unit'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, null=True, blank=True, help_text=_("A variable duration for the operation")) search = models.CharField( _('search mode'), max_length=20, null=True, blank=True, choices=searchmode, help_text=_('Method to select preferred alternate')) def __unicode__(self): return self.name def save(self, *args, **kwargs): if self.type is None or self.type == '' or self.type == 'fixed_time': self.duration_per = None self.search = None elif self.type == 'alternate': self.duration = None self.duration_per = None elif self.type != 'time_per': self.duration = None self.duration_per = None self.search = None # Call the real save() method super(Operation, self).save(*args, **kwargs) class Meta(AuditModel.Meta): db_table = 'operation' verbose_name = _('operation') verbose_name_plural = _('operations') ordering = ['name']
class Demand(AuditModel, HierarchyModel): # The priorities defined here are for convenience only. FrePPLe accepts any number as priority. demandpriorities = ( (1, '1'), (2, '2'), (3, '3'), (4, '4'), (5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'), (10, '10'), (11, '11'), (12, '12'), (13, '13'), (14, '14'), (15, '15'), (16, '16'), (17, '17'), (18, '18'), (19, '19'), (20, '20') ) # Status demandstatus = ( ('inquiry', _('Inquiry')), ('quote', _('Quote')), ('open', _('Open')), ('closed', _('Closed')), ('canceled', _('Canceled')), ) # Database fields description = models.CharField( _('description'), max_length=settings.DESCRIPTIONSIZE, null=True, blank=True ) category = models.CharField( _('category'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True ) subcategory = models.CharField( _('subcategory'), max_length=settings.CATEGORYSIZE, null=True, blank=True, db_index=True ) customer = models.ForeignKey( Customer, verbose_name=_('customer'), null=True, blank=True, db_index=True ) item = models.ForeignKey( Item, verbose_name=_('item'), null=True, blank=True, db_index=True ) due = models.DateTimeField(_('due'), help_text=_('Due date of the demand')) status = models.CharField( _('status'), max_length=10, null=True, blank=True, choices=demandstatus, default='open', help_text=_('Status of the demand. Only "open" demands are planned'), ) operation = models.ForeignKey( Operation, verbose_name=_('delivery operation'), null=True, blank=True, related_name='used_demand', help_text=_('Operation used to satisfy this demand') ) quantity = models.DecimalField( _('quantity'), max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES ) priority = models.PositiveIntegerField( _('priority'), default=10, choices=demandpriorities, help_text=_('Priority of the demand (lower numbers indicate more important demands)') ) minshipment = models.DecimalField( _('minimum shipment'), null=True, blank=True, max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, help_text=_('Minimum shipment quantity when planning this demand') ) maxlateness = DurationField( _('maximum lateness'), null=True, blank=True, max_digits=settings.MAX_DIGITS, decimal_places=settings.DECIMAL_PLACES, help_text=_("Maximum lateness allowed when planning this demand") ) # Convenience methods def __str__(self): return self.name class Meta(AuditModel.Meta): db_table = 'demand' verbose_name = _('demand') verbose_name_plural = _('demands') ordering = ['name']
class ItemDistribution(AuditModel): # Database fields id = models.AutoField(_('identifier'), primary_key=True) item = models.ForeignKey( Item, verbose_name=_('item'), db_index=True, related_name='distributions' ) location = models.ForeignKey( Location, verbose_name=_('location'), null=True, blank=True, db_index=True, related_name='itemdistributions_destination' ) origin = models.ForeignKey( Location, verbose_name=_('origin'), db_index=True, related_name='itemdistributions_origin' ) leadtime = DurationField( _('lead time'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_('lead time') ) sizeminimum = models.DecimalField( _('size minimum'), max_digits=15, decimal_places=4, null=True, blank=True, default='1.0', help_text=_("A minimum shipping quantity") ) sizemultiple = models.DecimalField( _('size multiple'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A multiple shipping quantity") ) cost = models.DecimalField( _('cost'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("Shipping cost per unit") ) priority = models.IntegerField( _('priority'), default=1, null=True, blank=True, help_text=_('Priority among all alternates') ) effective_start = models.DateTimeField( _('effective start'), null=True, blank=True, help_text=_('Validity start date') ) effective_end = models.DateTimeField( _('effective end'), null=True, blank=True, help_text=_('Validity end date') ) resource = models.ForeignKey( Resource, verbose_name=_('resource'), null=True, blank=True, db_index=True, related_name='itemdistributions', help_text=_("Resource to model the distribution capacity") ) resource_qty = models.DecimalField( _('resource quantity'), null=True, blank=True, max_digits=15, decimal_places=4, default='1.0', help_text=_("Resource capacity consumed per distributed unit") ) fence = DurationField( _('fence'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_('Frozen fence for creating new shipments') ) def __str__(self): return '%s - %s - %s' % ( self.location.name if self.location else 'Any destination', self.item.name if self.item else 'No item', self.origin.name if self.origin else 'No origin' ) class Meta(AuditModel.Meta): db_table = 'itemdistribution' unique_together = (('item', 'location', 'origin', 'effective_start'),) verbose_name = _('item distribution') verbose_name_plural = _('item distributions')
class Operation(AuditModel): # Types of operations types = ( ('fixed_time', _('fixed_time')), ('time_per', _('time_per')), ('routing', _('routing')), ('alternate', _('alternate')), ('split', _('split')), ) # Database fields #. Translators: Translation included with Django name = models.CharField(_('name'), max_length=300, primary_key=True) type = models.CharField(_('type'), max_length=20, null=True, blank=True, choices=types, default='fixed_time') description = models.CharField(_('description'), max_length=500, null=True, blank=True) category = models.CharField(_('category'), max_length=300, null=True, blank=True, db_index=True) subcategory = models.CharField(_('subcategory'), max_length=300, null=True, blank=True, db_index=True) location = models.ForeignKey( Location, verbose_name=_('location'), null=True, blank=True, db_index=True ) fence = DurationField( _('release fence'), max_digits=15, decimal_places=4, null=True, blank=True, help_text=_("Operationplans within this time window from the current day are expected to be released to production ERP") ) posttime = DurationField( _('post-op time'), max_digits=15, decimal_places=4, null=True, blank=True, help_text=_("A delay time to be respected as a soft constraint after ending the operation") ) sizeminimum = models.DecimalField( _('size minimum'), max_digits=15, decimal_places=4, null=True, blank=True, default='1.0', help_text=_("A minimum quantity for operationplans") ) sizemultiple = models.DecimalField( _('size multiple'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A multiple quantity for operationplans") ) sizemaximum = models.DecimalField( _('size maximum'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A maximum quantity for operationplans") ) cost = models.DecimalField( _('cost'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("Cost per operationplan unit") ) duration = DurationField( _('duration'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A fixed duration for the operation") ) duration_per = DurationField( _('duration per unit'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A variable duration for the operation") ) search = models.CharField( _('search mode'), max_length=20, null=True, blank=True, choices=searchmode, help_text=_('Method to select preferred alternate') ) def __str__(self): return self.name def save(self, *args, **kwargs): # Reset fields that are not used for specific operation types if self.type != 'time_per': self.duration_per = None if self.type != 'alternate': self.search = None if self.type is not None and self.type not in ['time_per', 'fixed_time', '']: self.duration = None # Call the real save() method super(Operation, self).save(*args, **kwargs) class Meta(AuditModel.Meta): db_table = 'operation' verbose_name = _('operation') verbose_name_plural = _('operations') ordering = ['name']
class ItemSupplier(AuditModel): # Database fields id = models.AutoField(_('identifier'), primary_key=True) item = models.ForeignKey(Item, verbose_name=_('item'), db_index=True, related_name='itemsuppliers') location = models.ForeignKey(Location, verbose_name=_('location'), null=True, blank=True, db_index=True, related_name='itemsuppliers') supplier = models.ForeignKey(Supplier, verbose_name=_('supplier'), db_index=True, related_name='suppliers') leadtime = DurationField(_('lead time'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_('Purchasing lead time')) sizeminimum = models.DecimalField( _('size minimum'), max_digits=15, decimal_places=4, null=True, blank=True, default='1.0', help_text=_("A minimum purchasing quantity")) sizemultiple = models.DecimalField( _('size multiple'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("A multiple purchasing quantity")) cost = models.DecimalField(_('cost'), null=True, blank=True, max_digits=15, decimal_places=4, help_text=_("Purchasing cost per unit")) priority = models.IntegerField( _('priority'), default=1, null=True, blank=True, help_text=_('Priority among all alternates')) effective_start = models.DateTimeField(_('effective start'), null=True, blank=True, help_text=_('Validity start date')) effective_end = models.DateTimeField(_('effective end'), null=True, blank=True, help_text=_('Validity end date')) def __str__(self): return '%s - %s - %s' % ( self.supplier.name if self.supplier else 'No supplier', self.item.name if self.item else 'No item', self.location.name if self.location else 'Any location') class Meta(AuditModel.Meta): db_table = 'itemsupplier' unique_together = (('item', 'location', 'supplier', 'effective_start'), ) verbose_name = _('item supplier') verbose_name_plural = _('item suppliers')