internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: saleor/saleor

Issue:
Promotional code field and button overlap each other.
In the checkout process:
<img width="465" alt="zrzut ekranu 2018-01-10 o 10 02 22" src="https://user-images.githubusercontent.com/1561204/34765559-24865056-f5f2-11e7-9e2a-d0ff639e7a79.png">



Discussion:

Resolving patch:
diff --git a/saleor/discount/forms.py b/saleor/discount/forms.py
--- a/saleor/discount/forms.py
+++ b/saleor/discount/forms.py
@@ -21,7 +21,7 @@ class CheckoutDiscountForm(forms.Form):
     voucher = VoucherField(
         queryset=Voucher.objects.none(),
         to_field_name='code',
-        label=pgettext_lazy(
+        help_text=pgettext_lazy(
             'Checkout discount form label for voucher field',
             'Gift card or discount code'),
         widget=forms.TextInput)


Test patch:
Repository: saleor/saleor

Issue:
Order notes is created with with empty content
When going through checkout and not filling the "Order note", it gets created anyway with an empty text. Probably the reason is this check in `create_order` function:
```
if self.note is not None:
    order.notes.create(user=order.user, content=self.note)
```



Discussion:
We should probably also strip the field before checking if it's empty to avoid storing notes consisting of nothing but whitespace.

Resolving patch:
diff --git a/saleor/checkout/core.py b/saleor/checkout/core.py
--- a/saleor/checkout/core.py
+++ b/saleor/checkout/core.py
@@ -341,7 +341,7 @@ def create_order(self):
         if voucher is not None:
             increase_voucher_usage(voucher)
 
-        if self.note is not None:
+        if self.note is not None and self.note:
             order.notes.create(user=order.user, content=self.note)
 
         return order
diff --git a/saleor/checkout/forms.py b/saleor/checkout/forms.py
--- a/saleor/checkout/forms.py
+++ b/saleor/checkout/forms.py
@@ -118,7 +118,7 @@ class AnonymousUserBillingForm(forms.Form):
 class NoteForm(forms.Form):
     """ Form to add a note to an order as it is
     created for shop staff to see """
-    note = forms.CharField(max_length=250, required=False)
+    note = forms.CharField(max_length=250, required=False, strip=True)
 
     def __init__(self, *args, **kwargs):
         self.checkout = kwargs.pop('checkout', None)


Test patch:
diff --git a/tests/test_checkout.py b/tests/test_checkout.py
--- a/tests/test_checkout.py
+++ b/tests/test_checkout.py
@@ -228,17 +228,23 @@ def test_checkout_create_order_insufficient_stock(
         checkout.create_order()
 
 
-def test_note_form():
+@pytest.mark.parametrize('note_value', [
+    '', '    ', '   test_note  ','test_note'
+])
+def test_note_form(note_value):
     checkout = Checkout(Mock(), AnonymousUser(), 'tracking_code')
-    form = NoteForm({'note': 'test_note'}, checkout=checkout)
+    form = NoteForm({'note': note_value}, checkout=checkout)
     form.is_valid()
     form.set_checkout_note()
-    assert checkout.note == 'test_note'
+    assert checkout.note == note_value.strip()
 
 
 def test_note_in_created_order(request_cart, customer_user, billing_address):
     customer_user.default_billing_address = billing_address
     checkout = Checkout(request_cart, customer_user, 'tracking_code')
+    checkout.note = ''
+    order = checkout.create_order()
+    assert not order.notes.all()
     checkout.note = 'test_note'
     order = checkout.create_order()
     assert order.notes.values()[0].get('content') == 'test_note'
Repository: saleor/saleor

Issue:
Refactor passing possible sort_by fields to the category page
Currently, we have a function `get_sort_by_choices`, that constructs sort_by choices from product filter object. I think this could be done much simpler, by using `saleor.product.filters.SORT_BY_FIELDS`, which already have the field names and translated labels that should be displayed in the UI.


Discussion:

Resolving patch:
diff --git a/saleor/core/utils/filters.py b/saleor/core/utils/filters.py
--- a/saleor/core/utils/filters.py
+++ b/saleor/core/utils/filters.py
@@ -1,8 +1,3 @@
-def get_sort_by_choices(filter_set):
-    return [(choice[0], choice[1].lower()) for choice in
-            list(filter_set.filters['sort_by'].field.choices)[1::2]]
-
-
 def get_now_sorted_by(filter_set, default_sort='name'):
     sort_by = filter_set.form.cleaned_data.get('sort_by')
     if sort_by:
diff --git a/saleor/product/filters.py b/saleor/product/filters.py
--- a/saleor/product/filters.py
+++ b/saleor/product/filters.py
@@ -8,9 +8,10 @@
 from ..core.filters import SortedFilterSet
 from .models import Product, ProductAttribute
 
-SORT_BY_FIELDS = {
-    'name': pgettext_lazy('Product list sorting option', 'name'),
-    'price': pgettext_lazy('Product list sorting option', 'price')}
+
+SORT_BY_FIELDS = OrderedDict([
+    ('name', pgettext_lazy('Product list sorting option', 'name')),
+    ('price', pgettext_lazy('Product list sorting option', 'price'))])
 
 
 class ProductFilter(SortedFilterSet):
diff --git a/saleor/product/views.py b/saleor/product/views.py
--- a/saleor/product/views.py
+++ b/saleor/product/views.py
@@ -9,7 +9,7 @@
 
 from ..cart.utils import set_cart_cookie
 from ..core.utils import get_paginator_items, serialize_decimal
-from ..core.utils.filters import get_now_sorted_by, get_sort_by_choices
+from ..core.utils.filters import get_now_sorted_by
 from .filters import ProductFilter, SORT_BY_FIELDS
 from .models import Category
 from .utils import (
@@ -129,7 +129,7 @@ def category_index(request, path, category_id):
     ctx = {'category': category, 'filter_set': product_filter,
            'products': products_and_availability,
            'products_paginated': products_paginated,
-           'sort_by_choices': get_sort_by_choices(product_filter),
+           'sort_by_choices': SORT_BY_FIELDS,
            'now_sorted_by': now_sorted_by,
            'is_descending': is_descending}
     return TemplateResponse(request, 'category/index.html', ctx)


Test patch:
Repository: saleor/saleor

Issue:
Move AJAX Select2 fields to dashboard
Our custom AJAX Select2 fields sitting in `saleor/core/forms` are only used in the dashboard. If I'm correct they're also adjusted to match the Material Design style. Therefore, they should be moved from `saleor/core` to `saleor/dashboard/forms`.


Discussion:

Resolving patch:
diff --git a/saleor/dashboard/discount/forms.py b/saleor/dashboard/discount/forms.py
--- a/saleor/dashboard/discount/forms.py
+++ b/saleor/dashboard/discount/forms.py
@@ -6,12 +6,12 @@
 from django.utils.translation import pgettext_lazy
 from django_prices.forms import PriceField
 
-from ...core.forms import (
-    AjaxSelect2ChoiceField, AjaxSelect2MultipleChoiceField)
 from ...discount import DiscountValueType, VoucherApplyToProduct
 from ...discount.models import Sale, Voucher
 from ...product.models import Product
 from ...shipping.models import ShippingMethodCountry, COUNTRY_CODE_CHOICES
+from ..forms import (
+    AjaxSelect2ChoiceField, AjaxSelect2MultipleChoiceField)
 
 
 class SaleForm(forms.ModelForm):
diff --git a/saleor/core/forms.py b/saleor/dashboard/forms.py
similarity index 98%
rename from saleor/core/forms.py
rename to saleor/dashboard/forms.py
--- a/saleor/core/forms.py
+++ b/saleor/dashboard/forms.py
@@ -1,6 +1,7 @@
 import json
 
 from django import forms
+from django.core.exceptions import ValidationError
 
 
 class AjaxSelect2ChoiceField(forms.ChoiceField):
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
@@ -7,9 +7,7 @@
 from payments import PaymentError, PaymentStatus
 from satchless.item import InsufficientStock
 
-from ..widgets import PhonePrefixWidget
 from ...cart.forms import QuantityField
-from ...core.forms import AjaxSelect2ChoiceField
 from ...discount.utils import decrease_voucher_usage
 from ...order import GroupStatus
 from ...order.models import DeliveryGroup, OrderLine, OrderNote
@@ -19,8 +17,10 @@
     recalculate_order, remove_empty_groups)
 from ...product.models import Product, ProductVariant, Stock
 from ...product.utils import allocate_stock, deallocate_stock
-from ...userprofile.i18n import (AddressForm as StorefrontAddressForm,
-                                 PossiblePhoneNumberFormField)
+from ...userprofile.i18n import (
+    AddressForm as StorefrontAddressForm, PossiblePhoneNumberFormField)
+from ..forms import AjaxSelect2ChoiceField
+from ..widgets import PhonePrefixWidget
 
 
 class OrderNoteForm(forms.ModelForm):


Test patch:
Repository: saleor/saleor

Issue:
Improve generating prices in the populatedb script
We should improve the random data generator to produce more meaningful prices. The problem is that we first generate random prices for products that are later overridden in variants in the `price_override` field. As a result, variant prices may vary significantly within a single product, which makes no much sense. Example situation:

Product Briggs, Williams and Bradley - $85,36
Variants:
- 1 kg - $184.84
- 500g - $150.08
- 250g - $144.46

I think there is no much interest in generating the `price_override` field at all and I'd drop that.


Discussion:
In case of coffee we could maybe use the override to provide prices for 500g and 1kg variants. For t-shirts it does not make sense to use the override.

Resolving patch:
diff --git a/saleor/core/utils/random_data.py b/saleor/core/utils/random_data.py
--- a/saleor/core/utils/random_data.py
+++ b/saleor/core/utils/random_data.py
@@ -77,7 +77,6 @@
             'Candy Box Size': ['100g', '250g', '500g']
         },
         'images_dir': 'candy/',
-        'different_variant_prices': True,
         'is_shipping_required': True
     },
     'E-books': {
@@ -102,7 +101,6 @@
             'Cover': ['Soft', 'Hard']
         },
         'images_dir': 'books/',
-        'different_variant_prices': True,
         'is_shipping_required': True
     }
 }


Test patch:
Repository: saleor/saleor

Issue:
Product prices disappear in storefront after removing stock locations
When removing all stock locations, product prices disappear in the storefront. I think it's a bug, as prices aren't related to stock locations.


Discussion:
Many stores work this way, it's a business decision not to disclose previous prices so you don't see them increase after items are restocked.

(I'm not saying that's the only correct way to do business, just providing context.)
I've checked in the template and we don't display prices for products that aren't in stock or before their availability date (if set). Was that implemented on purpose? From the customer's point of view, I'd like to know the price of the listed product.
I think it's safest not to disclose prices during embargo period. It's probably safe to display the last known price for an out-of-stock product.

Resolving patch:
diff --git a/saleor/graphql/product/types.py b/saleor/graphql/product/types.py
--- a/saleor/graphql/product/types.py
+++ b/saleor/graphql/product/types.py
@@ -28,6 +28,7 @@ def get_ancestors_from_cache(category, context):
 
 class ProductAvailabilityType(graphene.ObjectType):
     available = graphene.Boolean()
+    on_sale = graphene.Boolean()
     discount = graphene.Field(lambda: PriceType)
     discount_local_currency = graphene.Field(lambda: PriceType)
     price_range = graphene.Field(lambda: PriceRangeType)
diff --git a/saleor/product/utils.py b/saleor/product/utils.py
--- a/saleor/product/utils.py
+++ b/saleor/product/utils.py
@@ -52,8 +52,8 @@ def products_with_availability(products, discounts, local_currency):
 
 ProductAvailability = namedtuple(
     'ProductAvailability', (
-        'available', 'price_range', 'price_range_undiscounted', 'discount',
-        'price_range_local_currency', 'discount_local_currency'))
+        'available', 'on_sale', 'price_range', 'price_range_undiscounted',
+        'discount', 'price_range_local_currency', 'discount_local_currency'))
 
 
 def get_availability(product, discounts=None, local_currency=None):
@@ -82,9 +82,13 @@ def get_availability(product, discounts=None, local_currency=None):
         discount_local_currency = None
 
     is_available = product.is_in_stock() and product.is_available()
+    is_on_sale = (
+        product.is_available() and discount is not None and
+        undiscounted.min_price != price_range.min_price)
 
     return ProductAvailability(
         available=is_available,
+        on_sale=is_on_sale,
         price_range=price_range,
         price_range_undiscounted=undiscounted,
         discount=discount,


Test patch:
Repository: saleor/saleor

Issue:
Exception doesn't have a 'message' attribute on Python3.4+
### What I'm trying to achieve

Refunding a product from the dashboard that was paid using the dummy provider.


### Steps to reproduce the problem

1. Refund an order with an input higher than the captured amount
2. Look at the error stack console, it should fail

### What I expected to happen

A simple error message (`Payment gateway error: Refund amount can not be greater then captured amount `)

![pic](https://i.imgur.com/0Q4vTXn.png)
(notice the typo from [django-payments](https://github.com/mirumee/django-payments/blob/db6279d220085f83f3c85b46b12d46aa871c5433/payments/models.py#L161))

### What happened instead/how it failed

```
Traceback (most recent call last):
  File "py3venv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "py3venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "py3venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "py3venv/lib/python3.6/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "py3venv/lib/python3.6/site-packages/django/contrib/auth/decorators.py", line 23, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "development/saleor/saleor/dashboard/order/views.py", line 137, in refund_payment
    if form.is_valid() and form.refund():
  File "development/saleor/saleor/dashboard/order/forms.py", line 97, in refund
    return self.try_payment_action(self.payment.refund)
  File "development/saleor/saleor/dashboard/order/forms.py", line 75, in try_payment_action
    self.payment_error(e.message)
AttributeError: 'ValueError' object has no attribute 'message'
```

Edit: while I'm here, I would like to thank the whole team behind this project and all the contributors. You are doing a great job, working on such a clean, well structured code and repository, feels just great.


Discussion:
Hey @NyanKiyoshi, thanks for reporting this issue, we'll take a look at it. Also, thanks for your kind words about the project, we're doing our best to make the codebase easy to understand and pleasant to work with 🙂.

Resolving patch:
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
@@ -72,7 +72,7 @@ def try_payment_action(self, action):
         try:
             action(amount.gross)
         except (PaymentError, ValueError) as e:
-            self.payment_error(e.message)
+            self.payment_error(str(e))
             return False
         return True
 


Test patch:
Repository: saleor/saleor

Issue:
Improving product variant behaviour
### Steps to reproduce the problem

1. Choose any product in dashboard
2. Remove all variants
3. Try to go to the product page in storefront

### What I expected to happen

Product page in storefront with "UNAVAILABLE" label.

### What happened instead/how it failed
500 code. 


It is getting crashed with `list index out of range` error, because in method `update_field_data` in `VariantChoiceField` lines
```
        if self.queryset.count() < 2:
            self.widget = forms.HiddenInput(
                {'value': variants.all()[0].pk})
```
are trying to get index of empty query set.
Possible solution would be to omit this block of code if `variants.all()` is `False`.


Discussion:

Resolving patch:
diff --git a/saleor/product/forms.py b/saleor/product/forms.py
--- a/saleor/product/forms.py
+++ b/saleor/product/forms.py
@@ -31,8 +31,8 @@ def update_field_data(self, variants, cart):
                 vi.image.image.url for vi in variant.variant_images.all()]
             for variant in variants.all()}
         self.widget.attrs['data-images'] = json.dumps(images_map)
-        # Don't display select input if there are less than two variants
-        if self.queryset.count() < 2:
+        # Don't display select input if there is only one variant.
+        if self.queryset.count() == 1:
             self.widget = forms.HiddenInput(
                 {'value': variants.all()[0].pk})
 


Test patch:
diff --git a/tests/test_product.py b/tests/test_product.py
--- a/tests/test_product.py
+++ b/tests/test_product.py
@@ -503,3 +503,18 @@ def test_view_ajax_available_products_list(admin_client, product_in_stock):
 
     assert response.status_code == 200
     assert resp_decoded == {'results': product_list}
+
+
+def test_render_product_page_with_no_variant(
+        unavailable_product, admin_client):
+    product = unavailable_product
+    product.is_published = True
+    product.product_type.has_variants = True
+    product.save()
+    status = get_product_availability_status(product)
+    assert status == ProductAvailabilityStatus.VARIANTS_MISSSING
+    url = reverse(
+            'product:details',
+            kwargs={'product_id': product.pk, 'slug': product.get_slug()})
+    response = admin_client.get(url)
+    assert response.status_code == 200
Repository: saleor/saleor

Issue:
Consider replacing favicons-webpack-plugin
This Webpack plugin seems to be unmaintained, has heavy dependencies¹ and takes a long time to regenerate the images every time `webpack` is executed.

Maybe we should just add the necessary icons to the repository instead? There are online tools like https://realfavicongenerator.net/ that will provide users with a set of replacement files when customizing the store.

¹ `favicons-webpack-plugin` > `favicons` > `svg2png` > `phantomjs`


Discussion:
Have you tested it? 
I may be doing something wrong, but average time for `npm run build-assets` to execute with and without favicons-webpack-plugin is nearly the same,  and `npm run build-assets --production` gains about 1 second if we drop favicons building.
I'm mostly interested in the requirements this pulls into the project (PhantomJS et al).

I'm not sure building graphical assets has its place in the deployment pipeline. I get that it's convenient. It would also be convenient to have webpack slice PSD files. I'm not sure where the border lies but to me it seems that building favicons automatically is not a great idea (especially given that there's no way to customize them for legibility in any given resolution).

Resolving patch:
diff --git a/saleor/settings.py b/saleor/settings.py
--- a/saleor/settings.py
+++ b/saleor/settings.py
@@ -80,6 +80,7 @@ def get_list(text):
 STATIC_URL = '/static/'
 STATICFILES_DIRS = [
     ('assets', os.path.join(PROJECT_ROOT, 'saleor', 'static', 'assets')),
+    ('favicons', os.path.join(PROJECT_ROOT, 'saleor', 'static', 'favicons')),
     ('images', os.path.join(PROJECT_ROOT, 'saleor', 'static', 'images')),
     ('dashboard', os.path.join(PROJECT_ROOT, 'saleor', 'static', 'dashboard'))]
 STATICFILES_FINDERS = [


Test patch:
Repository: saleor/saleor

Issue:
Product variant without name or attrs displays as blank space in dashboard's breadcrumbs
Seems like `__str__` on our `ProductVariant` may produce empty string if ProductVariant has no name or attributes set. Our titles seem to fallback to SKU if this is the case, but not our breadcrumbs:

<img width="362" alt="zrzut ekranu 2018-03-01 o 13 58 23" src="https://user-images.githubusercontent.com/750553/36845921-d21bf616-1d58-11e8-851c-763c32356818.png">



Discussion:
I had the exact same issue with products without variants. But I'm not able to reproduce it, I don't remember where and when it occurred. I'm gonna try to find it otherwise it means it's gone or no idea.

Resolving patch:
diff --git a/saleor/product/models.py b/saleor/product/models.py
--- a/saleor/product/models.py
+++ b/saleor/product/models.py
@@ -199,7 +199,7 @@ class Meta:
         app_label = 'product'
 
     def __str__(self):
-        return self.name
+        return self.name or self.sku
 
     @property
     def quantity_available(self):


Test patch:
diff --git a/tests/test_product.py b/tests/test_product.py
--- a/tests/test_product.py
+++ b/tests/test_product.py
@@ -320,7 +320,7 @@ def test_get_variant_picker_data_proper_variant_count(product):
 def test_view_ajax_available_variants_list(admin_client, product):
     variant = product.variants.first()
     variant_list = [
-        {'id': variant.pk, 'text': '123, Test product, $10.00'}]
+        {'id': variant.pk, 'text': '123, Test product (123), $10.00'}]
 
     url = reverse('dashboard:ajax-available-variants')
     response = admin_client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
Repository: saleor/saleor

Issue:
New orders in the client's panel do not appear
After updating to the dev version commit afc26b0 new orders in the client's panel do not appear.
In the dashboard is ok.


Discussion:
@mad-anne Could you take a look?
Hi @maltitco, I can't reproduce your problem - orders are always visible for customer. Could you please provide more details?
@mad-anne the problem is in the display order:
<img width="987" alt="zrzut ekranu 2018-03-22 o 12 33 21" src="https://user-images.githubusercontent.com/1561204/37768308-6749e5c0-2dcd-11e8-884c-ed704845f43e.png">
in DB view:
<img width="341" alt="zrzut ekranu 2018-03-22 o 12 47 27" src="https://user-images.githubusercontent.com/1561204/37768819-3fe9fbe4-2dcf-11e8-8dd8-2b9fa8862f42.png">


Resolving patch:
diff --git a/saleor/dashboard/order/views.py b/saleor/dashboard/order/views.py
--- a/saleor/dashboard/order/views.py
+++ b/saleor/dashboard/order/views.py
@@ -37,8 +37,7 @@
 @staff_member_required
 @permission_required('order.view_order')
 def order_list(request):
-    orders = Order.objects.prefetch_related(
-        'payments', 'lines', 'user').order_by('-pk')
+    orders = Order.objects.prefetch_related('payments', 'lines', 'user')
     order_filter = OrderFilter(request.GET, queryset=orders)
     orders = get_paginator_items(
         order_filter.qs, settings.DASHBOARD_PAGINATE_BY,
diff --git a/saleor/order/migrations/0043_auto_20180322_0655.py b/saleor/order/migrations/0043_auto_20180322_0655.py
new file mode 100644
--- /dev/null
+++ b/saleor/order/migrations/0043_auto_20180322_0655.py
@@ -0,0 +1,22 @@
+# Generated by Django 2.0.3 on 2018-03-22 11:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('order', '0042_auto_20180227_0436'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='order',
+            options={'ordering': ('-pk',), 'permissions': (('view_order', 'Can view orders'), ('edit_order', 'Can edit orders'))},
+        ),
+        migrations.AlterField(
+            model_name='order',
+            name='language_code',
+            field=models.CharField(default='en', max_length=35),
+        ),
+    ]
diff --git a/saleor/order/models.py b/saleor/order/models.py
--- a/saleor/order/models.py
+++ b/saleor/order/models.py
@@ -67,6 +67,7 @@ class Order(models.Model):
     discount_name = models.CharField(max_length=255, default='', blank=True)
 
     class Meta:
+        ordering = ('-pk',)
         permissions = (
             ('view_order',
              pgettext_lazy('Permission description', 'Can view orders')),


Test patch: