예제 #1
0
class CooperationPartnerProcess(Process):

    states = COOPERATION_PARTNER_STATE_CHOICES

    transitions = [
        Transition(action_name='action_verify_account',
                   sources=[
                       COOPERATION_PARTNER_STATE_REGISTERED,
                       COOPERATION_PARTNER_STATE_EXPIRED
                   ],
                   target=COOPERATION_PARTNER_STATE_ON_HOLD,
                   side_effects=[side_effects.verify_account],
                   callbacks=[call_backs.verify_account]),
        Transition(action_name='action_approve_account',
                   sources=[
                       COOPERATION_PARTNER_STATE_ON_HOLD,
                       COOPERATION_PARTNER_STATE_REJECTED
                   ],
                   target=COOPERATION_PARTNER_STATE_APPROVED,
                   side_effects=[side_effects.approve_account]),
        Transition(action_name='action_reject_account',
                   sources=[
                       COOPERATION_PARTNER_STATE_ON_HOLD,
                       COOPERATION_PARTNER_STATE_APPROVED
                   ],
                   target=COOPERATION_PARTNER_STATE_REJECTED,
                   side_effects=[side_effects.reject_account]),
    ]
예제 #2
0
    def test_nested_process_fail(self):
        transition1 = Transition('action', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['done'], target='closed')

        class ChildProcess(Process):
            permissions = [allowed]
            conditions = [is_editable]
            transitions = [transition1, transition2]

        process = ChildProcess(instance=Invoice.objects.create(status='draft'),
                               field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [transition1])

        class ParentProcess(Process):
            permissions = [allowed]
            conditions = [is_editable]
            nested_processes = (ChildProcess, )

        process = ParentProcess(
            instance=Invoice.objects.create(status='draft'),
            field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [transition1])

        class GrandParentProcess(Process):
            permissions = [allowed]
            conditions = [not_available]
            nested_processes = (ParentProcess, )

        process = GrandParentProcess(
            instance=Invoice.objects.create(status='draft'),
            field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [])
예제 #3
0
 class TestProcess(Process):
     transitions = [
         Transition('cancel', sources=[
             'draft',
         ], target='cancelled'),
         Transition('undo', sources=['cancelled'], target='draft')
     ]
예제 #4
0
    def test_transition_permissions_as_conditions(self):
        def is_staff(obj):
            return False

        def is_permitted(obj):
            return False

        transition1 = Transition('action',
                                 sources=['draft'],
                                 target='done',
                                 permissions=[is_staff])
        transition2 = Transition('action',
                                 sources=['draft'],
                                 target='closed',
                                 permissions=[is_permitted])

        class MainProcess(Process):
            transitions = [transition1, transition2]

        self.assertEqualNodes(
            annotate_nodes(MainProcess), {
                'id':
                get_object_id(MainProcess),
                'name':
                'Main Process',
                'type':
                'process',
                'nodes': [{
                    'id': get_object_id(transition1),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': get_object_id(transition2),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': f'{get_object_id(transition1)}|conditions',
                    'name': 'is_staff',
                    'type': 'transition_conditions'
                }, {
                    'id': f'{get_object_id(transition2)}|conditions',
                    'name': 'is_permitted',
                    'type': 'transition_conditions'
                }, {
                    'id': 'closed',
                    'name': 'closed',
                    'type': 'state'
                }, {
                    'id': 'done',
                    'name': 'done',
                    'type': 'state'
                }, {
                    'id': 'draft',
                    'name': 'draft',
                    'type': 'state'
                }]
            })
예제 #5
0
    def test_get_actions_with_the_same_name(self):
        transition1 = Transition('action', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['draft'], target='closed')

        class ChildProcess(Process):
            transitions = [transition1, transition2]

        process = ChildProcess(instance=Invoice.objects.create(status='draft'),
                               field_name='status')
        self.assertEqual(process.get_available_actions(), ['action'])
예제 #6
0
class UserLockerProcess(Process):
    permissions = [is_user]
    transitions = [
        Transition(action_name='lock',
                   sources=[LOCK_STATES.open],
                   target=LOCK_STATES.locked),
        Transition(action_name='unlock',
                   sources=[LOCK_STATES.locked],
                   target=LOCK_STATES.open)
    ]
예제 #7
0
 def test_many_side_effects(self):
     transition = Transition('test',
                             sources=[],
                             target='cancelled',
                             side_effects=[disable_invoice, enable_invoice])
     self.assertTrue(self.invoice.is_available)
     state = State(self.invoice, 'status')
     transition.change_state(state)
     self.assertEqual(self.invoice.status, transition.target)
     self.assertTrue(self.invoice.is_available)
     self.assertFalse(state.is_locked())
예제 #8
0
 def test_one_callback(self):
     transition = Transition('test',
                             sources=[],
                             target='cancelled',
                             callbacks=[disable_invoice])
     self.assertTrue(self.invoice.is_available)
     state = State(self.invoice, 'status')
     transition.change_state(state)
     self.assertEqual(self.invoice.status, transition.target)
     self.assertFalse(self.invoice.is_available)
     self.assertFalse(state.is_locked())
예제 #9
0
 def test_one_callback(self):
     transition = Transition('test',
                             sources=[],
                             target='success',
                             side_effects=[fail_invoice],
                             failure_callbacks=[disable_invoice],
                             failed_state='failed')
     self.assertTrue(self.invoice.is_available)
     state = State(self.invoice, 'status')
     transition.change_state(state)
     self.assertEqual(self.invoice.status, 'failed')
     self.assertFalse(self.invoice.is_available)
     self.assertFalse(state.is_locked())
예제 #10
0
 class TestProcess(Process):
     transitions = [
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    callbacks=[disable_invoice]),
         Transition('undo',
                    sources=['cancelled'],
                    target='draft',
                    callbacks=[update_invoice])
     ]
예제 #11
0
 def test_failure_during_side_effect_with_failed_state(self):
     transition = Transition(
         'test',
         sources=[],
         target='cancelled',
         failed_state='failed',
         side_effects=[disable_invoice, fail_invoice, enable_invoice])
     self.assertTrue(self.invoice.is_available)
     state = State(self.invoice, 'status')
     transition.change_state(state)
     self.assertEqual(self.invoice.status, 'failed')
     self.assertFalse(self.invoice.is_available)
     self.assertFalse(state.is_locked())
예제 #12
0
    def test_nested_process_with_nested_transitions_conditions_and_permissions_fail(
            self):
        transition1 = Transition('action',
                                 permissions=[allowed],
                                 conditions=[is_editable],
                                 sources=['draft'],
                                 target='done')
        transition2 = Transition('action',
                                 permissions=[disallow],
                                 conditions=[is_editable],
                                 sources=['done'],
                                 target='closed')
        transition3 = Transition('action',
                                 permissions=[allowed],
                                 conditions=[not_available],
                                 sources=['draft'],
                                 target='approved')
        transition4 = Transition('action',
                                 permissions=[allowed],
                                 conditions=[is_editable],
                                 sources=['done'],
                                 target='closed')
        transition5 = Transition('action',
                                 permissions=[disallow],
                                 conditions=[not_available],
                                 sources=['draft'],
                                 target='declined')

        class ChildProcess(Process):
            transitions = [transition1, transition2]

        class ParentProcess(Process):
            nested_processes = (ChildProcess, )
            transitions = [transition3, transition4]

        class GrandParentProcess(Process):
            nested_processes = (ParentProcess, )

            transitions = [transition5]

        process = GrandParentProcess(
            instance=Invoice.objects.create(status='draft'),
            field_name='status')
        for transition in process.get_available_transitions(self.user):
            self.assertIn(transition, [transition1])

        process = GrandParentProcess(
            instance=Invoice.objects.create(status='done'),
            field_name='status')
        for transition in process.get_available_transitions(self.user):
            self.assertIn(transition, [transition4])
예제 #13
0
    def test_get_sorted_list(self):
        transition1 = Transition('cancel', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['draft'], target='closed')
        transition3 = Transition('bulk_action',
                                 sources=['draft'],
                                 target='closed')

        class ChildProcess(Process):
            transitions = [transition1, transition2, transition3]

        process = ChildProcess(instance=Invoice.objects.create(status='draft'),
                               field_name='status')
        self.assertEqual(process.get_available_actions(),
                         ['action', 'bulk_action', 'cancel'])
예제 #14
0
 class TestProcess(Process):
     transitions = [
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    callbacks=[disable_invoice]),
         Transition('undo',
                    sources=['draft'],
                    target='draft',
                    side_effects=[fail_invoice],
                    failed_state='failed',
                    failure_callbacks=[update_invoice])
     ]
예제 #15
0
 class TestProcess(Process):
     transitions = [
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    conditions=[is_editable]),
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    conditions=[is_available])
     ]
예제 #16
0
 class TestProcess(Process):
     transitions = [
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    permissions=[is_staff]),
         Transition('cancel',
                    sources=[
                        'draft',
                    ],
                    target='cancelled',
                    permissions=[allowed])
     ]
예제 #17
0
class StaffLockerProcess(Process):
    permissions = [is_staff]
    all_states = [x for x, y in LOCK_STATES]

    transitions = [
        Transition(action_name='lock',
                   sources=[LOCK_STATES.open, LOCK_STATES.maintenance],
                   target=LOCK_STATES.locked),
        Transition(action_name='unlock',
                   sources=[LOCK_STATES.locked, LOCK_STATES.maintenance],
                   target=LOCK_STATES.open),
        Transition(action_name='maintain',
                   sources=all_states,
                   target=LOCK_STATES.maintenance,
                   conditions=[is_planned])
    ]
예제 #18
0
 def test_side_effect_with_parameters(self):
     update_invoice(self.invoice, is_available=True, customer_received=True)
     transition = Transition('test',
                             sources=[],
                             target='cancelled',
                             failed_state='failed',
                             side_effects=[update_invoice])
     self.invoice.refresh_from_db()
     self.assertTrue(self.invoice.is_available)
     self.assertTrue(self.invoice.customer_received)
     state = State(self.invoice, 'status')
     transition.change_state(state,
                             is_available=False,
                             customer_received=False)
     self.invoice.refresh_from_db()
     self.assertFalse(self.invoice.is_available)
     self.assertFalse(self.invoice.customer_received)
     self.assertFalse(state.is_locked())
예제 #19
0
    def test_get_target_states(self):
        transition1 = Transition('cancel',
                                 sources=['draft'],
                                 target='done',
                                 failed_state='failed')
        transition2 = Transition('action',
                                 sources=['draft'],
                                 target='closed',
                                 failed_state='invalid')
        transition3 = Transition('bulk_action',
                                 sources=['draft'],
                                 target='closed',
                                 in_progress_state='closing')

        class ChildProcess(Process):
            transitions = [transition1, transition2, transition3]

        states = {'done', 'closed', 'failed', 'invalid', 'closing'}
        self.assertEqual(get_target_states(ChildProcess), states)
예제 #20
0
 def test_failure_callback_exception_passed(self, debug_mock):
     update_invoice(self.invoice, is_available=True, customer_received=True)
     transition = Transition('test',
                             sources=[],
                             target='success',
                             failed_state='failed',
                             side_effects=[fail_invoice],
                             failure_callbacks=[debug_action])
     self.invoice.refresh_from_db()
     state = State(self.invoice, 'status')
     transition.change_state(state, foo="bar")
     self.assertTrue(debug_mock.called)
     self.assertEqual(debug_mock.call_count, 1)
     call_args = debug_mock.call_args[0]
     call_kwargs = debug_mock.call_args[1]
     self.assertEqual(call_args, (self.invoice, ))
     self.assertEqual(len(call_kwargs), 2)
     self.assertTrue(isinstance(call_kwargs['exception'], Exception))
     self.assertEqual(call_kwargs['foo'], 'bar')
예제 #21
0
    def test_process_fail(self):
        transition1 = Transition('action', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['done'], target='closed')

        class ChildProcess(Process):
            conditions = [not_available]
            transitions = [transition1, transition2]

        process = ChildProcess(instance=Invoice.objects.create(status='draft'),
                               field_name='status')
        self.assertEqual(list(process.get_available_transitions()), [])

        process = ChildProcess(instance=Invoice.objects.create(status='done'),
                               field_name='status')
        self.assertEqual(list(process.get_available_transitions()), [])

        process = ChildProcess(
            instance=Invoice.objects.create(status='closed'),
            field_name='status')
        self.assertEqual(list(process.get_available_transitions()), [])
예제 #22
0
    def test_transitions(self):
        transition1 = Transition('action', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['draft'], target='closed')

        class MainProcess(Process):
            transitions = [transition1, transition2]

        nodes = annotate_nodes(MainProcess)

        self.assertEqualNodes(
            nodes, {
                'id':
                get_object_id(MainProcess),
                'name':
                'Main Process',
                'type':
                'process',
                'nodes': [{
                    'id': get_object_id(transition1),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': get_object_id(transition2),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': 'closed',
                    'name': 'closed',
                    'type': 'state'
                }, {
                    'id': 'done',
                    'name': 'done',
                    'type': 'state'
                }, {
                    'id': 'draft',
                    'name': 'draft',
                    'type': 'state'
                }]
            })
예제 #23
0
    def test_get_all_states(self):
        transition1 = Transition('cancel',
                                 sources=['draft', 'open'],
                                 target='done',
                                 failed_state='failed')
        transition2 = Transition('action',
                                 sources=['draft'],
                                 target='closed',
                                 failed_state='invalid')
        transition3 = Transition('bulk_action',
                                 sources=['draft'],
                                 target='closed',
                                 in_progress_state='closing')

        class ChildProcess(Process):
            transitions = [transition1, transition2, transition3]

        states = {
            'done', 'closed', 'failed', 'invalid', 'closing', 'draft', 'open'
        }
        self.assertEqual(get_all_states(ChildProcess), states)

        transition4 = Transition('approve',
                                 sources=['draft', 'created'],
                                 target='approved',
                                 failed_state='declined',
                                 in_progress_state='approving')
        states |= {'approved', 'approving', 'declined', 'created'}

        class MainProcess(Process):
            transitions = [
                transition4,
            ]
            nested_processes = [
                ChildProcess,
            ]

        self.assertEqual(get_all_states(MainProcess), states)
예제 #24
0
    def test_conditions_and_permissions_successfully(self):
        transition1 = Transition('action', sources=['draft'], target='done')
        transition2 = Transition('action', sources=['done'], target='closed')

        class ChildProcess(Process):
            conditions = [is_editable]
            permissions = [allowed]
            transitions = [transition1, transition2]

        process = ChildProcess(instance=Invoice.objects.create(status='draft'),
                               field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [transition1])

        process = ChildProcess(instance=Invoice.objects.create(status='done'),
                               field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [transition2])

        process = ChildProcess(
            instance=Invoice.objects.create(status='closed'),
            field_name='status')
        self.assertEqual(list(process.get_available_transitions(self.user)),
                         [])
예제 #25
0
class InvoiceProcess(Process):
    process_name = 'invoice_process'

    states = (
        ('draft', 'Draft'),
        ('paid', 'Paid'),
        ('void', 'Void'),
        ('sent', 'Sent'),
        ('failed', 'Failed'),
    )

    transitions = [
        Transition(action_name='approve', sources=['draft'],
                   target='approved'),
        CeleryTransition(action_name='send_to_customer',
                         sources=['approved'],
                         side_effects=['demo.tasks.send_to_a_customer'],
                         target='sent'),
        Transition(action_name='void',
                   sources=['draft', 'paid'],
                   target='voided'),
        CeleryTransition(
            action_name='demo',
            sources=['draft'],
            target='sent',
            in_progress_state='in_progress',
            side_effects=[
                'demo.tasks.demo_task_1', 'demo.tasks.demo_task_2',
                'demo.tasks.demo_task_3'
            ],
            callbacks=['demo.tasks.demo_task_4', 'demo.tasks.demo_task_5']),
        CelerySingleTaskTransition(
            action_name='demo_single',
            sources=['draft'],
            target='sent',
            in_progress_state='in_progress',
            side_effects=[
                tasks.demo_task_1, tasks.demo_task_2, tasks.demo_task_3
            ],
            callbacks=[tasks.demo_task_4, tasks.demo_task_5]),
        CeleryTransition(action_name='failing_transition',
                         sources=['draft'],
                         target='sent',
                         in_progress_state='in_progress',
                         failed_state='failed',
                         side_effects=[
                             'demo.tasks.demo_task_1',
                             'demo.tasks.demo_task_exception',
                             'demo.tasks.demo_task_2'
                         ],
                         failure_callbacks=[
                             'demo.tasks.demo_task_3', 'demo.tasks.demo_task_4'
                         ]),
        CelerySingleTaskTransition(
            action_name='failing_transition_single',
            sources=['draft'],
            target='sent',
            in_progress_state='in_progress',
            failed_state='failed',
            side_effects=[
                tasks.demo_task_1, tasks.demo_task_exception, tasks.demo_task_2
            ],
            failure_callbacks=[tasks.demo_task_3, tasks.demo_task_4])
    ]
예제 #26
0
    def test_transition_conditions(self):
        def is_available(obj):
            return True

        def is_open(obj):
            return True

        transition1 = Transition('action',
                                 sources=['draft'],
                                 target='done',
                                 conditions=[
                                     is_available,
                                 ])
        transition2 = Transition('action',
                                 sources=['draft'],
                                 target='closed',
                                 conditions=[
                                     is_open,
                                 ])

        class MainProcess(Process):
            transitions = [transition1, transition2]

        self.assertEqualNodes(
            annotate_nodes(MainProcess), {
                'id':
                get_object_id(MainProcess),
                'name':
                'Main Process',
                'type':
                'process',
                'nodes': [{
                    'id': get_object_id(transition1),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': get_object_id(transition2),
                    'name': 'action',
                    'type': 'transition'
                }, {
                    'id': f'{get_object_id(transition1)}|conditions',
                    'name': 'is_available',
                    'type': 'transition_conditions'
                }, {
                    'id': f'{get_object_id(transition2)}|conditions',
                    'name': 'is_open',
                    'type': 'transition_conditions'
                }, {
                    'id': 'closed',
                    'name': 'closed',
                    'type': 'state'
                }, {
                    'id': 'done',
                    'name': 'done',
                    'type': 'state'
                }, {
                    'id': 'draft',
                    'name': 'draft',
                    'type': 'state'
                }]
            })
예제 #27
0
    def test_intersect_states(self):
        transition1 = Transition('action', sources=['draft'], target='open')
        transition2 = Transition('action', sources=['draft'], target='closed')
        transition3 = Transition('action', sources=['draft'], target='closed')
        transition4 = Transition('action', sources=['draft'], target='open')

        class ChildProcess(Process):
            transitions = [transition1, transition2]

        class MainProcess(Process):
            transitions = [transition3]
            nested_processes = [ChildProcess]

        class SuperProcess(Process):
            transitions = [transition4]
            nested_processes = [MainProcess]

        self.assertEqualNodes(
            annotate_nodes(SuperProcess), {
                "id":
                get_object_id(SuperProcess),
                "name":
                "Super Process",
                "type":
                "process",
                "nodes": [{
                    "id": get_object_id(transition4),
                    "name": "action",
                    "type": "transition"
                }, {
                    "id": "open",
                    "name": "open",
                    "type": "state"
                }, {
                    "id": "draft",
                    "name": "draft",
                    "type": "state"
                }, {
                    "id":
                    get_object_id(MainProcess),
                    "name":
                    "Main Process",
                    "type":
                    "process",
                    "nodes": [{
                        "id": get_object_id(transition3),
                        "name": "action",
                        "type": "transition"
                    }, {
                        "id": "closed",
                        "name": "closed",
                        "type": "state"
                    }, {
                        "id":
                        get_object_id(ChildProcess),
                        "name":
                        "Child Process",
                        "type":
                        "process",
                        "nodes": [{
                            "id": get_object_id(transition1),
                            "name": "action",
                            "type": "transition"
                        }, {
                            "id": get_object_id(transition2),
                            "name": "action",
                            "type": "transition"
                        }]
                    }]
                }]
            })
예제 #28
0
 class MyProcess(Process):
     transitions = [
         Transition('get_available_transition',
                    sources=['draft'],
                    target='valid')
     ]
예제 #29
0
 class MyProcess(Process):
     transitions = [
         Transition('validate', sources=['draft'], target='valid')
     ]