<commit_before>import datetime
import uuid
from contextlib import contextmanager
from decimal import Decimal
from functools import partial
from io import BytesIO
from typing import List, Optional
from unittest.mock import MagicMock, Mock

import pytest
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site
from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db import connection
from django.forms import ModelForm
from django.test.client import Client
from django.test.utils import CaptureQueriesContext as BaseCaptureQueriesContext
from django_countries import countries
from PIL import Image
from prices import Money, TaxedMoney

from saleor.account.models import (
    Address,
    ServiceAccount,
    StaffNotificationRecipient,
    User,
)
from saleor.checkout import utils
from saleor.checkout.models import Checkout
from saleor.checkout.utils import add_variant_to_checkout
from saleor.core.payments import PaymentInterface
from saleor.discount import DiscountInfo, DiscountValueType, VoucherType
from saleor.discount.models import (
    Sale,
    SaleTranslation,
    Voucher,
    VoucherCustomer,
    VoucherTranslation,
)
from saleor.giftcard.models import GiftCard
from saleor.menu.models import Menu, MenuItem, MenuItemTranslation
from saleor.menu.utils import update_menu
from saleor.order import OrderStatus
from saleor.order.actions import fulfill_order_line
from saleor.order.events import OrderEvents
from saleor.order.models import FulfillmentStatus, Order, OrderEvent
from saleor.order.utils import recalculate_order
from saleor.page.models import Page, PageTranslation
from saleor.payment import ChargeStatus, TransactionKind
from saleor.payment.models import Payment
from saleor.product import AttributeInputType
from saleor.product.models import (
    Attribute,
    AttributeTranslation,
    AttributeValue,
    AttributeValueTranslation,
    Category,
    CategoryTranslation,
    Collection,
    CollectionTranslation,
    DigitalContent,
    DigitalContentUrl,
    Product,
    ProductImage,
    ProductTranslation,
    ProductType,
    ProductVariant,
    ProductVariantTranslation,
)
from saleor.product.utils.attributes import associate_attribute_values_to_instance
from saleor.shipping.models import (
    ShippingMethod,
    ShippingMethodTranslation,
    ShippingMethodType,
    ShippingZone,
)
from saleor.site import AuthenticationBackends
from saleor.site.models import AuthorizationKey, SiteSettings
from saleor.stock.models import Stock
from saleor.warehouse.models import Warehouse
from saleor.webhook.event_types import WebhookEventType
from saleor.webhook.models import Webhook
from saleor.wishlist.models import Wishlist
from tests.utils import create_image


class CaptureQueriesContext(BaseCaptureQueriesContext):
    IGNORED_QUERIES = settings.PATTERNS_IGNORED_IN_QUERY_CAPTURES

    @property
    def captured_queries(self):
        # flake8: noqa
        base_queries = self.connection.queries[
            self.initial_queries : self.final_queries
        ]
        new_queries = []

        def is_query_ignored(sql):
            for pattern in self.IGNORED_QUERIES:
                # Ignore the query if matches
                if pattern.match(sql):
                    return True
            return False

        for query in base_queries:
            if not is_query_ignored(query["sql"]):
                new_queries.append(query)

        return new_queries


def _assert_num_queries(context, *, config, num, exact=True, info=None):
    """
    Extracted from pytest_django.fixtures._assert_num_queries
    """
    yield context

    verbose = config.getoption("verbose") > 0
    num_performed = len(context)

    if exact:
        failed = num != num_performed
    else:
        failed = num_performed > num

    if not failed:
        return

    msg = "Expected to perform {} queries {}{}".format(
        num,
        "" if exact else "or less ",
        "but {} done".format(
            num_performed == 1 and "1 was" or "%d were" % (num_performed,)
        ),
    )
    if info:
        msg += "\n{}".format(info)
    if verbose:
        sqls = (q["sql"] for q in context.captured_queries)
        msg += "\n\nQueries:\n========\n\n%s" % "\n\n".join(sqls)
    else:
        msg += " (add -v option to show queries)"
    pytest.fail(msg)


@pytest.fixture
def capture_queries(pytestconfig):
    cfg = pytestconfig

    @contextmanager
    def _capture_queries(
        num: Optional[int] = None, msg: Optional[str] = None, exact=False
    ):
        with CaptureQueriesContext(connection) as ctx:
            yield ctx
            if num is not None:
                _assert_num_queries(ctx, config=cfg, num=num, exact=exact, info=msg)

    return _capture_queries


@pytest.fixture
def assert_num_queries(capture_queries):
    return partial(capture_queries, exact=True)


@pytest.fixture
def assert_max_num_queries(capture_queries):
    return partial(capture_queries, exact=False)


@pytest.fixture(autouse=True)
def setup_dummy_gateway(settings):
    settings.PLUGINS = ["saleor.payment.gateways.dummy.plugin.DummyGatewayPlugin"]
    return settings


@pytest.fixture(autouse=True)
def site_settings(db, settings) -> SiteSettings:
    """Create a site and matching site settings.

    This fixture is autouse because django.contrib.sites.models.Site and
    saleor.site.models.SiteSettings have a one-to-one relationship and a site
    should never exist without a matching settings object.
    """
    site = Site.objects.get_or_create(name="mirumee.com", domain="mirumee.com")[0]
    obj = SiteSettings.objects.get_or_create(
        site=site,
        default_mail_sender_name="Mirumee Labs",
        default_mail_sender_address="<EMAIL>",
    )[0]
    settings.SITE_ID = site.pk

    main_menu = Menu.objects.get_or_create(
        name=settings.DEFAULT_MENUS["top_menu_name"]
    )[0]
    update_menu(main_menu)
    secondary_menu = Menu.objects.get_or_create(
        name=settings.DEFAULT_MENUS["bottom_menu_name"]
    )[0]
    update_menu(secondary_menu)
    obj.top_menu = main_menu
    obj.bottom_menu = secondary_menu
    obj.save()
    return obj


@pytest.fixture
def checkout(db):
    checkout = Checkout.objects.create()
    checkout.set_country("US")
    return checkout


@pytest.fixture
def checkout_with_item(checkout, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_single_item(checkout, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 1)
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_items(checkout, product_list, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 1)
    for prod in product_list:
        variant = prod.variants.get()
        add_variant_to_checkout(checkout, variant, 1)
    checkout.refresh_from_db()
    return checkout


@pytest.fixture
def checkout_with_voucher(checkout, product, voucher):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.voucher_code = voucher.code
    checkout.discount = Money("20.00", "USD")
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_voucher_percentage(checkout, product, voucher_percentage):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.voucher_code = voucher_percentage.code
    checkout.discount = Money("3.00", "USD")
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_gift_card(checkout_with_item, gift_card):
    checkout_with_item.gift_cards.add(gift_card)
    checkout_with_item.save()
    return checkout_with_item


@pytest.fixture
def checkout_with_voucher_percentage_and_shipping(
    checkout_with_voucher_percentage, shipping_method, address
):
    checkout = checkout_with_voucher_percentage
    checkout.shipping_method = shipping_method
    checkout.shipping_address = address
    checkout.save()
    return checkout


@pytest.fixture
def address(db):  # pylint: disable=W0613
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        company_name="Mirumee Software",
        street_address_1="Tęczowa 7",
        city="WROCŁAW",
        postal_code="53-601",
        country="PL",
        phone="+48713988102",
    )


@pytest.fixture
def address_other_country():
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        street_address_1="4371 Lucas Knoll Apt. 791",
        city="BENNETTMOUTH",
        postal_code="13377",
        country="IS",
        phone="",
    )


@pytest.fixture
def address_usa():
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        street_address_1="2000 Main Street",
        city="Irvine",
        postal_code="92614",
        country_area="CA",
        country="US",
        phone="",
    )


@pytest.fixture
def graphql_address_data():
    return {
        "firstName": "<NAME>",
        "lastName": "<NAME>",
        "companyName": "Mirumee Software",
        "streetAddress1": "Tęczowa 7",
        "streetAddress2": "",
        "postalCode": "53-601",
        "country": "PL",
        "city": "Wrocław",
        "countryArea": "",
        "phone": "+48321321888",
    }


@pytest.fixture
def customer_user(address):  # pylint: disable=W0613
    default_address = address.get_copy()
    user = User.objects.create_user(
        "<EMAIL>",
        "password",
        default_billing_address=default_address,
        default_shipping_address=default_address,
        first_name="Leslie",
        last_name="Wade",
    )
    user.addresses.add(default_address)
    user._password = "password"
    return user


@pytest.fixture
def user_checkout(customer_user):
    return Checkout.objects.get_or_create(user=customer_user)[0]


@pytest.fixture
def request_checkout(checkout, monkeypatch):
    # FIXME: Fixtures should not have any side effects
    monkeypatch.setattr(
        utils,
        "get_checkout_from_request",
        lambda request, checkout_queryset=None: checkout,
    )
    return checkout


@pytest.fixture
def request_checkout_with_item(product, request_checkout):
    variant = product.variants.get()
    add_variant_to_checkout(request_checkout, variant)
    return request_checkout


@pytest.fixture
def order(customer_user):
    address = customer_user.default_billing_address.get_copy()
    return Order.objects.create(
        billing_address=address, user_email=customer_user.email, user=customer_user
    )


@pytest.fixture
def admin_user(db):
    """Return a Django admin user."""
    return User.objects.create_superuser("<EMAIL>", "password")


@pytest.fixture
def staff_user(db):
    """Return a staff member."""
    return User.objects.create_user(
        email="<EMAIL>",
        password="password",
        is_staff=True,
        is_active=True,
    )


@pytest.fixture
def shipping_zone(db):  # pylint: disable=W0613
    shipping_zone = ShippingZone.objects.create(
        name="Europe", countries=[code for code, name in countries]
    )
    shipping_zone.shipping_methods.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )
    return shipping_zone


@pytest.fixture
def shipping_zone_without_countries(db):  # pylint: disable=W0613
    shipping_zone = ShippingZone.objects.create(name="Europe", countries=[])
    shipping_zone.shipping_methods.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )
    return shipping_zone


@pytest.fixture
def shipping_method(shipping_zone):
    return ShippingMethod.objects.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )


@pytest.fixture
def color_attribute(db):  # pylint: disable=W0613
    attribute = Attribute.objects.create(slug="color", name="Color")
    AttributeValue.objects.create(attribute=attribute, name="Red", slug="red")
    AttributeValue.objects.create(attribute=attribute, name="Blue", slug="blue")
    return attribute


@pytest.fixture
def color_attribute_without_values(db):  # pylint: disable=W0613
    return Attribute.objects.create(slug="color", name="Color")


@pytest.fixture
def pink_attribute_value(color_attribute):  # pylint: disable=W0613
    value = AttributeValue.objects.create(
        slug="pink", name="Pink", attribute=color_attribute, value="#FF69B4"
    )
    return value


@pytest.fixture
def size_attribute(db):  # pylint: disable=W0613
    attribute = Attribute.objects.create(slug="size", name="Size")
    AttributeValue.objects.create(attribute=attribute, name="Small", slug="small")
    AttributeValue.objects.create(attribute=attribute, name="Big", slug="big")
    return attribute


@pytest.fixture
def attribute_list() -> List[Attribute]:
    return list(
        Attribute.objects.bulk_create(
            [
                Attribute(slug="size", name="Size"),
                Attribute(slug="weight", name="Weight"),
                Attribute(slug="thickness", name="Thickness"),
            ]
        )
    )


@pytest.fixture
def image():
    img_data = BytesIO()
    image = Image.new("RGB", size=(1, 1))
    image.save(img_data, format="JPEG")
    return SimpleUploadedFile("product.jpg", img_data.getvalue())


@pytest.fixture
def category(db):  # pylint: disable=W0613
    return Category.objects.create(name="Default", slug="default")


@pytest.fixture
def category_with_image(db, image, media_root):  # pylint: disable=W0613
    return Category.objects.create(
        name="Default", slug="default", background_image=image
    )


@pytest.fixture
def categories_tree(db, product_type):  # pylint: disable=W0613
    parent = Category.objects.create(name="Parent", slug="parent")
    parent.children.create(name="Child", slug="child")
    child = parent.children.first()

    product_attr = product_type.product_attributes.first()
    attr_value = product_attr.values.first()

    product = Product.objects.create(
        name="Test product",
        price=Money(10, "USD"),
        product_type=product_type,
        category=child,
        is_published=True,
    )

    associate_attribute_values_to_instance(product, product_attr, attr_value)
    return parent


@pytest.fixture
def categories_tree_with_published_products(categories_tree, product):
    parent = categories_tree
    parent_product = product
    parent_product.category = parent

    child = parent.children.first()
    child_product = child.products.first()

    for product in [child_product, parent_product]:
        product.publication_date = datetime.date.today()
        product.is_published = True
        product.save()
    return parent


@pytest.fixture
def non_default_category(db):  # pylint: disable=W0613
    return Category.objects.create(name="Not default", slug="not-default")


@pytest.fixture
def permission_manage_discounts():
    return Permission.objects.get(codename="manage_discounts")


@pytest.fixture
def permission_manage_gift_card():
    return Permission.objects.get(codename="manage_gift_card")


@pytest.fixture
def permission_manage_orders():
    return Permission.objects.get(codename="manage_orders")


@pytest.fixture
def permission_manage_checkouts():
    return Permission.objects.get(codename="manage_checkouts")


@pytest.fixture
def permission_manage_plugins():
    return Permission.objects.get(codename="manage_plugins")


@pytest.fixture
def permission_manage_service_accounts():
    return Permission.objects.get(codename="manage_service_accounts")


@pytest.fixture
def permission_manage_warehouses():
    return Permission.objects.get(codename="manage_warehouses")


@pytest.fixture
def product_type(color_attribute, size_attribute):
    product_type = ProductType.objects.create(
        name="Default Type", has_variants=True, is_shipping_required=True
    )
    product_type.product_attributes.add(color_attribute)
    product_type.variant_attributes.add(size_attribute)
    return product_type


@pytest.fixture
def product_type_without_variant():
    product_type = ProductType.objects.create(
        name="Type", has_variants=False, is_shipping_required=True
    )
    return product_type


@pytest.fixture
def product(product_type, category, warehouse):
    product_attr = product_type.product_attributes.first()
    product_attr_value = product_attr.values.first()

    product = Product.objects.create(
        name="Test product",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )

    associate_attribute_values_to_instance(product, product_attr, product_attr_value)

    variant_attr = product_type.variant_attributes.first()
    variant_attr_value = variant_attr.values.first()

    variant = ProductVariant.objects.create(
        product=product, sku="123", cost_price=Money("1.00", "USD")
    )
    Stock.objects.create(
        warehouse=warehouse, product_variant=variant, quantity=10, quantity_allocated=1
    )

    associate_attribute_values_to_instance(variant, variant_attr, variant_attr_value)
    return product


@pytest.fixture
def product_with_single_variant(product_type, category, warehouse):
    product = Product.objects.create(
        name="Test product with single variant",
        price=Money("1.99", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )
    variant = ProductVariant.objects.create(
        product=product,
        sku="SKU_SINGLE_VARIANT",
        cost_price=Money("1.00", "USD"),
    )
    Stock.objects.create(product_variant=variant, warehouse=warehouse, quantity=101, quantity_allocated=1)
    return product


@pytest.fixture
def product_with_two_variants(product_type, category, warehouse):
    product = Product.objects.create(
        name="Test product with two variants",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
    )

    variants = [
            ProductVariant(
                product=product,
                sku=f"Product variant #{i}",
                cost_price=Money("1.00", "USD"),
            )
            for i in (1, 2)
        ]
    ProductVariant.objects.bulk_create(variants)
    Stock.objects.bulk_create(
        [Stock(warehouse=warehouse, product_variant=variant, quantity=10, quantity_allocated=1)]
    )

    return product


@pytest.fixture
def product_with_variant_with_two_attributes(color_attribute, size_attribute, category, warehouse):
    product_type = ProductType.objects.create(
        name="Type with two variants", has_variants=True, is_shipping_required=True
    )
    product_type.variant_attributes.add(color_attribute)
    product_type.variant_attributes.add(size_attribute)

    product = Product.objects.create(
        name="Test product with two variants",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )

    variant = ProductVariant.objects.create(
        product=product, sku="prodVar1", cost_price=Money("1.00", "USD")
    )
    Stock.objects.create(
        product_variant=variant, warehouse=warehouse, quantity=10, quantity_allocated=1
    )

    associate_attribute_values_to_instance(
        variant, color_attribute, color_attribute.values.first()
    )
    associate_attribute_values_to_instance(
        variant, size_attribute, size_attribute.values.first()
    )

    return product


@pytest.fixture
def product_with_multiple_values_attributes(product, product_type, category) -> Product:

    attribute = Attribute.objects.create(
        slug="modes", name="Available Modes", input_type=AttributeInputType.MULTISELECT
    )

    attr_val_1 = AttributeValue.objects.create(
        attribute=attribute, name="Eco Mode", slug="eco"
    )
    attr_val_2 = AttributeValue.objects.create(
        attribute=attribute, name="Performance Mode", slug="power"
    )

    product_type.product_attributes.clear()
    product_type.product_attributes.add(attribute)

    associate_attribute_values_to_instance(product, attribute, attr_val_1, attr_val_2)
    return product


@pytest.fixture
def product_with_default_variant(product_type_without_variant, category, warehouse):
    product = Product.objects.create(
        name="Test product",
        price=Money(10, "USD"),
        product_type=product_type_without_variant,
        category=category,
        is_published=True,
    )
    ProductVariant.objects.create(product=product, sku="1234", track_inventory=True)
    Stock.objects.create(warehouse=warehouse, product_variant=variant, quantity=100)
    return product


@pytest.fixture
def variant(product):
    product_variant = ProductVariant.objects.create(
        product=product, sku="SKU_A", cost_price=Money(1, "USD")
    )
    return product_variant


@pytest.fixture
def product_variant_list(product):
    return list(
        ProductVariant.objects.bulk_create(
            [
                ProductVariant(product=product, sku="1"),
                ProductVariant(product=product, sku="2"),
                ProductVariant(product=product, sku="3"),
            ]
        )
    )<commit_msg>Update tests to work with new implementation<commit_after>import datetime
import uuid
from contextlib import contextmanager
from decimal import Decimal
from functools import partial
from io import BytesIO
from typing import List, Optional
from unittest.mock import MagicMock, Mock

import pytest
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.sites.models import Site
from django.core.files import File
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db import connection
from django.forms import ModelForm
from django.test.client import Client
from django.test.utils import CaptureQueriesContext as BaseCaptureQueriesContext
from django_countries import countries
from PIL import Image
from prices import Money, TaxedMoney

from saleor.account.models import (
    Address,
    ServiceAccount,
    StaffNotificationRecipient,
    User,
)
from saleor.checkout import utils
from saleor.checkout.models import Checkout
from saleor.checkout.utils import add_variant_to_checkout
from saleor.core.payments import PaymentInterface
from saleor.discount import DiscountInfo, DiscountValueType, VoucherType
from saleor.discount.models import (
    Sale,
    SaleTranslation,
    Voucher,
    VoucherCustomer,
    VoucherTranslation,
)
from saleor.giftcard.models import GiftCard
from saleor.menu.models import Menu, MenuItem, MenuItemTranslation
from saleor.menu.utils import update_menu
from saleor.order import OrderStatus
from saleor.order.actions import fulfill_order_line
from saleor.order.events import OrderEvents
from saleor.order.models import FulfillmentStatus, Order, OrderEvent
from saleor.order.utils import recalculate_order
from saleor.page.models import Page, PageTranslation
from saleor.payment import ChargeStatus, TransactionKind
from saleor.payment.models import Payment
from saleor.product import AttributeInputType
from saleor.product.models import (
    Attribute,
    AttributeTranslation,
    AttributeValue,
    AttributeValueTranslation,
    Category,
    CategoryTranslation,
    Collection,
    CollectionTranslation,
    DigitalContent,
    DigitalContentUrl,
    Product,
    ProductImage,
    ProductTranslation,
    ProductType,
    ProductVariant,
    ProductVariantTranslation,
)
from saleor.product.utils.attributes import associate_attribute_values_to_instance
from saleor.shipping.models import (
    ShippingMethod,
    ShippingMethodTranslation,
    ShippingMethodType,
    ShippingZone,
)
from saleor.site import AuthenticationBackends
from saleor.site.models import AuthorizationKey, SiteSettings
from saleor.stock.models import Stock
from saleor.warehouse.models import Warehouse
from saleor.webhook.event_types import WebhookEventType
from saleor.webhook.models import Webhook
from saleor.wishlist.models import Wishlist
from tests.utils import create_image


class CaptureQueriesContext(BaseCaptureQueriesContext):
    IGNORED_QUERIES = settings.PATTERNS_IGNORED_IN_QUERY_CAPTURES

    @property
    def captured_queries(self):
        # flake8: noqa
        base_queries = self.connection.queries[
            self.initial_queries : self.final_queries
        ]
        new_queries = []

        def is_query_ignored(sql):
            for pattern in self.IGNORED_QUERIES:
                # Ignore the query if matches
                if pattern.match(sql):
                    return True
            return False

        for query in base_queries:
            if not is_query_ignored(query["sql"]):
                new_queries.append(query)

        return new_queries


def _assert_num_queries(context, *, config, num, exact=True, info=None):
    """
    Extracted from pytest_django.fixtures._assert_num_queries
    """
    yield context

    verbose = config.getoption("verbose") > 0
    num_performed = len(context)

    if exact:
        failed = num != num_performed
    else:
        failed = num_performed > num

    if not failed:
        return

    msg = "Expected to perform {} queries {}{}".format(
        num,
        "" if exact else "or less ",
        "but {} done".format(
            num_performed == 1 and "1 was" or "%d were" % (num_performed,)
        ),
    )
    if info:
        msg += "\n{}".format(info)
    if verbose:
        sqls = (q["sql"] for q in context.captured_queries)
        msg += "\n\nQueries:\n========\n\n%s" % "\n\n".join(sqls)
    else:
        msg += " (add -v option to show queries)"
    pytest.fail(msg)


@pytest.fixture
def capture_queries(pytestconfig):
    cfg = pytestconfig

    @contextmanager
    def _capture_queries(
        num: Optional[int] = None, msg: Optional[str] = None, exact=False
    ):
        with CaptureQueriesContext(connection) as ctx:
            yield ctx
            if num is not None:
                _assert_num_queries(ctx, config=cfg, num=num, exact=exact, info=msg)

    return _capture_queries


@pytest.fixture
def assert_num_queries(capture_queries):
    return partial(capture_queries, exact=True)


@pytest.fixture
def assert_max_num_queries(capture_queries):
    return partial(capture_queries, exact=False)


@pytest.fixture(autouse=True)
def setup_dummy_gateway(settings):
    settings.PLUGINS = ["saleor.payment.gateways.dummy.plugin.DummyGatewayPlugin"]
    return settings


@pytest.fixture(autouse=True)
def site_settings(db, settings) -> SiteSettings:
    """Create a site and matching site settings.

    This fixture is autouse because django.contrib.sites.models.Site and
    saleor.site.models.SiteSettings have a one-to-one relationship and a site
    should never exist without a matching settings object.
    """
    site = Site.objects.get_or_create(name="mir<EMAIL>", domain="mirumee.com")[0]
    obj = SiteSettings.objects.get_or_create(
        site=site,
        default_mail_sender_name="<NAME>",
        default_mail_sender_address="<EMAIL>",
    )[0]
    settings.SITE_ID = site.pk

    main_menu = Menu.objects.get_or_create(
        name=settings.DEFAULT_MENUS["top_menu_name"]
    )[0]
    update_menu(main_menu)
    secondary_menu = Menu.objects.get_or_create(
        name=settings.DEFAULT_MENUS["bottom_menu_name"]
    )[0]
    update_menu(secondary_menu)
    obj.top_menu = main_menu
    obj.bottom_menu = secondary_menu
    obj.save()
    return obj


@pytest.fixture
def checkout(db):
    checkout = Checkout.objects.create()
    checkout.set_country("US")
    return checkout


@pytest.fixture
def checkout_with_item(checkout, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_single_item(checkout, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 1)
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_items(checkout, product_list, product):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 1)
    for prod in product_list:
        variant = prod.variants.get()
        add_variant_to_checkout(checkout, variant, 1)
    checkout.refresh_from_db()
    return checkout


@pytest.fixture
def checkout_with_voucher(checkout, product, voucher):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.voucher_code = voucher.code
    checkout.discount = Money("20.00", "USD")
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_voucher_percentage(checkout, product, voucher_percentage):
    variant = product.variants.get()
    add_variant_to_checkout(checkout, variant, 3)
    checkout.voucher_code = voucher_percentage.code
    checkout.discount = Money("3.00", "USD")
    checkout.save()
    return checkout


@pytest.fixture
def checkout_with_gift_card(checkout_with_item, gift_card):
    checkout_with_item.gift_cards.add(gift_card)
    checkout_with_item.save()
    return checkout_with_item


@pytest.fixture
def checkout_with_voucher_percentage_and_shipping(
    checkout_with_voucher_percentage, shipping_method, address
):
    checkout = checkout_with_voucher_percentage
    checkout.shipping_method = shipping_method
    checkout.shipping_address = address
    checkout.save()
    return checkout


@pytest.fixture
def address(db):  # pylint: disable=W0613
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        company_name="Mirumee Software",
        street_address_1="Tęczowa 7",
        city="WROCŁAW",
        postal_code="53-601",
        country="PL",
        phone="+48713988102",
    )


@pytest.fixture
def address_other_country():
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        street_address_1="4371 Lucas Knoll Apt. 791",
        city="BENNETTMOUTH",
        postal_code="13377",
        country="IS",
        phone="",
    )


@pytest.fixture
def address_usa():
    return Address.objects.create(
        first_name="John",
        last_name="Doe",
        street_address_1="2000 Main Street",
        city="Irvine",
        postal_code="92614",
        country_area="CA",
        country="US",
        phone="",
    )


@pytest.fixture
def graphql_address_data():
    return {
        "firstName": "<NAME>",
        "lastName": "<NAME>",
        "companyName": "Mirumee Software",
        "streetAddress1": "Tęczowa 7",
        "streetAddress2": "",
        "postalCode": "53-601",
        "country": "PL",
        "city": "Wrocław",
        "countryArea": "",
        "phone": "+48321321888",
    }


@pytest.fixture
def customer_user(address):  # pylint: disable=W0613
    default_address = address.get_copy()
    user = User.objects.create_user(
        "<EMAIL>",
        "password",
        default_billing_address=default_address,
        default_shipping_address=default_address,
        first_name="Leslie",
        last_name="Wade",
    )
    user.addresses.add(default_address)
    user._password = "password"
    return user


@pytest.fixture
def user_checkout(customer_user):
    return Checkout.objects.get_or_create(user=customer_user)[0]


@pytest.fixture
def request_checkout(checkout, monkeypatch):
    # FIXME: Fixtures should not have any side effects
    monkeypatch.setattr(
        utils,
        "get_checkout_from_request",
        lambda request, checkout_queryset=None: checkout,
    )
    return checkout


@pytest.fixture
def request_checkout_with_item(product, request_checkout):
    variant = product.variants.get()
    add_variant_to_checkout(request_checkout, variant)
    return request_checkout


@pytest.fixture
def order(customer_user):
    address = customer_user.default_billing_address.get_copy()
    return Order.objects.create(
        billing_address=address, user_email=customer_user.email, user=customer_user
    )


@pytest.fixture
def admin_user(db):
    """Return a Django admin user."""
    return User.objects.create_superuser("<EMAIL>", "password")


@pytest.fixture
def staff_user(db):
    """Return a staff member."""
    return User.objects.create_user(
        email="<EMAIL>",
        password="password",
        is_staff=True,
        is_active=True,
    )


@pytest.fixture
def shipping_zone(db):  # pylint: disable=W0613
    shipping_zone = ShippingZone.objects.create(
        name="Europe", countries=[code for code, name in countries]
    )
    shipping_zone.shipping_methods.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )
    return shipping_zone


@pytest.fixture
def shipping_zone_without_countries(db):  # pylint: disable=W0613
    shipping_zone = ShippingZone.objects.create(name="Europe", countries=[])
    shipping_zone.shipping_methods.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )
    return shipping_zone


@pytest.fixture
def shipping_method(shipping_zone):
    return ShippingMethod.objects.create(
        name="DHL",
        minimum_order_price=Money(0, "USD"),
        type=ShippingMethodType.PRICE_BASED,
        price=Money(10, "USD"),
        shipping_zone=shipping_zone,
    )


@pytest.fixture
def color_attribute(db):  # pylint: disable=W0613
    attribute = Attribute.objects.create(slug="color", name="Color")
    AttributeValue.objects.create(attribute=attribute, name="Red", slug="red")
    AttributeValue.objects.create(attribute=attribute, name="Blue", slug="blue")
    return attribute


@pytest.fixture
def color_attribute_without_values(db):  # pylint: disable=W0613
    return Attribute.objects.create(slug="color", name="Color")


@pytest.fixture
def pink_attribute_value(color_attribute):  # pylint: disable=W0613
    value = AttributeValue.objects.create(
        slug="pink", name="Pink", attribute=color_attribute, value="#FF69B4"
    )
    return value


@pytest.fixture
def size_attribute(db):  # pylint: disable=W0613
    attribute = Attribute.objects.create(slug="size", name="Size")
    AttributeValue.objects.create(attribute=attribute, name="Small", slug="small")
    AttributeValue.objects.create(attribute=attribute, name="Big", slug="big")
    return attribute


@pytest.fixture
def attribute_list() -> List[Attribute]:
    return list(
        Attribute.objects.bulk_create(
            [
                Attribute(slug="size", name="Size"),
                Attribute(slug="weight", name="Weight"),
                Attribute(slug="thickness", name="Thickness"),
            ]
        )
    )


@pytest.fixture
def image():
    img_data = BytesIO()
    image = Image.new("RGB", size=(1, 1))
    image.save(img_data, format="JPEG")
    return SimpleUploadedFile("product.jpg", img_data.getvalue())


@pytest.fixture
def category(db):  # pylint: disable=W0613
    return Category.objects.create(name="Default", slug="default")


@pytest.fixture
def category_with_image(db, image, media_root):  # pylint: disable=W0613
    return Category.objects.create(
        name="Default", slug="default", background_image=image
    )


@pytest.fixture
def categories_tree(db, product_type):  # pylint: disable=W0613
    parent = Category.objects.create(name="Parent", slug="parent")
    parent.children.create(name="Child", slug="child")
    child = parent.children.first()

    product_attr = product_type.product_attributes.first()
    attr_value = product_attr.values.first()

    product = Product.objects.create(
        name="Test product",
        price=Money(10, "USD"),
        product_type=product_type,
        category=child,
        is_published=True,
    )

    associate_attribute_values_to_instance(product, product_attr, attr_value)
    return parent


@pytest.fixture
def categories_tree_with_published_products(categories_tree, product):
    parent = categories_tree
    parent_product = product
    parent_product.category = parent

    child = parent.children.first()
    child_product = child.products.first()

    for product in [child_product, parent_product]:
        product.publication_date = datetime.date.today()
        product.is_published = True
        product.save()
    return parent


@pytest.fixture
def non_default_category(db):  # pylint: disable=W0613
    return Category.objects.create(name="Not default", slug="not-default")


@pytest.fixture
def permission_manage_discounts():
    return Permission.objects.get(codename="manage_discounts")


@pytest.fixture
def permission_manage_gift_card():
    return Permission.objects.get(codename="manage_gift_card")


@pytest.fixture
def permission_manage_orders():
    return Permission.objects.get(codename="manage_orders")


@pytest.fixture
def permission_manage_checkouts():
    return Permission.objects.get(codename="manage_checkouts")


@pytest.fixture
def permission_manage_plugins():
    return Permission.objects.get(codename="manage_plugins")


@pytest.fixture
def permission_manage_service_accounts():
    return Permission.objects.get(codename="manage_service_accounts")


@pytest.fixture
def permission_manage_warehouses():
    return Permission.objects.get(codename="manage_warehouses")


@pytest.fixture
def product_type(color_attribute, size_attribute):
    product_type = ProductType.objects.create(
        name="Default Type", has_variants=True, is_shipping_required=True
    )
    product_type.product_attributes.add(color_attribute)
    product_type.variant_attributes.add(size_attribute)
    return product_type


@pytest.fixture
def product_type_without_variant():
    product_type = ProductType.objects.create(
        name="Type", has_variants=False, is_shipping_required=True
    )
    return product_type


@pytest.fixture
def product(product_type, category, warehouse):
    product_attr = product_type.product_attributes.first()
    product_attr_value = product_attr.values.first()

    product = Product.objects.create(
        name="Test product",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )

    associate_attribute_values_to_instance(product, product_attr, product_attr_value)

    variant_attr = product_type.variant_attributes.first()
    variant_attr_value = variant_attr.values.first()

    variant = ProductVariant.objects.create(
        product=product, sku="123", cost_price=Money("1.00", "USD")
    )
    Stock.objects.create(
        warehouse=warehouse, product_variant=variant, quantity=10, quantity_allocated=1
    )

    associate_attribute_values_to_instance(variant, variant_attr, variant_attr_value)
    return product


@pytest.fixture
def product_with_single_variant(product_type, category, warehouse):
    product = Product.objects.create(
        name="Test product with single variant",
        price=Money("1.99", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )
    variant = ProductVariant.objects.create(
        product=product,
        sku="SKU_SINGLE_VARIANT",
        cost_price=Money("1.00", "USD"),
    )
    Stock.objects.create(product_variant=variant, warehouse=warehouse, quantity=101, quantity_allocated=1)
    return product


@pytest.fixture
def product_with_two_variants(product_type, category, warehouse):
    product = Product.objects.create(
        name="Test product with two variants",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
    )

    variants = [
            ProductVariant(
                product=product,
                sku=f"Product variant #{i}",
                cost_price=Money("1.00", "USD"),
            )
            for i in (1, 2)
        ]
    ProductVariant.objects.bulk_create(variants)
    Stock.objects.bulk_create(
        [Stock(warehouse=warehouse, product_variant=variant, quantity=10, quantity_allocated=1)]
    )

    return product


@pytest.fixture
def product_with_variant_with_two_attributes(color_attribute, size_attribute, category, warehouse):
    product_type = ProductType.objects.create(
        name="Type with two variants", has_variants=True, is_shipping_required=True
    )
    product_type.variant_attributes.add(color_attribute)
    product_type.variant_attributes.add(size_attribute)

    product = Product.objects.create(
        name="Test product with two variants",
        price=Money("10.00", "USD"),
        product_type=product_type,
        category=category,
        is_published=True,
    )

    variant = ProductVariant.objects.create(
        product=product, sku="prodVar1", cost_price=Money("1.00", "USD")
    )
    Stock.objects.create(
        product_variant=variant, warehouse=warehouse, quantity=10, quantity_allocated=1
    )

    associate_attribute_values_to_instance(
        variant, color_attribute, color_attribute.values.first()
    )
    associate_attribute_values_to_instance(
        variant, size_attribute, size_attribute.values.first()
    )

    return product


@pytest.fixture
def product_with_multiple_values_attributes(product, product_type, category) -> Product:

    attribute = Attribute.objects.create(
        slug="modes", name="Available Modes", input_type=AttributeInputType.MULTISELECT
    )

    attr_val_1 = AttributeValue.objects.create(
        attribute=attribute, name="Eco Mode", slug="eco"
    )
    attr_val_2 = AttributeValue.objects.create(
        attribute=attribute, name="Performance Mode", slug="power"
    )

    product_type.product_attributes.clear()
    product_type.product_attributes.add(attribute)

    associate_attribute_values_to_instance(product, attribute, attr_val_1, attr_val_2)
    return product


@pytest.fixture
def product_with_default_variant(product_type_without_variant, category, warehouse):
    product = Product.objects.create(
        name="<NAME>",
        price=Money(10, "USD"),
        product_type=product_type_without_variant,
        category=category,
        is_published=True,
    )
    variant = ProductVariant.objects.create(
        product=product, sku="1234", track_inventory=True
    )
    Stock.objects.create(warehouse=warehouse, product_variant=variant, quantity=100)
    return product


@pytest.fixture
def variant(product):
    product_variant = ProductVariant.objects.create(
        product=product, sku="SKU_A", cost_price=Money(1, "USD")
    )
    return product_variant


@pytest.fixture
def product_variant_list(product):
    return list(
        ProductVariant.objects.bulk_create(
            [
                ProductVariant(product=product, sku="1"),
                ProductVariant(product=product, sku="2"),
                ProductVariant(product=product, sku="3"),
            ]
        )
    )
{'fraction_non_alphanumeric': 0.09930545973046317, 'fraction_numerical': 0.00961317326709903, 'mean_word_length': 3.676597117659712, 'pattern_counts': {'":': 20, '<': 18, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '610445', 'n_tokens_mistral': 13663, 'n_tokens_neox': 13132, 'n_words': 2520}