class Roller(Appliance): state = FSMField(default="closed", protected=True) class Meta: verbose_name = "Roller" verbose_name_plural = "Rollers" def __str__(self): return f"<Roller {self.mqtt_topic}>" @transition(field=state, source="closed", target="requestOpen") def open(self): return @transition(field=state, source="requestOpen", target="opened") def opened(self): return @transition(field=state, source="opened", target="requestClose") def close(self): return @transition(field=state, source="requestClose", target="closed") def closed(self): return def mqtt_message(self, topic, payload): """ Handle the mqtt message passed from the room """ payload = payload.lower().strip() if payload not in ("opened", "closed", "open", "close"): return method = getattr(self, payload) if can_proceed(method): method() self.save() logger.info(f"Roller {self.mqtt_topic}: {self.state}") else: logger.warning( f"Roller {self.mqtt_topic} can't '{payload}', current state is {self.state}" )
class ObjectPermissionTestModel(models.Model): state = FSMField(default="new") @transition(field=state, source='new', target='published', on_error='failed', permission='testapp.can_publish_objectpermissiontestmodel') def publish(self): pass class Meta: app_label = 'testapp' permissions = [ ('can_publish_objectpermissiontestmodel', 'Can publish ObjectPermissionTestModel'), ]
class AllUrl(models.Model): source = models.ForeignKey( Source, related_name='urls', related_query_name='url', on_delete=models.CASCADE ) url = models.URLField() state = FSMField(default=AllUrlStates.PENDING.value, db_index=True) is_article = models.BooleanField(default=True) @transition( field=state, source='*', target=AllUrlStates.PROCESSED.value ) def processed(self): pass
class Post(models.Model): state = FSMField(default='new') post_text = models.TextField() title = models.CharField(max_length=200) content = models.TextField() pub_date = models.DateTimeField('date published') @transition(field=state, source='*', target='published') def publish(self): self.state = 'published' self.save() @transition(field=state, source='published', target='unpublished') def unpublish(self): self.state = 'unpublished' self.save()
class NormalFSM(models.Model): state = FSMField(default='a') @transition(field=state, source='a', target='b') def a_to_b(self): pass @transition(field=state, source='b', target='c') def b_to_c(self): pass @transition(field=state, source='a', target='c') def a_to_c(self): pass @transition(field=state, source='c', target='d', custom={'viewset': False}) def c_to_d(self): pass
class Book(models.Model): LOW_RATING, HIGH_RATING = 0, 1 BLOG_RATING_CHOICES = ((LOW_RATING, 'low'), (HIGH_RATING, 'high')) PLANNING, WRITING, PUBLISHED = 'planning', 'writing', 'publishing' STATUS_CHOICES = (PLANNING, WRITING, PUBLISHED) title = models.CharField(max_length=20, null=True, blank=True) status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=PLANNING) publishing_url = models.URLField(null=True) blog_rating = models.BigIntegerField(null=True, choices=BLOG_RATING_CHOICES) github_stars = models.PositiveIntegerField(null=True) amazon_rating = models.FloatField(null=True) current_price = models.DecimalField(null=True, decimal_places=4) written = models.DateField(null=True) published_at = models.DateTimeField(null=True) author = models.ForeignKey(Author, related_name='books', on_delete=models.CASCADE, null=True) INT_CHOICES = Choices( (1, 'one', 'I'), (2, 'two', 'II'), ) int_choice_field = models.IntegerField(choices=INT_CHOICES, default=INT_CHOICES.one) STR_CHOICES = Choices( ('one', 'I'), ('two', 'II'), ) str_choice_field = models.CharField(max_length=5, choices=STR_CHOICES, default=STR_CHOICES.one) fsm_field = FSMField(default=STR_CHOICES.one, choices=STR_CHOICES, null=True)
class Volunteer(TrackedModel): first_name = models.TextField() last_name = models.TextField() phone = PhoneNumberField() email = models.TextField() address_line_one = models.TextField() address_line_two = models.TextField(null=True, blank=True) city = models.TextField() state = models.TextField() zip = models.TextField() neighborhood = models.ForeignKey("Neighborhood", on_delete=models.CASCADE) status = FSMField(default="waiting_for_review") def __str__(self): return f"{self.first_name} {self.last_name} - {self.neighborhood}" class Meta: ordering = ["id"] unique_together = ["phone", "email"] @transition( field=status, source="waiting_for_review", target="approved", custom=dict(button_name="Approve"), ) def approve(self): """ This function may contain side-effects, like updating caches, notifying users, etc. The return value will be discarded. """ @transition( field=status, source="waiting_for_review", target="denied", custom=dict(button_name="Deny"), ) def deny(self): """
class Article(models.Model): STATES = ( ('draft', 'Draft'), ('submitted', 'Article submitted'), ('published', 'Article published'), ('deleted', 'Article deleted'), ) state = FSMField(choices=STATES, default='draft', protected=True) @fsm_log_by @fsm_log_description @transition(field=state, source='draft', target='submitted') def submit(self, description=None, by=None): pass @fsm_log_by @transition(field=state, source='submitted', target='draft') def request_changes(self, by=None): pass @fsm_log_by @transition(field=state, source='submitted', target='published') def publish(self, by=None): pass @fsm_log_by @transition(field=state, source='*', target='deleted') def delete(self, using=None): pass @fsm_log_by @fsm_log_description(allow_inline=True) @transition(field=state, source='draft', target='submitted') def submit_inline_description_change(self, change_to, description=None, by=None): description.set(change_to) @fsm_log_by @transition(field=state, source='draft', target=None) def validate_draft(self, by=None): pass
class SiteEnquiry(PartyManagementServiceBaseModel): email = models.EmailField('Enquirer Email', null=True, blank=True) phone = models.CharField('Enquirer Phone', default=0, blank=True, max_length=100) business_name = models.CharField('Business Name', null=True, blank=True, max_length=200) enquiry_message = models.CharField('Enquiry', max_length=3000, null=True, blank=True) enquiry_status = FSMField(protected=True, default='Pending') enquiry_response = models.CharField('Enquiry response', max_length=3000, null=True, blank=True) def __str__(self): return self.name+"'s Enquiry" @transition(field=enquiry_status, source='Pending', target='Responded') def despatch_response(self, response_message): self.enquiry_response = response_message class Meta: ordering = ['-creation_date'] verbose_name = 'Site Enquiry' verbose_name_plural = 'Site Enquiries'
class State(TimeStampedModel, ChangedByMixin): """ Publisher Workflow State Model. """ DRAFT = 'draft' NEEDS_REVIEW = 'needs_review' NEEDS_FINAL_APPROVAL = 'needs_final_approval' FINALIZED = 'finalized' PUBLISHED = 'published' CHOICES = ((DRAFT, _('Draft')), (NEEDS_REVIEW, _('Needs Review')), (NEEDS_FINAL_APPROVAL, _('Needs Final Approval')), (FINALIZED, _('Finalized')), (PUBLISHED, _('Published'))) name = FSMField(default=DRAFT, choices=CHOICES) history = HistoricalRecords() def __str__(self): return self.get_name_display() @transition(field=name, source='*', target=DRAFT) def draft(self): # TODO: send email etc. pass @transition(field=name, source=DRAFT, target=NEEDS_REVIEW) def needs_review(self): # TODO: send email etc. pass @transition(field=name, source=NEEDS_REVIEW, target=NEEDS_FINAL_APPROVAL) def needs_final_approval(self): # TODO: send email etc. pass @transition(field=name, source=NEEDS_FINAL_APPROVAL, target=FINALIZED) def finalized(self): # TODO: send email etc. pass @transition(field=name, source=FINALIZED, target=PUBLISHED) def publish(self): # TODO: send email etc. pass
class DucatusTransfer(models.Model): STATES = ('DONE', 'WAITING_FOR_CONFIRMATION') STATES = list(zip(STATES, STATES)) exchange_request = models.ForeignKey(ExchangeRequest, on_delete=models.CASCADE, null=True) tx_hash = models.CharField(max_length=100, null=True, default='') amount = models.DecimalField(max_digits=MAX_DIGITS, decimal_places=0) payment = models.ForeignKey(Payment, on_delete=models.CASCADE, related_name='transfers') currency = models.CharField(max_length=25, null=True, default=None) state = FSMField(default=STATES[0], choices=STATES) created_date = models.DateTimeField(auto_now_add=True) # States change @transition(field=state, source='*', target='DONE') def state_done(self): pass
class Task(models.Model): title = models.CharField(max_length=300) body = models.TextField() taskid = UUIDField(auto=True) slug = models.CharField(max_length=200, unique=True, blank=True, help_text='auto generate slug field') state = FSMField(default='new') priority = models.IntegerField(choices=PRIORITY_CHOICES, default=2) assign_date = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) staff = models.ForeignKey(Staff, blank=True) due_date = models.DateTimeField(default=None) @transition(field=state, source='new', target='approve') def approve(self): pass @transition(field=state, source='approve', target='new') def unapprove(self): pass def save(self, *args, **kwargs): if not self.id: self.assign_date = datetime.datetime.today() self.modified = datetime.datetime.today() # self.slug = slugify(self.title) self.slug = "%s-%s" % (self.assign_date.strftime('%d-%b-%Y'), self.title.replace(" ", "-")) #self.slug = "%s" % (self.title.replace(" ", "-")) super(Task, self).save(*args, **kwargs) def __unicode__(self): return self.title class Meta: verbose_name = "Task" verbose_name_plural = "Tasks" ordering = ["-assign_date"]
class Article(models.Model): title = models.CharField(max_length=256) url = models.URLField() created_on = models.DateTimeField(auto_now_add=True) state = FSMField(default='submitted', protected=True) def __str__(self): return self.title @transition(field=state, source='submitted', target='approved') def approve(self): pass @transition(field=state, source='submitted', target='rejected') def reject(self): pass @transition(field=state, source='approved', target='published') def publish(self): pass
class Newsletter(models.Model): title = models.CharField(max_length=100) message = models.TextField() date_created = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) state = FSMField(default='Draft') @transition(field=state, source='Draft', target='Ready') def ready(self): self.state = 'Ready' self.save() @transition(field=state, source='Ready', target='Send') def send(self): self.state = 'Sent' self.save() from .utils import send_newsletter_mail subscribers = Subscriber.objects.filter( unsubscribed=False).values_list('email', flat=True) send_newsletter_mail(subscribers, self)
class BooksFlow(models.Model): book_id = models.IntegerField(default='1') name = models.CharField(max_length=100) status = FSMField(default='ADD', protected=True) @transition(field=status, source=TRANSITION_MAP.get('ISU'), target='ISU') def issue(self): pass @transition(field=status, source=TRANSITION_MAP.get('RSU'), target='RSU') def reissue(self): pass @transition(field=status, source=TRANSITION_MAP.get('RMV'), target='RMV') def remove(self): pass @transition(field=status, source=TRANSITION_MAP.get('RTN'), target='RTN') def returned(self): pass
class BaseOrderShipping(with_metaclass(WorkflowMixinMetaclass, models.Model)): """ A model to keep track on the shipping of each order's item. """ order = deferred.ForeignKey(BaseOrder, verbose_name=_("Order")) status = FSMField(default='new', protected=True, verbose_name=_("Status")) shipping_id = models.CharField( _("Shipping ID"), max_length=255, help_text=_("The transaction processor's reference")) shipping_method = models.CharField( _("Shipping method"), max_length=255, help_text=_( "The shipping backend used to deliver the items for this order")) class Meta: abstract = True verbose_name = _("Shipping order") verbose_name_plural = _("Shipping orders")
class BlogPost(models.Model): """ Test workflow """ state = FSMField(default='new', protected=True) @transition(field=state, source='new', target='published', permission='testapp.can_publish_post') def publish(self): pass @transition(field=state, source='published') def notify_all(self): pass @transition(field=state, source='published', target='hidden') def hide(self): pass @transition(field=state, source='new', target='removed', permission=lambda u: u.has_perm('testapp.can_remove_post')) def remove(self): raise Exception('No rights to delete %s' % self) @transition(field=state, source=['published', 'hidden'], target='stolen') def steal(self): pass @transition(field=state, source='*', target='moderated') def moderate(self): pass class Meta: permissions = [ ('can_publish_post', 'Can publish post'), ('can_remove_post', 'Can remove post'), ]
class TranslationImportJob(models.Model): language = models.ForeignKey('Language', on_delete=models.CASCADE) google_sheet_id = models.CharField(max_length=50) status = FSMField(default='new') updated_rows = models.PositiveIntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) @transition(field=status, source='new', target='in_progress') def start_processing(self): pass @transition(field=status, source='in_progress', target='successful') def mark_success(self): pass @transition(field=status, source='in_progress', target='failed') def mark_fail(self): pass
class Channel(TimeStampedModel): name = models.CharField(max_length=32, verbose_name=_('Name')) description = models.TextField(max_length=256, verbose_name=_('Description')) channel_type = FSMField(choices=CHANNEL_TYPE_CHOICES, default=CHAT_ROOM_TYPE.private, verbose_name=_('Channel type')) class Meta: ordering = ('created', ) verbose_name = _('Channel') verbose_name_plural = _('Channels') @classmethod def get_public_channel(cls): channel, created = Channel.objects.get_or_create( name='Public', channel_type=CHAT_ROOM_TYPE.public) return channel def quick_messages(self): return self.messages.all()
class Talk(models.Model): created = models.DateTimeField(default=timezone.now) submission = models.ForeignKey('formbuilder.Submission', null=True) token = models.CharField(max_length=15, unique=True) title = models.CharField(max_length=300) call = models.ForeignKey('Call') profile = models.ForeignKey('Profile') state = FSMField(default='new', protected=True, db_index=True) def __str__(self): return self.title @transition(field=state, source='new', target='submitted') def submit(self): pass def get_absolute_url(self): return reverse('talk_read', args=[self.id]) def get_admin_url(self): return reverse('submission_read', args=[self.id])
class Proposal(ConcurrentTransitionMixin, Base): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) state = FSMField( default=State.NEW, choices=State.PROPOSAL_STATES, protected=True, ) user = models.ForeignKey(settings.AUTH_USER_MODEL) travel = models.ForeignKey(Travel) description = models.CharField(max_length=255) class Meta: unique_together = (("user", "route"),) def save(self, *args, **kwargs): if self.ACCEPT_ARRIVED def __str__(self): return str(self.id)
class Publication(models.Model): """ Model representing a publication. """ class Meta: app_label = 'article' ordering = ['-year', '-month', '-id'] verbose_name_plural = 'Articles' # names shown in admin area MONTH_CHOICES = ((1, 'January'), (2, 'February'), (3, 'March'), (4, 'April'), (5, 'May'), (6, 'June'), (7, 'July'), (8, 'August'), (9, 'September'), (10, 'October'), (11, 'November'), (12, 'December')) title = models.CharField(max_length=512) #TODO many to many with user authors = models.CharField( max_length=2048, help_text='List of authors separated by commas or <i>and</i>.') year = models.PositiveIntegerField() month = models.IntegerField(choices=MONTH_CHOICES, blank=True, null=True) volume = models.IntegerField(blank=True, null=True) number = models.IntegerField(blank=True, null=True, verbose_name='Issue number') pages = PagesField(max_length=32, blank=True) #here sth wrong, needs pages field note = models.CharField(max_length=256, blank=True) keywords = models.CharField( max_length=256, blank=True, help_text='List of keywords separated by commas.') url = models.URLField(blank=True, verbose_name='URL', help_text='Link to PDF or journal page.') #pdf = models.FileField(upload_to='publications/', verbose_name='PDF', blank=True, null=True) doi = models.CharField(max_length=128, verbose_name='DOI', blank=True) abstract = models.TextField(blank=True) state = FSMField(default='new') #???
class Document(models.Model): created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) slug = models.SlugField(max_length=4096, unique=True) url = TextFieldSingleLine(unique=True) title = TextFieldSingleLine(null=True, blank=True) meta = models.TextField() content = models.TextField() text = models.TextField(null=True, blank=True) feed = models.ForeignKey(Feed) state = FSMField(default='new', protected=True) @transition(field=state, source='new', target='parsed') def parse(self): if not self.feed.parser: raise Exception('No parser defined.') module = import_module('parsers.parsers') c = getattr(module, self.feed.parser.slug) parser = c() parser.get_text(self) if not self.text: raise Exception('Could not parse text.') def get_absolute_url(self): return reverse('document', args=[str(self.slug)]) def save(self, *args, **kwargs): if not self.id: self.slug = slugify(self.url) super(Document, self).save(*args, **kwargs) def __str__(self): return self.title if self.title else self.url class Meta: ordering = ('-created_at', )
class SeasonReport(models.Model): """SeasonReport model""" class Meta: verbose_name = "Отчет за сезон" verbose_name_plural = "Отчеты за сезон" seasons = models.ManyToManyField(Season, blank=True, related_name="season_reports") brigade = models.ForeignKey( Brigade, on_delete=models.RESTRICT, verbose_name="Отряд", related_name="season_reports", ) year = models.IntegerField(verbose_name="Год выезда") employer = models.TextField(blank=True, null=True) class SeasonReportState(TextChoices): INITIAL = "initial", _("Создан") ACCEPTED = "accepted", _("Подтвержден") REQUEST = "request", _("Заявка бойца") is_summer = models.BooleanField(default=False, verbose_name="Летний") state = FSMField( default=SeasonReportState.INITIAL, choices=SeasonReportState.choices, verbose_name="Статус отчета", ) @property def boec_count(self): return self.seasons.filter( state=SeasonReport.SeasonReportState.ACCEPTED).count() def __str__(self): return f"{self.brigade.title}"
class JobApplication(TimeStampedModel): STATUS = Choices( ("DRAFT", _("Draft")), ("ACTIVE", _("Active")), ("SHORTLISTED", _("Short-listed")), ("REJECTED", _("Rejected")), ("ARCHIVED", _("Archived")), ) user = models.ForeignKey(User, on_delete=models.CASCADE) job = models.ForeignKey(Job, on_delete=models.CASCADE) state = FSMField(default=STATUS.DRAFT, choices=STATUS) data = JSONField() cv_url = models.URLField(max_length=100) objects = JobApplicationManager() @transition(field=state, source=STATUS.DRAFT, target=STATUS.ACTIVE) def activate(self): pass @transition(field=state, source=STATUS.ACTIVE, target=STATUS.SHORTLISTED) def shortlisted(self): pass @transition( field=state, source=[STATUS.SHORTLISTED, STATUS.ACTIVE], target=STATUS.REJECTED, ) def rejected(self): pass @transition(field=state, source="*", target=STATUS.ARCHIVED) def archive(self): pass def __str__(self): return f"Application: {self.id}: {self.job.title} {self.user.username}"
class Account(Model): OPEN = 'OPEN' CLOSED = 'CLOSED' STATUS_CHOICES = ( (OPEN, _('Open')), (CLOSED, _('Closed')), ) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) created = models.DateTimeField(auto_now_add=True, db_index=True) modified = models.DateTimeField(auto_now=True) owner = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='billing_account', on_delete=PROTECT) currency = CurrencyField(db_index=True) status = FSMField(max_length=20, choices=STATUS_CHOICES, default=OPEN, db_index=True) objects = AccountQuerySet.as_manager() def balance(self, as_of: date = None): charges = Charge.objects.filter(account=self) transactions = Transaction.successful.filter(account=self) if as_of is not None: charges = charges.filter(created__lte=as_of) transactions = transactions.filter(created__lte=as_of) return total_amount(transactions) - total_amount(charges) @transition(field=status, source=OPEN, target=CLOSED) def close(self): pass @transition(field=status, source=CLOSED, target=OPEN) def reopen(self): pass def __str__(self): return str(self.owner)
class Inventory(models.Model): sku = models.ForeignKey('SKU', on_delete=models.PROTECT) total_price = models.DecimalField(_("MRP"), max_digits=20, decimal_places=2, null=True, blank=True) created_at = models.DateTimeField(_("Creation Date"), auto_now_add=True) created_by = models.ForeignKey(User, related_name='inventory_created_by') modified_at = models.DateTimeField(_("Modified Date"), blank=True, null=True) modified_by = models.ForeignKey(User, blank=True, null=True, related_name='inventory_modified_by') quantity = models.PositiveIntegerField(_("Quantity"), null=True, blank=True) status = FSMField(default=PENDING, protected=False, db_index=True) batch = models.ForeignKey(Batch, on_delete=models.PROTECT, blank=True) vendor = models.ForeignKey('vendor.Vendor', on_delete=models.PROTECT) @transition( field=status, source=PENDING, target=APPROVED, permission=can_approve_inventory, ) def approve(self): self.modified_by = current_request().user self.modified_at = timezone.now() SKU.objects.filter(pk=self.sku_id).update( total_quantity=F('total_quantity') + self.quantity) class Meta: verbose_name = _('Inventory') verbose_name_plural = _('Inventories')
class Insect(models.Model): class STATE: CATERPILLAR = 'CTR' BUTTERFLY = 'BTF' STATE_CHOICES = ((STATE.CATERPILLAR, 'Caterpillar', 'Caterpillar'), (STATE.BUTTERFLY, 'Butterfly', 'Butterfly')) state = FSMField(default=STATE.CATERPILLAR, state_choices=STATE_CHOICES) @transition(field=state, source=STATE.CATERPILLAR, target=STATE.BUTTERFLY) def cocoon(self): pass def fly(self): raise NotImplementedError def crawl(self): raise NotImplementedError class Meta: app_label = 'testapp'
class JobApplication(m.Model): id = m.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) job = m.ForeignKey(Job, blank=True, null=True, on_delete=m.SET_NULL) issuer = m.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=m.SET_NULL, related_name='application_issuer') state = FSMField(default='requested') date_created = m.DateTimeField(auto_now_add=True) date_last_modified = m.DateTimeField(auto_now=True) def __str__(self): return self.issuer.username @transition(field=state, source=['requested'], target='approved') def move_to_approved(self): pass @transition(field=state, source=['requested'], target='rejected') def move_to_rejected(self): pass
class Research(models.Model): claim = models.ForeignKey(Claim, related_name="research_set", on_delete=models.CASCADE) truth = models.IntegerField(_("Truth"), null=True) content = models.TextField(blank=True) sources = models.ManyToManyField("Source", verbose_name=_("Sources"), related_name='research') researcher = models.ForeignKey("user.User", related_name="researched", on_delete=models.PROTECT) researched = models.DateTimeField(null=True) verification = models.ForeignKey("Verification", related_name="+", null=True, on_delete=models.SET_NULL) arbitration = models.ForeignKey("Arbitration", related_name="+", null=True, on_delete=models.SET_NULL) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) RESEARCHING = 'researching' RESEARCHED = 'researched' VERIFYING = 'verifying' VERIFIED = 'verified' CONTENTION = 'contention' # a type of Research ARBITRATE = 'arbitrate' ARBITRATING = 'arbitrating' COMPLETED = 'completed' PHASES = ( (RESEARCHING, pgettext_lazy('research.status', 'Researching')), (RESEARCHED, pgettext_lazy('research.status', 'Researched')), (VERIFYING, pgettext_lazy('research.status', 'Verifying')), (VERIFIED, pgettext_lazy('research.status', 'Verified')), (CONTENTION, pgettext_lazy('research.status', 'Contention')), (ARBITRATE, pgettext_lazy('research.status', 'Needs Arbitration')), (ARBITRATING, pgettext_lazy('research.status', 'Arbitrating')), (COMPLETED, pgettext_lazy('research.status', 'Completed')), ) phase = FSMField(choices=PHASES, default=RESEARCHING) objects = ResearchQuerySet.as_manager() def is_completed(self): return self.phase == Research.COMPLETED