Skip to content

Instantly share code, notes, and snippets.

@mariocesar
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mariocesar/882e911d8863dbc738b2 to your computer and use it in GitHub Desktop.
Save mariocesar/882e911d8863dbc738b2 to your computer and use it in GitHub Desktop.
Workflow Model Helper for Django
from django.db import models
from .workflow import Workflow, StateField
class SaleOrder(Workflow, models.Model):
DRAFT = 'draft'
QUOTATION = 'quotation'
CONFIRMED = 'confirmed'
PROCESSING = 'processing'
CANCEL = 'cancel'
DONE = 'done'
ORDER_STATES = (
(DRAFT, 'Draft'),
(QUOTATION, 'Quotation'),
(CONFIRMED, 'Confirmed'),
(PROCESSING, 'Processing'),
(CANCEL, 'Cancel'),
(DONE, 'Done')
)
state = StateField(choices=ORDER_STATES, default=DRAFT)
_transitions = (
((DRAFT, QUOTATION), 'Send Quotation'),
((QUOTATION, CONFIRMED), 'Confirm Sale'),
((CONFIRMED, PROCESSING), 'Process'),
((PROCESSING, PROCESSING), 'Process'), # To Force an update
((PROCESSING, DONE), 'Sale'),
((DONE, PROCESSING), 'Update'),
((DRAFT, CANCEL), 'Cancel'),
((QUOTATION, CANCEL), 'Canel'),
((QUOTATION, DRAFT), 'Revert as Draft'),
((CANCEL, DRAFT), 'Cancel')
)
@Workflow.transition(CANCEL)
def cancel(self, context):
pass
@Workflow.transition(DRAFT)
def draft(self, context):
pass
@Workflow.transition(QUOTATION)
def quote(self, context):
pass
@Workflow.transition(CONFIRMED)
def confirm(self, context):
pass
@Workflow.transition(PROCESSING)
def proceed(self, context):
pass
@Workflow.transition(DONE)
def do(self, context):
pass
from django.db.models import CharField
from functools import wraps
class Workflow:
_state_field_name = 'state'
_transitions = None
@staticmethod
def transition(state):
"""Decorador para transicion"""
def check_transition(func):
@wraps(func)
def wrapper(self, context=None, *args, **kwargs):
current_state = self.get_current_state()
# actionable transition
transition = (current_state, state)
if self._transitions:
# If the transition is declared we will apply
for transition, label in self._transitions:
if transition in self._transitions:
return func(self, context)
return wrapper
return check_transition
def get_current_state(self):
return getattr(self, self._state_field_name)
def get_available_transitions(self):
current_state = self.get_current_state()
state_field = self._meta.get_field(self._state_field_name)
current_state_label = dict(state_field.flatchoices).get(current_state, current_state)
available_transitions = [(current_state, current_state_label)]
for transition, label in self._transitions:
step, next_state = transition
if next_state not in available_transitions and step == current_state:
available_transitions.append((next_state, label))
return available_transitions
class StateField(CharField):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 20
kwargs['db_index'] = True
kwargs['null'] = False
kwargs['blank'] = False
super(CharField, self).__init__(*args, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment