Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / quotaholder / commission.py @ 2b888e60

History | View | Annotate | Download (7.6 kB)

1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from astakos.quotaholder.exception import (
35
    NoCapacityError, NoStockError,
36
    NonImportedError, NoStockReleaseError, NonExportedError)
37

    
38

    
39
class Operation(object):
40

    
41
    @staticmethod
42
    def assertions(holding):
43
        assert(0 <= holding.imported_min)
44
        assert(holding.imported_min <= holding.imported_max)
45
        assert(0 <= holding.stock_min)
46
        assert(holding.stock_min <= holding.stock_max)
47

    
48
    @classmethod
49
    def _prepare(cls, holding, quantity, check=True):
50
        raise NotImplementedError
51

    
52
    @classmethod
53
    def prepare(cls, holding, quantity, check=True):
54
        cls.assertions(holding)
55
        cls._prepare(holding, quantity, check=True)
56

    
57
    @classmethod
58
    def _finalize(cls, holding, quantity):
59
        raise NotImplementedError
60

    
61
    @classmethod
62
    def finalize(cls, holding, quantity):
63
        cls.assertions(holding)
64
        cls._finalize(holding, quantity)
65

    
66
    @classmethod
67
    def undo(cls, holding, quantity):
68
        cls.prepare(holding, -quantity, check=False)
69

    
70
    @classmethod
71
    def revert(cls, holding, quantity):
72
        # Assertions do not hold when reverting
73
        cls._prepare(holding, -quantity, check=False)
74

    
75

    
76
class Import(Operation):
77

    
78
    @classmethod
79
    def _prepare(cls, holding, quantity, check=True):
80
        imported_max = holding.imported_max
81
        new_imported_max = imported_max + quantity
82

    
83
        capacity = holding.capacity
84
        if check and new_imported_max > capacity:
85
            holder = holding.holder
86
            resource = holding.resource
87
            m = ("%s has not enough capacity of %s." % (holder, resource))
88
            raise NoCapacityError(m,
89
                                  holder=holder,
90
                                  resource=resource,
91
                                  requested=quantity,
92
                                  current=imported_max,
93
                                  limit=capacity)
94

    
95
        holding.imported_max = new_imported_max
96
        holding.save()
97

    
98
    @classmethod
99
    def _finalize(cls, holding, quantity):
100
        holding.imported_min += quantity
101
        holding.stock_min += quantity
102
        holding.stock_max += quantity
103
        holding.save()
104

    
105

    
106
class Export(Operation):
107

    
108
    @classmethod
109
    def _prepare(cls, holding, quantity, check=True):
110
        stock_min = holding.stock_min
111
        new_stock_min = stock_min - quantity
112

    
113
        if check and new_stock_min < 0:
114
            holder = holding.holder
115
            resource = holding.resource
116
            m = ("%s has not enough stock of %s." % (holder, resource))
117
            raise NoStockError(m,
118
                               holder=holder,
119
                               resource=resource,
120
                               requested=quantity,
121
                               limit=stock_min)
122

    
123
        holding.stock_min = new_stock_min
124
        holding.save()
125

    
126
    @classmethod
127
    def _finalize(cls, holding, quantity):
128
        holding.stock_max -= quantity
129
        holding.save()
130

    
131

    
132
class Release(Operation):
133

    
134
    @classmethod
135
    def _prepare(cls, holding, quantity, check=True):
136
        imported_min = holding.imported_min
137
        new_imported_min = imported_min - quantity
138

    
139
        stock_min = holding.stock_min
140
        new_stock_min = stock_min - quantity
141
        stock_max = holding.stock_max
142
        new_stock_max = stock_max - quantity
143

    
144
        if check and new_imported_min < 0:
145
            holder = holding.holder
146
            resource = holding.resource
147
            m = ("%s attempts to release more %s than it contains." %
148
                 (holder, resource))
149
            raise NonImportedError(m,
150
                                   holder=holder,
151
                                   resource=resource,
152
                                   requested=quantity,
153
                                   limit=imported_min)
154

    
155
        if check and new_stock_min < 0:
156
            holder = holding.holder
157
            resource = holding.resource
158
            m = ("%s attempts to release %s that has been reexported." %
159
                 (holder, resource))
160
            raise NoStockReleaseError(m,
161
                                      holder=holder,
162
                                      resource=resource,
163
                                      requested=quantity,
164
                                      limit=stock_min)
165

    
166
        holding.imported_min = new_imported_min
167
        holding.stock_min = new_stock_min
168
        holding.stock_max = new_stock_max
169
        holding.save()
170

    
171
    @classmethod
172
    def _finalize(cls, holding, quantity):
173
        holding.imported_max -= quantity
174
        holding.save()
175

    
176

    
177
class Reclaim(Operation):
178

    
179
    @classmethod
180
    def _prepare(cls, holding, quantity, check=True):
181
        stock_max = holding.stock_max
182
        new_stock_max = stock_max + quantity
183

    
184
        imported_min = holding.imported_min
185
        if check and new_stock_max > imported_min:
186
            holder = holding.holder
187
            resource = holding.resource
188
            m = ("%s attempts to reclaim %s not originating by itself." %
189
                 (holder, resource))
190
            raise NonExportedError(m,
191
                                   holder=holder,
192
                                   resource=resource,
193
                                   requested=quantity,
194
                                   current=stock_max,
195
                                   limit=imported_min)
196

    
197
        holding.stock_max = new_stock_max
198
        holding.save()
199

    
200
    @classmethod
201
    def _finalize(cls, holding, quantity):
202
        holding.stock_min += quantity
203
        holding.save()
204

    
205

    
206
class Operations(object):
207
    def __init__(self):
208
        self.operations = []
209

    
210
    def prepare(self, operation, holding, quantity):
211
        operation.prepare(holding, quantity)
212
        self.operations.append((operation, holding, quantity))
213

    
214
    def finalize(self, operation, holding, quantity):
215
        operation.finalize(holding, quantity)
216
        self.operations.append((operation, holding, quantity))
217

    
218
    def undo(self, operation, holding, quantity):
219
        operation.undo(holding, quantity)
220
        self.operations.append((operation, holding, quantity))
221

    
222
    def revert(self):
223
        for (operation, holding, quantity) in self.operations:
224
            operation.revert(holding, quantity)