We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allocated line items should be computed while changing line quantity
A user makes an order for 5 items of the same product. 
Now we have this stock situation:  Quantity: 6,  Allocated:5

Go to the dashboard order page.
If we try to change the line quantity to 2-6 inside the dashboard we'll get an error: "Only 1 remaining in stock.".
The allocated line items should be added to the available stock.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `saleor/dashboard/order/forms.py`
Content:
```
1 from __future__ import unicode_literals
2 
3 from django import forms
4 from django.conf import settings
5 from django.shortcuts import get_object_or_404
6 from django.utils.translation import ugettext_lazy as _
7 from django.utils.translation import pgettext_lazy
8 from django_prices.forms import PriceField
9 from payments import PaymentError
10 from payments.models import PAYMENT_STATUS_CHOICES
11 from satchless.item import InsufficientStock
12 
13 from ...cart.forms import QuantityField
14 from ...discount.models import Voucher
15 from ...order import Status
16 from ...order.models import DeliveryGroup, Order, OrderedItem, OrderNote
17 from ...product.models import ProductVariant, Stock
18 
19 
20 class OrderNoteForm(forms.ModelForm):
21     class Meta:
22         model = OrderNote
23         fields = ['content']
24         widgets = {'content': forms.Textarea({
25             'rows': 5, 'placeholder': _('Note')})}
26 
27     def __init__(self, *args, **kwargs):
28         super(OrderNoteForm, self).__init__(*args, **kwargs)
29 
30 
31 class ManagePaymentForm(forms.Form):
32     amount = PriceField(max_digits=12, decimal_places=2,
33                         currency=settings.DEFAULT_CURRENCY)
34 
35     def __init__(self, *args, **kwargs):
36         self.payment = kwargs.pop('payment')
37         super(ManagePaymentForm, self).__init__(*args, **kwargs)
38 
39 
40 class CapturePaymentForm(ManagePaymentForm):
41     def clean(self):
42         if self.payment.status != 'preauth':
43             raise forms.ValidationError(
44                 _('Only pre-authorized payments can be captured'))
45 
46     def capture(self):
47         amount = self.cleaned_data['amount']
48         try:
49             self.payment.capture(amount.gross)
50         except (PaymentError, ValueError) as e:
51             self.add_error(None, _('Payment gateway error: %s') % e.message)
52             return False
53         return True
54 
55 
56 class RefundPaymentForm(ManagePaymentForm):
57     def clean(self):
58         if self.payment.status != 'confirmed':
59             raise forms.ValidationError(
60                 _('Only confirmed payments can be refunded'))
61 
62     def refund(self):
63         amount = self.cleaned_data['amount']
64         try:
65             self.payment.refund(amount.gross)
66         except (PaymentError, ValueError) as e:
67             self.add_error(None, _('Payment gateway error: %s') % e.message)
68             return False
69         return True
70 
71 
72 class ReleasePaymentForm(forms.Form):
73     def __init__(self, *args, **kwargs):
74         self.payment = kwargs.pop('payment')
75         super(ReleasePaymentForm, self).__init__(*args, **kwargs)
76 
77     def clean(self):
78         if self.payment.status != 'preauth':
79             raise forms.ValidationError(
80                 _('Only pre-authorized payments can be released'))
81 
82     def release(self):
83         try:
84             self.payment.release()
85         except (PaymentError, ValueError) as e:
86             self.add_error(None, _('Payment gateway error: %s') % e.message)
87             return False
88         return True
89 
90 
91 class MoveItemsForm(forms.Form):
92     quantity = QuantityField(label=_('Quantity'))
93     target_group = forms.ChoiceField(label=_('Target shipment'))
94 
95     def __init__(self, *args, **kwargs):
96         self.item = kwargs.pop('item')
97         super(MoveItemsForm, self).__init__(*args, **kwargs)
98         self.fields['quantity'].widget.attrs.update({
99             'max': self.item.quantity, 'min': 1})
100         self.fields['target_group'].choices = self.get_delivery_group_choices()
101 
102     def get_delivery_group_choices(self):
103         group = self.item.delivery_group
104         groups = group.order.groups.exclude(pk=group.pk).exclude(
105             status='cancelled')
106         choices = [('new', _('New shipment'))]
107         choices.extend([(g.pk, str(g)) for g in groups])
108         return choices
109 
110     def move_items(self):
111         how_many = self.cleaned_data['quantity']
112         choice = self.cleaned_data['target_group']
113         old_group = self.item.delivery_group
114         if choice == 'new':
115             # For new group we use the same delivery name but zero price
116             target_group = old_group.order.groups.create(
117                 status=old_group.status,
118                 shipping_method_name=old_group.shipping_method_name)
119         else:
120             target_group = DeliveryGroup.objects.get(pk=choice)
121         OrderedItem.objects.move_to_group(self.item, target_group, how_many)
122         return target_group
123 
124 
125 class CancelItemsForm(forms.Form):
126 
127     def __init__(self, *args, **kwargs):
128         self.item = kwargs.pop('item')
129         super(CancelItemsForm, self).__init__(*args, **kwargs)
130 
131     def cancel_item(self):
132         if self.item.stock:
133             Stock.objects.deallocate_stock(self.item.stock, self.item.quantity)
134         order = self.item.delivery_group.order
135         OrderedItem.objects.remove_empty_groups(self.item, force=True)
136         Order.objects.recalculate_order(order)
137 
138 
139 class ChangeQuantityForm(forms.ModelForm):
140     class Meta:
141         model = OrderedItem
142         fields = ['quantity']
143 
144     def __init__(self, *args, **kwargs):
145         super(ChangeQuantityForm, self).__init__(*args, **kwargs)
146         self.initial_quantity = self.instance.quantity
147         self.fields['quantity'].widget.attrs.update({'min': 1})
148         self.fields['quantity'].initial = self.initial_quantity
149 
150     def clean_quantity(self):
151         quantity = self.cleaned_data['quantity']
152         variant = get_object_or_404(
153             ProductVariant, sku=self.instance.product_sku)
154         try:
155             variant.check_quantity(quantity)
156         except InsufficientStock as e:
157             raise forms.ValidationError(
158                 _('Only %(remaining)d remaining in stock.') % {
159                     'remaining': e.item.get_stock_quantity()})
160         return quantity
161 
162     def save(self):
163         quantity = self.cleaned_data['quantity']
164         stock = self.instance.stock
165         if stock is not None:
166             # update stock allocation
167             delta = quantity - self.initial_quantity
168             Stock.objects.allocate_stock(stock, delta)
169         self.instance.change_quantity(quantity)
170         Order.objects.recalculate_order(self.instance.delivery_group.order)
171 
172 
173 class ShipGroupForm(forms.ModelForm):
174     class Meta:
175         model = DeliveryGroup
176         fields = ['tracking_number']
177 
178     def __init__(self, *args, **kwargs):
179         super(ShipGroupForm, self).__init__(*args, **kwargs)
180         self.fields['tracking_number'].widget.attrs.update(
181             {'placeholder': _('Parcel tracking number')})
182 
183     def clean(self):
184         if self.instance.status != 'new':
185             raise forms.ValidationError(_('Cannot ship this group'),
186                                         code='invalid')
187 
188     def save(self):
189         order = self.instance.order
190         for line in self.instance.items.all():
191             stock = line.stock
192             if stock is not None:
193                 # remove and deallocate quantity
194                 Stock.objects.decrease_stock(stock, line.quantity)
195         self.instance.change_status('shipped')
196         statuses = [g.status for g in order.groups.all()]
197         if 'shipped' in statuses and 'new' not in statuses:
198             order.change_status('shipped')
199 
200 
201 class CancelGroupForm(forms.Form):
202     def __init__(self, *args, **kwargs):
203         self.delivery_group = kwargs.pop('delivery_group')
204         super(CancelGroupForm, self).__init__(*args, **kwargs)
205 
206     def cancel_group(self):
207         for line in self.delivery_group:
208             if line.stock:
209                 Stock.objects.deallocate_stock(line.stock, line.quantity)
210         self.delivery_group.status = Status.CANCELLED
211         self.delivery_group.save()
212         other_groups = self.delivery_group.order.groups.all()
213         statuses = set(other_groups.values_list('status', flat=True))
214         if statuses == {Status.CANCELLED}:
215             # Cancel whole order
216             self.delivery_group.order.status = Status.CANCELLED
217             self.delivery_group.order.save(update_fields=['status'])
218 
219 
220 class CancelOrderForm(forms.Form):
221 
222     def __init__(self, *args, **kwargs):
223         self.order = kwargs.pop('order')
224         super(CancelOrderForm, self).__init__(*args, **kwargs)
225 
226     def clean(self):
227         data = super(CancelOrderForm, self).clean()
228         if not self.order.can_cancel():
229             raise forms.ValidationError(_('This order can\'t be cancelled'))
230         return data
231 
232     def cancel_order(self):
233         for group in self.order.groups.all():
234             group_form = CancelGroupForm(delivery_group=group)
235             group_form.cancel_group()
236 
237 
238 class RemoveVoucherForm(forms.Form):
239 
240     def __init__(self, *args, **kwargs):
241         self.order = kwargs.pop('order')
242         super(RemoveVoucherForm, self).__init__(*args, **kwargs)
243 
244     def clean(self):
245         data = super(RemoveVoucherForm, self).clean()
246         if not self.order.voucher:
247             raise forms.ValidationError(_('This order has no voucher'))
248         return data
249 
250     def remove_voucher(self):
251         self.order.discount_amount = 0
252         self.order.discount_name = ''
253         voucher = self.order.voucher
254         Voucher.objects.decrease_usage(voucher)
255         self.order.voucher = None
256         Order.objects.recalculate_order(self.order)
257 
258 ORDER_STATUS_CHOICES = [('', pgettext_lazy('Order status field value',
259                                            'All'))] + Status.CHOICES
260 
261 PAYMENT_STATUS_CHOICES = (('', pgettext_lazy('Payment status field value',
262                                              'All')),) + PAYMENT_STATUS_CHOICES
263 
264 
265 class OrderFilterForm(forms.Form):
266     status = forms.ChoiceField(choices=ORDER_STATUS_CHOICES)
267 
268 
269 class PaymentFilterForm(forms.Form):
270     status = forms.ChoiceField(choices=PAYMENT_STATUS_CHOICES)
271
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/saleor/dashboard/order/forms.py b/saleor/dashboard/order/forms.py
--- a/saleor/dashboard/order/forms.py
+++ b/saleor/dashboard/order/forms.py
@@ -149,10 +149,11 @@
 
     def clean_quantity(self):
         quantity = self.cleaned_data['quantity']
+        delta = quantity - self.initial_quantity
         variant = get_object_or_404(
             ProductVariant, sku=self.instance.product_sku)
         try:
-            variant.check_quantity(quantity)
+            variant.check_quantity(delta)
         except InsufficientStock as e:
             raise forms.ValidationError(
                 _('Only %(remaining)d remaining in stock.') % {

{"golden_diff": "diff --git a/saleor/dashboard/order/forms.py b/saleor/dashboard/order/forms.py\n--- a/saleor/dashboard/order/forms.py\n+++ b/saleor/dashboard/order/forms.py\n@@ -149,10 +149,11 @@\n \n     def clean_quantity(self):\n         quantity = self.cleaned_data['quantity']\n+        delta = quantity - self.initial_quantity\n         variant = get_object_or_404(\n             ProductVariant, sku=self.instance.product_sku)\n         try:\n-            variant.check_quantity(quantity)\n+            variant.check_quantity(delta)\n         except InsufficientStock as e:\n             raise forms.ValidationError(\n                 _('Only %(remaining)d remaining in stock.') % {\n", "issue": "Allocated line items should be computed while changing line quantity\nA user makes an order for 5 items of the same product. \nNow we have this stock situation:  Quantity: 6,  Allocated:5\n\nGo to the dashboard order page.\nIf we try to change the line quantity to 2-6 inside the dashboard we'll get an error: \"Only 1 remaining in stock.\".\nThe allocated line items should be added to the available stock.\n\n", "before_files": [{"content": "from __future__ import unicode_literals\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.shortcuts import get_object_or_404\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.utils.translation import pgettext_lazy\nfrom django_prices.forms import PriceField\nfrom payments import PaymentError\nfrom payments.models import PAYMENT_STATUS_CHOICES\nfrom satchless.item import InsufficientStock\n\nfrom ...cart.forms import QuantityField\nfrom ...discount.models import Voucher\nfrom ...order import Status\nfrom ...order.models import DeliveryGroup, Order, OrderedItem, OrderNote\nfrom ...product.models import ProductVariant, Stock\n\n\nclass OrderNoteForm(forms.ModelForm):\n    class Meta:\n        model = OrderNote\n        fields = ['content']\n        widgets = {'content': forms.Textarea({\n            'rows': 5, 'placeholder': _('Note')})}\n\n    def __init__(self, *args, **kwargs):\n        super(OrderNoteForm, self).__init__(*args, **kwargs)\n\n\nclass ManagePaymentForm(forms.Form):\n    amount = PriceField(max_digits=12, decimal_places=2,\n                        currency=settings.DEFAULT_CURRENCY)\n\n    def __init__(self, *args, **kwargs):\n        self.payment = kwargs.pop('payment')\n        super(ManagePaymentForm, self).__init__(*args, **kwargs)\n\n\nclass CapturePaymentForm(ManagePaymentForm):\n    def clean(self):\n        if self.payment.status != 'preauth':\n            raise forms.ValidationError(\n                _('Only pre-authorized payments can be captured'))\n\n    def capture(self):\n        amount = self.cleaned_data['amount']\n        try:\n            self.payment.capture(amount.gross)\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass RefundPaymentForm(ManagePaymentForm):\n    def clean(self):\n        if self.payment.status != 'confirmed':\n            raise forms.ValidationError(\n                _('Only confirmed payments can be refunded'))\n\n    def refund(self):\n        amount = self.cleaned_data['amount']\n        try:\n            self.payment.refund(amount.gross)\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass ReleasePaymentForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        self.payment = kwargs.pop('payment')\n        super(ReleasePaymentForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        if self.payment.status != 'preauth':\n            raise forms.ValidationError(\n                _('Only pre-authorized payments can be released'))\n\n    def release(self):\n        try:\n            self.payment.release()\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass MoveItemsForm(forms.Form):\n    quantity = QuantityField(label=_('Quantity'))\n    target_group = forms.ChoiceField(label=_('Target shipment'))\n\n    def __init__(self, *args, **kwargs):\n        self.item = kwargs.pop('item')\n        super(MoveItemsForm, self).__init__(*args, **kwargs)\n        self.fields['quantity'].widget.attrs.update({\n            'max': self.item.quantity, 'min': 1})\n        self.fields['target_group'].choices = self.get_delivery_group_choices()\n\n    def get_delivery_group_choices(self):\n        group = self.item.delivery_group\n        groups = group.order.groups.exclude(pk=group.pk).exclude(\n            status='cancelled')\n        choices = [('new', _('New shipment'))]\n        choices.extend([(g.pk, str(g)) for g in groups])\n        return choices\n\n    def move_items(self):\n        how_many = self.cleaned_data['quantity']\n        choice = self.cleaned_data['target_group']\n        old_group = self.item.delivery_group\n        if choice == 'new':\n            # For new group we use the same delivery name but zero price\n            target_group = old_group.order.groups.create(\n                status=old_group.status,\n                shipping_method_name=old_group.shipping_method_name)\n        else:\n            target_group = DeliveryGroup.objects.get(pk=choice)\n        OrderedItem.objects.move_to_group(self.item, target_group, how_many)\n        return target_group\n\n\nclass CancelItemsForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.item = kwargs.pop('item')\n        super(CancelItemsForm, self).__init__(*args, **kwargs)\n\n    def cancel_item(self):\n        if self.item.stock:\n            Stock.objects.deallocate_stock(self.item.stock, self.item.quantity)\n        order = self.item.delivery_group.order\n        OrderedItem.objects.remove_empty_groups(self.item, force=True)\n        Order.objects.recalculate_order(order)\n\n\nclass ChangeQuantityForm(forms.ModelForm):\n    class Meta:\n        model = OrderedItem\n        fields = ['quantity']\n\n    def __init__(self, *args, **kwargs):\n        super(ChangeQuantityForm, self).__init__(*args, **kwargs)\n        self.initial_quantity = self.instance.quantity\n        self.fields['quantity'].widget.attrs.update({'min': 1})\n        self.fields['quantity'].initial = self.initial_quantity\n\n    def clean_quantity(self):\n        quantity = self.cleaned_data['quantity']\n        variant = get_object_or_404(\n            ProductVariant, sku=self.instance.product_sku)\n        try:\n            variant.check_quantity(quantity)\n        except InsufficientStock as e:\n            raise forms.ValidationError(\n                _('Only %(remaining)d remaining in stock.') % {\n                    'remaining': e.item.get_stock_quantity()})\n        return quantity\n\n    def save(self):\n        quantity = self.cleaned_data['quantity']\n        stock = self.instance.stock\n        if stock is not None:\n            # update stock allocation\n            delta = quantity - self.initial_quantity\n            Stock.objects.allocate_stock(stock, delta)\n        self.instance.change_quantity(quantity)\n        Order.objects.recalculate_order(self.instance.delivery_group.order)\n\n\nclass ShipGroupForm(forms.ModelForm):\n    class Meta:\n        model = DeliveryGroup\n        fields = ['tracking_number']\n\n    def __init__(self, *args, **kwargs):\n        super(ShipGroupForm, self).__init__(*args, **kwargs)\n        self.fields['tracking_number'].widget.attrs.update(\n            {'placeholder': _('Parcel tracking number')})\n\n    def clean(self):\n        if self.instance.status != 'new':\n            raise forms.ValidationError(_('Cannot ship this group'),\n                                        code='invalid')\n\n    def save(self):\n        order = self.instance.order\n        for line in self.instance.items.all():\n            stock = line.stock\n            if stock is not None:\n                # remove and deallocate quantity\n                Stock.objects.decrease_stock(stock, line.quantity)\n        self.instance.change_status('shipped')\n        statuses = [g.status for g in order.groups.all()]\n        if 'shipped' in statuses and 'new' not in statuses:\n            order.change_status('shipped')\n\n\nclass CancelGroupForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        self.delivery_group = kwargs.pop('delivery_group')\n        super(CancelGroupForm, self).__init__(*args, **kwargs)\n\n    def cancel_group(self):\n        for line in self.delivery_group:\n            if line.stock:\n                Stock.objects.deallocate_stock(line.stock, line.quantity)\n        self.delivery_group.status = Status.CANCELLED\n        self.delivery_group.save()\n        other_groups = self.delivery_group.order.groups.all()\n        statuses = set(other_groups.values_list('status', flat=True))\n        if statuses == {Status.CANCELLED}:\n            # Cancel whole order\n            self.delivery_group.order.status = Status.CANCELLED\n            self.delivery_group.order.save(update_fields=['status'])\n\n\nclass CancelOrderForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.order = kwargs.pop('order')\n        super(CancelOrderForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        data = super(CancelOrderForm, self).clean()\n        if not self.order.can_cancel():\n            raise forms.ValidationError(_('This order can\\'t be cancelled'))\n        return data\n\n    def cancel_order(self):\n        for group in self.order.groups.all():\n            group_form = CancelGroupForm(delivery_group=group)\n            group_form.cancel_group()\n\n\nclass RemoveVoucherForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.order = kwargs.pop('order')\n        super(RemoveVoucherForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        data = super(RemoveVoucherForm, self).clean()\n        if not self.order.voucher:\n            raise forms.ValidationError(_('This order has no voucher'))\n        return data\n\n    def remove_voucher(self):\n        self.order.discount_amount = 0\n        self.order.discount_name = ''\n        voucher = self.order.voucher\n        Voucher.objects.decrease_usage(voucher)\n        self.order.voucher = None\n        Order.objects.recalculate_order(self.order)\n\nORDER_STATUS_CHOICES = [('', pgettext_lazy('Order status field value',\n                                           'All'))] + Status.CHOICES\n\nPAYMENT_STATUS_CHOICES = (('', pgettext_lazy('Payment status field value',\n                                             'All')),) + PAYMENT_STATUS_CHOICES\n\n\nclass OrderFilterForm(forms.Form):\n    status = forms.ChoiceField(choices=ORDER_STATUS_CHOICES)\n\n\nclass PaymentFilterForm(forms.Form):\n    status = forms.ChoiceField(choices=PAYMENT_STATUS_CHOICES)\n", "path": "saleor/dashboard/order/forms.py"}], "after_files": [{"content": "from __future__ import unicode_literals\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.shortcuts import get_object_or_404\nfrom django.utils.translation import ugettext_lazy as _\nfrom django.utils.translation import pgettext_lazy\nfrom django_prices.forms import PriceField\nfrom payments import PaymentError\nfrom payments.models import PAYMENT_STATUS_CHOICES\nfrom satchless.item import InsufficientStock\n\nfrom ...cart.forms import QuantityField\nfrom ...discount.models import Voucher\nfrom ...order import Status\nfrom ...order.models import DeliveryGroup, Order, OrderedItem, OrderNote\nfrom ...product.models import ProductVariant, Stock\n\n\nclass OrderNoteForm(forms.ModelForm):\n    class Meta:\n        model = OrderNote\n        fields = ['content']\n        widgets = {'content': forms.Textarea({\n            'rows': 5, 'placeholder': _('Note')})}\n\n    def __init__(self, *args, **kwargs):\n        super(OrderNoteForm, self).__init__(*args, **kwargs)\n\n\nclass ManagePaymentForm(forms.Form):\n    amount = PriceField(max_digits=12, decimal_places=2,\n                        currency=settings.DEFAULT_CURRENCY)\n\n    def __init__(self, *args, **kwargs):\n        self.payment = kwargs.pop('payment')\n        super(ManagePaymentForm, self).__init__(*args, **kwargs)\n\n\nclass CapturePaymentForm(ManagePaymentForm):\n    def clean(self):\n        if self.payment.status != 'preauth':\n            raise forms.ValidationError(\n                _('Only pre-authorized payments can be captured'))\n\n    def capture(self):\n        amount = self.cleaned_data['amount']\n        try:\n            self.payment.capture(amount.gross)\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass RefundPaymentForm(ManagePaymentForm):\n    def clean(self):\n        if self.payment.status != 'confirmed':\n            raise forms.ValidationError(\n                _('Only confirmed payments can be refunded'))\n\n    def refund(self):\n        amount = self.cleaned_data['amount']\n        try:\n            self.payment.refund(amount.gross)\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass ReleasePaymentForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        self.payment = kwargs.pop('payment')\n        super(ReleasePaymentForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        if self.payment.status != 'preauth':\n            raise forms.ValidationError(\n                _('Only pre-authorized payments can be released'))\n\n    def release(self):\n        try:\n            self.payment.release()\n        except (PaymentError, ValueError) as e:\n            self.add_error(None, _('Payment gateway error: %s') % e.message)\n            return False\n        return True\n\n\nclass MoveItemsForm(forms.Form):\n    quantity = QuantityField(label=_('Quantity'))\n    target_group = forms.ChoiceField(label=_('Target shipment'))\n\n    def __init__(self, *args, **kwargs):\n        self.item = kwargs.pop('item')\n        super(MoveItemsForm, self).__init__(*args, **kwargs)\n        self.fields['quantity'].widget.attrs.update({\n            'max': self.item.quantity, 'min': 1})\n        self.fields['target_group'].choices = self.get_delivery_group_choices()\n\n    def get_delivery_group_choices(self):\n        group = self.item.delivery_group\n        groups = group.order.groups.exclude(pk=group.pk).exclude(\n            status='cancelled')\n        choices = [('new', _('New shipment'))]\n        choices.extend([(g.pk, str(g)) for g in groups])\n        return choices\n\n    def move_items(self):\n        how_many = self.cleaned_data['quantity']\n        choice = self.cleaned_data['target_group']\n        old_group = self.item.delivery_group\n        if choice == 'new':\n            # For new group we use the same delivery name but zero price\n            target_group = old_group.order.groups.create(\n                status=old_group.status,\n                shipping_method_name=old_group.shipping_method_name)\n        else:\n            target_group = DeliveryGroup.objects.get(pk=choice)\n        OrderedItem.objects.move_to_group(self.item, target_group, how_many)\n        return target_group\n\n\nclass CancelItemsForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.item = kwargs.pop('item')\n        super(CancelItemsForm, self).__init__(*args, **kwargs)\n\n    def cancel_item(self):\n        if self.item.stock:\n            Stock.objects.deallocate_stock(self.item.stock, self.item.quantity)\n        order = self.item.delivery_group.order\n        OrderedItem.objects.remove_empty_groups(self.item, force=True)\n        Order.objects.recalculate_order(order)\n\n\nclass ChangeQuantityForm(forms.ModelForm):\n    class Meta:\n        model = OrderedItem\n        fields = ['quantity']\n\n    def __init__(self, *args, **kwargs):\n        super(ChangeQuantityForm, self).__init__(*args, **kwargs)\n        self.initial_quantity = self.instance.quantity\n        self.fields['quantity'].widget.attrs.update({'min': 1})\n        self.fields['quantity'].initial = self.initial_quantity\n\n    def clean_quantity(self):\n        quantity = self.cleaned_data['quantity']\n        delta = quantity - self.initial_quantity\n        variant = get_object_or_404(\n            ProductVariant, sku=self.instance.product_sku)\n        try:\n            variant.check_quantity(delta)\n        except InsufficientStock as e:\n            raise forms.ValidationError(\n                _('Only %(remaining)d remaining in stock.') % {\n                    'remaining': e.item.get_stock_quantity()})\n        return quantity\n\n    def save(self):\n        quantity = self.cleaned_data['quantity']\n        stock = self.instance.stock\n        if stock is not None:\n            # update stock allocation\n            delta = quantity - self.initial_quantity\n            Stock.objects.allocate_stock(stock, delta)\n        self.instance.change_quantity(quantity)\n        Order.objects.recalculate_order(self.instance.delivery_group.order)\n\n\nclass ShipGroupForm(forms.ModelForm):\n    class Meta:\n        model = DeliveryGroup\n        fields = ['tracking_number']\n\n    def __init__(self, *args, **kwargs):\n        super(ShipGroupForm, self).__init__(*args, **kwargs)\n        self.fields['tracking_number'].widget.attrs.update(\n            {'placeholder': _('Parcel tracking number')})\n\n    def clean(self):\n        if self.instance.status != 'new':\n            raise forms.ValidationError(_('Cannot ship this group'),\n                                        code='invalid')\n\n    def save(self):\n        order = self.instance.order\n        for line in self.instance.items.all():\n            stock = line.stock\n            if stock is not None:\n                # remove and deallocate quantity\n                Stock.objects.decrease_stock(stock, line.quantity)\n        self.instance.change_status('shipped')\n        statuses = [g.status for g in order.groups.all()]\n        if 'shipped' in statuses and 'new' not in statuses:\n            order.change_status('shipped')\n\n\nclass CancelGroupForm(forms.Form):\n    def __init__(self, *args, **kwargs):\n        self.delivery_group = kwargs.pop('delivery_group')\n        super(CancelGroupForm, self).__init__(*args, **kwargs)\n\n    def cancel_group(self):\n        for line in self.delivery_group:\n            if line.stock:\n                Stock.objects.deallocate_stock(line.stock, line.quantity)\n        self.delivery_group.status = Status.CANCELLED\n        self.delivery_group.save()\n        other_groups = self.delivery_group.order.groups.all()\n        statuses = set(other_groups.values_list('status', flat=True))\n        if statuses == {Status.CANCELLED}:\n            # Cancel whole order\n            self.delivery_group.order.status = Status.CANCELLED\n            self.delivery_group.order.save(update_fields=['status'])\n\n\nclass CancelOrderForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.order = kwargs.pop('order')\n        super(CancelOrderForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        data = super(CancelOrderForm, self).clean()\n        if not self.order.can_cancel():\n            raise forms.ValidationError(_('This order can\\'t be cancelled'))\n        return data\n\n    def cancel_order(self):\n        for group in self.order.groups.all():\n            group_form = CancelGroupForm(delivery_group=group)\n            group_form.cancel_group()\n\n\nclass RemoveVoucherForm(forms.Form):\n\n    def __init__(self, *args, **kwargs):\n        self.order = kwargs.pop('order')\n        super(RemoveVoucherForm, self).__init__(*args, **kwargs)\n\n    def clean(self):\n        data = super(RemoveVoucherForm, self).clean()\n        if not self.order.voucher:\n            raise forms.ValidationError(_('This order has no voucher'))\n        return data\n\n    def remove_voucher(self):\n        self.order.discount_amount = 0\n        self.order.discount_name = ''\n        voucher = self.order.voucher\n        Voucher.objects.decrease_usage(voucher)\n        self.order.voucher = None\n        Order.objects.recalculate_order(self.order)\n\nORDER_STATUS_CHOICES = [('', pgettext_lazy('Order status field value',\n                                           'All'))] + Status.CHOICES\n\nPAYMENT_STATUS_CHOICES = (('', pgettext_lazy('Payment status field value',\n                                             'All')),) + PAYMENT_STATUS_CHOICES\n\n\nclass OrderFilterForm(forms.Form):\n    status = forms.ChoiceField(choices=ORDER_STATUS_CHOICES)\n\n\nclass PaymentFilterForm(forms.Form):\n    status = forms.ChoiceField(choices=PAYMENT_STATUS_CHOICES)\n", "path": "saleor/dashboard/order/forms.py"}]}