class OrderLine(CountableDjangoObjectType): thumbnail = graphene.Field( Image, description="The main thumbnail for the ordered product.", size=graphene.Argument(graphene.Int, description="Size of thumbnail."), ) unit_price = graphene.Field( TaxedMoney, description="Price of the single item in the order line.", required=True, ) undiscounted_unit_price = graphene.Field( TaxedMoney, description=( "Price of the single item in the order line without applied an order line " "discount." ), required=True, ) unit_discount = graphene.Field( Money, description="The discount applied to the single order line.", required=True, ) unit_discount_value = graphene.Field( PositiveDecimal, description="Value of the discount. Can store fixed value or percent value", required=True, ) total_price = graphene.Field( TaxedMoney, description="Price of the order line.", required=True ) variant = graphene.Field( ProductVariant, required=False, description=( "A purchased product variant. Note: this field may be null if the variant " "has been removed from stock at all." ), ) translated_product_name = graphene.String( required=True, description="Product name in the customer's language" ) translated_variant_name = graphene.String( required=True, description="Variant name in the customer's language" ) allocations = graphene.List( graphene.NonNull(Allocation), description="List of allocations across warehouses.", ) quantity_to_fulfill = graphene.Int( required=True, description=f"{ADDED_IN_31} A quantity of items remaining to be fulfilled.", ) unit_discount_type = graphene.Field( DiscountValueTypeEnum, description="Type of the discount: fixed or percent", ) class Meta: description = "Represents order line of particular order." model = models.OrderLine interfaces = [relay.Node] only_fields = [ "digital_content_url", "id", "is_shipping_required", "product_name", "variant_name", "product_sku", "product_variant_id", "quantity", "quantity_fulfilled", "tax_rate", "unit_discount_reason", ] @staticmethod @traced_resolver def resolve_thumbnail(root: models.OrderLine, info, *, size=255): if not root.variant_id: return None def _get_image_from_media(image): url = get_product_image_thumbnail(image, size, method="thumbnail") alt = image.alt return Image(alt=alt, url=info.context.build_absolute_uri(url)) def _get_first_variant_image(all_medias): if image := next( ( media for media in all_medias if media.type == ProductMediaTypes.IMAGE ), None, ): return image def _get_first_product_image(images): return _get_image_from_media(images[0]) if images else None def _resolve_thumbnail(result): product, variant_medias = result if image := _get_first_variant_image(variant_medias): return _get_image_from_media(image) # we failed to get image from variant, lets use first from product return ( ProductImageByProductIdLoader(info.context) .load(product.id) .then(_get_first_product_image) )
class Query(graphene.ObjectType): hello = graphene.String( name=graphene.Argument(graphene.String, default_value="stranger")) def resolve_hello(self, args, context, info): return 'Hello ' + args['name']
class Arguments: tag_id = graphene.Int(required=True) tag_data = graphene.Argument(TagUpdateInput, required=True)
class Shop(graphene.ObjectType): available_payment_gateways = graphene.List( graphene.NonNull(PaymentGateway), currency=graphene.Argument( graphene.String, description="A currency for which gateways will be returned.", required=False, ), description="List of available payment gateways.", required=True, ) geolocalization = graphene.Field( Geolocalization, description="Customer's geolocalization data." ) authorization_keys = graphene.List( AuthorizationKey, description=( "List of configured authorization keys. Authorization keys are used to " "enable third-party OAuth authorization (currently Facebook or Google)." ), required=True, ) countries = graphene.List( graphene.NonNull(CountryDisplay), language_code=graphene.Argument( LanguageCodeEnum, description="A language code to return the translation for.", ), description="List of countries available in the shop.", required=True, ) currencies = graphene.List( graphene.String, description="List of available currencies.", required=True ) default_currency = graphene.String( description="Shop's default currency.", required=True ) default_country = graphene.Field( CountryDisplay, description="Shop's default country." ) default_mail_sender_name = graphene.String( description="Default shop's email sender's name." ) default_mail_sender_address = graphene.String( description="Default shop's email sender's address." ) description = graphene.String(description="Shop's description.") domain = graphene.Field(Domain, required=True, description="Shop's domain data.") homepage_collection = graphene.Field( Collection, description="Collection displayed on homepage." ) languages = graphene.List( LanguageDisplay, description="List of the shops's supported languages.", required=True, ) name = graphene.String(description="Shop's name.", required=True) navigation = graphene.Field(Navigation, description="Shop's navigation.") permissions = graphene.List( Permission, description="List of available permissions.", required=True ) phone_prefixes = graphene.List( graphene.String, description="List of possible phone prefixes.", required=True ) header_text = graphene.String(description="Header text.") include_taxes_in_prices = graphene.Boolean( description="Include taxes in prices.", required=True ) display_gross_prices = graphene.Boolean( description="Display prices with tax in store.", required=True ) charge_taxes_on_shipping = graphene.Boolean( description="Charge taxes on shipping.", required=True ) track_inventory_by_default = graphene.Boolean( description="Enable inventory tracking." ) default_weight_unit = WeightUnitsEnum(description="Default weight unit.") translation = TranslationField(ShopTranslation, type_name="shop", resolver=None) automatic_fulfillment_digital_products = graphene.Boolean( description="Enable automatic fulfillment for all digital products." ) default_digital_max_downloads = graphene.Int( description="Default number of max downloads per digital content URL." ) default_digital_url_valid_days = graphene.Int( description="Default number of days which digital content URL will be valid." ) company_address = graphene.Field( Address, description="Company address.", required=False ) customer_set_password_url = graphene.String( description="URL of a view where customers can set their password.", required=False, ) staff_notification_recipients = graphene.List( StaffNotificationRecipient, description="List of staff notification recipients.", required=False, ) class Meta: description = ( "Represents a shop resource containing general shop data and configuration." ) @staticmethod def resolve_available_payment_gateways(_, _info, currency: Optional[str] = None): return get_plugins_manager().list_payment_gateways(currency=currency) @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_authorization_keys(_, _info): return site_models.AuthorizationKey.objects.all() @staticmethod def resolve_countries(_, _info, language_code=None): taxes = {vat.country_code: vat for vat in VAT.objects.all()} with translation.override(language_code): return [ CountryDisplay( code=country[0], country=country[1], vat=taxes.get(country[0]) ) for country in filter(lambda c: c[0] == "MN" or c[0] == "GB", countries) ] @staticmethod def resolve_currencies(_, _info): return settings.AVAILABLE_CURRENCIES @staticmethod def resolve_domain(_, info): site = info.context.site return Domain( host=site.domain, ssl_enabled=settings.ENABLE_SSL, url=info.context.build_absolute_uri("/"), ) @staticmethod def resolve_geolocalization(_, info): client_ip = get_client_ip(info.context) country = get_country_by_ip(client_ip) if country: return Geolocalization( country=CountryDisplay(code=country.code, country=country.name) ) return Geolocalization(country=None) @staticmethod def resolve_default_currency(_, _info): return settings.DEFAULT_CURRENCY @staticmethod def resolve_description(_, info): return info.context.site.settings.description @staticmethod def resolve_homepage_collection(_, info): collection_pk = info.context.site.settings.homepage_collection_id qs = product_models.Collection.objects.all() return qs.filter(pk=collection_pk).first() @staticmethod def resolve_languages(_, _info): return [ LanguageDisplay( code=LanguageCodeEnum[str_to_enum(language[0])], language=language[1] ) for language in settings.LANGUAGES ] @staticmethod def resolve_name(_, info): return info.context.site.name @staticmethod def resolve_navigation(_, info): site_settings = info.context.site.settings main = ( MenuByIdLoader(info.context).load(site_settings.top_menu_id) if site_settings.top_menu_id else None ) secondary = ( MenuByIdLoader(info.context).load(site_settings.bottom_menu_id) if site_settings.bottom_menu_id else None ) return Navigation(main=main, secondary=secondary) @staticmethod def resolve_permissions(_, _info): permissions = get_permissions() return format_permissions_for_display(permissions) @staticmethod def resolve_phone_prefixes(_, _info): return list(COUNTRY_CODE_TO_REGION_CODE.keys()) @staticmethod def resolve_header_text(_, info): return info.context.site.settings.header_text @staticmethod def resolve_include_taxes_in_prices(_, info): return info.context.site.settings.include_taxes_in_prices @staticmethod def resolve_display_gross_prices(_, info): return info.context.site.settings.display_gross_prices @staticmethod def resolve_charge_taxes_on_shipping(_, info): return info.context.site.settings.charge_taxes_on_shipping @staticmethod def resolve_track_inventory_by_default(_, info): return info.context.site.settings.track_inventory_by_default @staticmethod def resolve_default_weight_unit(_, info): return info.context.site.settings.default_weight_unit @staticmethod def resolve_default_country(_, _info): default_country_code = settings.DEFAULT_COUNTRY default_country_name = countries.countries.get(default_country_code) if default_country_name: vat = VAT.objects.filter(country_code=default_country_code).first() default_country = CountryDisplay( code=default_country_code, country=default_country_name, vat=vat ) else: default_country = None return default_country @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_default_mail_sender_name(_, info): return info.context.site.settings.default_mail_sender_name @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_default_mail_sender_address(_, info): return info.context.site.settings.default_mail_sender_address @staticmethod def resolve_company_address(_, info): return info.context.site.settings.company_address @staticmethod def resolve_customer_set_password_url(_, info): return info.context.site.settings.customer_set_password_url @staticmethod def resolve_translation(_, info, language_code): return resolve_translation(info.context.site.settings, info, language_code) @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_automatic_fulfillment_digital_products(_, info): site_settings = info.context.site.settings return site_settings.automatic_fulfillment_digital_products @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_default_digital_max_downloads(_, info): return info.context.site.settings.default_digital_max_downloads @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_default_digital_url_valid_days(_, info): return info.context.site.settings.default_digital_url_valid_days @staticmethod @permission_required(SitePermissions.MANAGE_SETTINGS) def resolve_staff_notification_recipients(_, info): return account_models.StaffNotificationRecipient.objects.all()
def get_all_links_input_fields(): return { # this creates an input field using the LinkOrderBy custom enum 'order_by': graphene.Argument(LinkOrderBy) }
class Product(CountableDjangoObjectType, MetadataObjectType): url = graphene.String(description="The storefront URL for the product.", required=True) thumbnail = graphene.Field( Image, description="The main thumbnail for a product.", size=graphene.Argument(graphene.Int, description="Size of thumbnail."), ) pricing = graphene.Field( ProductPricingInfo, description= ("Lists the storefront product's pricing, the current price and discounts, " "only meant for displaying."), ) is_available = graphene.Boolean( description="Whether the product is in stock and visible or not.") base_price = graphene.Field( Money, description="The product's default base price.") minimal_variant_price = graphene.Field( Money, description="The price of the cheapest variant (including discounts).") tax_type = graphene.Field( TaxType, description="A type of tax. Assigned by enabled tax gateway") attributes = graphene.List( graphene.NonNull(SelectedAttribute), required=True, description="List of attributes assigned to this product.", ) purchase_cost = graphene.Field(MoneyRange) margin = graphene.Field(Margin) image_by_id = graphene.Field( lambda: ProductImage, id=graphene.Argument(graphene.ID, description="ID of a product image."), description="Get a single product image by ID.", ) variants = gql_optimizer.field( graphene.List(ProductVariant, description="List of variants for the product."), model_field="variants", ) images = gql_optimizer.field( graphene.List(lambda: ProductImage, description="List of images for the product."), model_field="images", ) collections = gql_optimizer.field( graphene.List(lambda: Collection, description="List of collections for the product."), model_field="collections", ) translation = TranslationField(ProductTranslation, type_name="product") slug = graphene.String(required=True, description="The slug of a product.") class Meta: description = "Represents an individual item for sale in the storefront." interfaces = [relay.Node] model = models.Product only_fields = [ "category", "charge_taxes", "description", "description_json", "id", "is_published", "name", "product_type", "publication_date", "seo_description", "seo_title", "updated_at", "weight", ] @staticmethod def resolve_tax_type(root: models.Product, info): tax_data = info.context.extensions.get_tax_code_from_object_meta(root) return TaxType(tax_code=tax_data.code, description=tax_data.description) @staticmethod @gql_optimizer.resolver_hints(prefetch_related="images") def resolve_thumbnail(root: models.Product, info, *, size=255): image = root.get_first_image() if image: url = get_product_image_thumbnail(image, size, method="thumbnail") alt = image.alt return Image(alt=alt, url=info.context.build_absolute_uri(url)) return None @staticmethod def resolve_url(root: models.Product, *_args): return root.get_absolute_url() @staticmethod @gql_optimizer.resolver_hints( prefetch_related=("variants", "collections"), only=[ "publication_date", "charge_taxes", "price_amount", "currency", "meta" ], ) def resolve_pricing(root: models.Product, info): context = info.context availability = get_product_availability( root, context.discounts, context.country, context.currency, context.extensions, ) return ProductPricingInfo(**asdict(availability)) @staticmethod @gql_optimizer.resolver_hints(prefetch_related=("variants")) def resolve_is_available(root: models.Product, _info): country = _info.context.country in_stock = is_product_in_stock(root, country) return root.is_visible and in_stock @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_base_price(root: models.Product, _info): return root.price @staticmethod @gql_optimizer.resolver_hints( prefetch_related=("variants", "collections"), only=[ "publication_date", "charge_taxes", "price_amount", "currency", "meta" ], ) def resolve_price(root: models.Product, info): price_range = root.get_price_range(info.context.discounts) price = info.context.extensions.apply_taxes_to_product( root, price_range.start, info.context.country) return price.net @staticmethod @gql_optimizer.resolver_hints(prefetch_related=[ Prefetch( "product_type__attributeproduct", queryset=models.AttributeProduct.objects.filter( attribute__visible_in_storefront=True).prefetch_related( "productassignments__values", "attribute"), to_attr="storefront_attributes", ) ]) def resolve_attributes(root: models.Product, info): return resolve_attribute_list(root, user=info.context.user) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_purchase_cost(root: models.Product, *_args): purchase_cost, _ = get_product_costs_data(root) return purchase_cost @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_margin(root: models.Product, *_args): _, margin = get_product_costs_data(root) return Margin(margin[0], margin[1]) @staticmethod def resolve_image_by_id(root: models.Product, info, id): pk = get_database_id(info, id, ProductImage) try: return root.images.get(pk=pk) except models.ProductImage.DoesNotExist: raise GraphQLError("Product image not found.") @staticmethod @gql_optimizer.resolver_hints(model_field="images") def resolve_images(root: models.Product, *_args, **_kwargs): return root.images.all() @staticmethod def resolve_variants(root: models.Product, *_args, **_kwargs): return root.variants.all() @staticmethod def resolve_collections(root: models.Product, *_args): return root.collections.all() @classmethod def get_node(cls, info, pk): if info.context: qs = cls._meta.model.objects.visible_to_user(info.context.user) return cls.maybe_optimize(info, qs, pk) return None @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_private_meta(root, _info): return resolve_private_meta(root, _info) @staticmethod def resolve_meta(root, _info): return resolve_meta(root, _info) @staticmethod def resolve_slug(root: models.Product, *_args): return root.get_slug() @staticmethod def __resolve_reference(root, _info, **_kwargs): return graphene.Node.get_node_from_global_id(_info, root.id)
class Page(CountableDjangoObjectType): content_json = graphene.JSONString( description="Content of the page (JSON).", deprecation_reason=( "Will be removed in Saleor 4.0. Use the `content` field instead." ), required=True, ) translation = TranslationField(PageTranslation, type_name="page") attributes = graphene.List( graphene.NonNull(SelectedAttribute), required=True, description="List of attributes assigned to this product.", ) media = graphene.List( graphene.NonNull(lambda: PageMedia), description="List of media for the page.", ) store = graphene.Field( Store, id=graphene.Argument(graphene.ID, description="ID of the store."), slug=graphene.Argument(graphene.String, description="Slug of the store"), description="Look up a store by ID or slug.", ) class Meta: description = ( "A static page that can be manually added by a shop operator through the " "dashboard." ) only_fields = [ "content", "created", "id", "is_published", "page_type", "publication_date", "seo_description", "seo_title", "slug", "title", "store", ] interfaces = [graphene.relay.Node, ObjectWithMetadata] model = models.Page @staticmethod def resolve_page_type(root: models.Page, info): return PageTypeByIdLoader(info.context).load(root.page_type_id) @staticmethod def resolve_content_json(root: models.Page, info): content = root.content return content if content is not None else {} @staticmethod def resolve_attributes(root: models.Page, info): return SelectedAttributesByPageIdLoader(info.context).load(root.id) @staticmethod def resolve_media(self, info, page=None, slug=None, channel=None, **_kwargs): return models.PageMedia.objects.filter(page_id=self.pk, is_active=True)
class Query(graphene.ObjectType): attributes = DjangoFilterConnectionField( ProductAttribute, filterset_class=DistinctFilterSet, query=graphene.String(description=DESCRIPTIONS['attributes']), in_category=graphene.Argument(graphene.ID), description='List of the shop\'s product attributes.') categories = DjangoFilterConnectionField( Category, filterset_class=DistinctFilterSet, query=graphene.String(description=DESCRIPTIONS['category']), level=graphene.Argument(graphene.Int), description='List of the shop\'s categories.') category = graphene.Field(Category, id=graphene.Argument(graphene.ID), description='Lookup a category by ID.') collection = graphene.Field(Collection, id=graphene.Argument(graphene.ID), description='Lookup a collection by ID.') collections = DjangoFilterConnectionField( Collection, query=graphene.String(description=DESCRIPTIONS['collection']), description='List of the shop\'s collections.') menu = graphene.Field(Menu, id=graphene.Argument(graphene.ID), description='Lookup a menu by ID.') menus = DjangoFilterConnectionField( Menu, query=graphene.String(description=DESCRIPTIONS['menu']), description="List of the shop\'s menus.") menu_item = graphene.Field(MenuItem, id=graphene.Argument(graphene.ID), description='Lookup a menu item by ID.') menu_items = DjangoFilterConnectionField( MenuItem, query=graphene.String(description=DESCRIPTIONS['menu_item']), description='List of the shop\'s menu items.') order = graphene.Field(Order, description='Lookup an order by ID.', id=graphene.Argument(graphene.ID)) orders = DjangoFilterConnectionField( Order, filterset_class=OrderFilter, query=graphene.String(description=DESCRIPTIONS['order']), description='List of the shop\'s orders.') page = graphene.Field( Page, id=graphene.Argument(graphene.ID), slug=graphene.String(description=DESCRIPTIONS['page']), description='Lookup a page by ID or by slug.') pages = DjangoFilterConnectionField( Page, filterset_class=DistinctFilterSet, query=graphene.String(), description='List of the shop\'s pages.') product = graphene.Field(Product, id=graphene.Argument(graphene.ID), description='Lookup a product by ID.') products = DjangoFilterConnectionField( Product, filterset_class=ProductFilterSet, query=graphene.String(description=DESCRIPTIONS['product']), description='List of the shop\'s products.') product_type = graphene.Field(ProductType, id=graphene.Argument(graphene.ID), description='Lookup a product type by ID.') product_types = DjangoFilterConnectionField( ProductType, filterset_class=DistinctFilterSet, description='List of the shop\'s product types.') product_variant = graphene.Field(ProductVariant, id=graphene.Argument(graphene.ID), description='Lookup a variant by ID.') sale = graphene.Field(Sale, id=graphene.Argument(graphene.ID), description='Lookup a sale by ID.') sales = DjangoFilterConnectionField( Sale, query=graphene.String(description=DESCRIPTIONS['sale']), description="List of the shop\'s sales.") shop = graphene.Field(Shop, description='Represents a shop resources.', resolver=resolve_shop) voucher = graphene.Field(Voucher, id=graphene.Argument(graphene.ID), description='Lookup a voucher by ID.') vouchers = DjangoFilterConnectionField( Voucher, query=graphene.String(description=DESCRIPTIONS['product']), description="List of the shop\'s vouchers.") shipping_method = graphene.Field( ShippingMethod, id=graphene.Argument(graphene.ID), description='Lookup a shipping method by ID.') shipping_methods = DjangoFilterConnectionField( ShippingMethod, description='List of the shop\'s shipping methods.') user = graphene.Field(User, id=graphene.Argument(graphene.ID), description='Lookup an user by ID.') users = DjangoFilterConnectionField( User, description='List of the shop\'s users.', query=graphene.String(description=DESCRIPTIONS['user'])) node = graphene.Node.Field() def resolve_attributes(self, info, in_category=None, query=None, **kwargs): return resolve_attributes(in_category, info, query) def resolve_category(self, info, id): return get_node(info, id, only_type=Category) def resolve_categories(self, info, level=None, query=None, **kwargs): return resolve_categories(info, level=level, query=query) def resolve_collection(self, info, id): return get_node(info, id, only_type=Collection) def resolve_collections(self, info, query=None, **kwargs): resolve_collections(info, query) def resolve_user(self, info, id): return resolve_user(info, id) def resolve_users(self, info, query=None, **kwargs): return resolve_users(info, query=query) def resolve_menu(self, info, id): return get_node(info, id, only_type=Menu) def resolve_menus(self, info, query=None, **kwargs): return resolve_menus(info, query) def resolve_menu_item(self, info, id): return get_node(info, id, only_type=MenuItem) def resolve_menu_items(self, info, query=None, **kwargs): return resolve_menu_items(info, query) def resolve_page(self, info, id=None, slug=None): return resolve_page(info, id, slug) def resolve_pages(self, info, query=None, **kwargs): return resolve_pages(user=info.context.user, query=query) def resolve_order(self, info, id): return resolve_order(info, id) def resolve_orders(self, info, query=None, **kwargs): return resolve_orders(info, query) def resolve_product(self, info, id): return get_node(info, id, only_type=Product) def resolve_products(self, info, category_id=None, query=None, **kwargs): return resolve_products(info, category_id, query) def resolve_product_type(self, info, id): return get_node(info, id, only_type=ProductType) def resolve_product_types(self, info, **kwargs): return resolve_product_types() @permission_required('discount.view_sale') def resolve_sale(self, info, id): return get_node(info, id, only_type=Sale) @permission_required('discount.view_sale') def resolve_sales(self, info, query=None, **kwargs): return resolve_sales(info, query) def resolve_product_variant(self, info, id): return get_node(info, id, only_type=ProductVariant) @permission_required('discount.view_voucher') def resolve_voucher(self, info, id): return get_node(info, id, only_type=Voucher) @permission_required('discount.view_voucher') def resolve_vouchers(self, info, query=None, **kwargs): return resolve_vouchers(info, query) def resolve_shipping_method(self, info, id): return get_node(info, id, only_type=ShippingMethod) def resolve_shipping_methods(self, info, **kwargs): return resolve_shipping_methods(info)
return evalg.proc.pollbook.get_voters_in_election_group( session, election_group_id, **kwargs).all() def resolve_voters_by_person_id(_, info, **kwargs): person_id = kwargs['id'] session = get_session(info) person = session.query(evalg.models.person.Person).get(person_id) return evalg.proc.pollbook.get_voters_for_person(session, person).all() search_voters_query = graphene.List( Voter, resolver=resolve_search_voters, election_group_id=graphene.Argument(graphene.UUID, required=True), self_added=graphene.Argument(graphene.Boolean, required=False), reviewed=graphene.Argument(graphene.Boolean, required=False), verified=graphene.Argument(graphene.Boolean, required=False), has_voted=graphene.Argument(graphene.Boolean, required=False), limit=graphene.Argument(graphene.Int, required=False), search=graphene.Argument(graphene.String, required=False), pollbook_id=graphene.Argument(graphene.UUID, required=False), ) # TODO: Re-design person-voter relationship find_voters_query = graphene.List(Voter, resolver=resolve_voters_by_person_id, id=graphene.Argument(graphene.UUID, required=True))
class OrderLine(CountableDjangoObjectType): thumbnail = graphene.Field( Image, description="The main thumbnail for the ordered product.", size=graphene.Argument(graphene.Int, description="Size of thumbnail."), ) unit_price = graphene.Field( TaxedMoney, description="Price of the single item in the order line." ) variant = graphene.Field( ProductVariant, required=False, description=( "A purchased product variant. Note: this field may be null if the variant " "has been removed from stock at all." ), ) translated_product_name = graphene.String( required=True, description="Product name in the customer's language" ) translated_variant_name = graphene.String( required=True, description="Variant name in the customer's language" ) class Meta: description = "Represents order line of particular order." model = models.OrderLine interfaces = [relay.Node] only_fields = [ "digital_content_url", "id", "is_shipping_required", "product_name", "variant_name", "product_sku", "quantity", "quantity_fulfilled", "tax_rate", ] @staticmethod @gql_optimizer.resolver_hints( prefetch_related=["variant__images", "variant__product__images"] ) def resolve_thumbnail(root: models.OrderLine, info, *, size=255): if not root.variant: return None image = root.variant.get_first_image() if image: url = get_product_image_thumbnail(image, size, method="thumbnail") alt = image.alt return Image(alt=alt, url=info.context.build_absolute_uri(url)) return None @staticmethod def resolve_unit_price(root: models.OrderLine, _info): return root.unit_price @staticmethod def resolve_translated_product_name(root: models.OrderLine, _info): return root.translated_product_name @staticmethod def resolve_translated_variant_name(root: models.OrderLine, _info): return root.translated_variant_name
class Input: availability = graphene.Argument(EditMatchAvailabilityInput)
class Query(graphene.ObjectType): hospitals = relay.ConnectionField( HospitalConnection, order_by=graphene.Argument(HospitalSortField, required=False, default_value="distance"), descending=graphene.Boolean(default_value=False, required=False), category_filters=graphene.List(graphene.String, required=False, default_value=[]), search_query=graphene.String(required=False, default_value='')) hospital = graphene.Field(HospitalType, id=graphene.NonNull(graphene.ID), lat=graphene.Float(default_value=0), lon=graphene.Float(default_value=0)) localities = relay.ConnectionField(LocalityConnection) locality = graphene.Field(LocalityType, name=graphene.String()) country = graphene.Field(CountryType) def resolve_hospitals(parent, info, order_by, descending, category_filters, lat, lon, search_query, **kwargs): info.context.coords = {"lat": lat, "lon": lon} coords = Point(lon, lat, srid=4326) def get_hospitals(order): joins = ''' FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available general_available, total general_total, (total - available) general_occupied FROM "Equipment" WHERE category = 'gen' ORDER BY branch_id, time DESC ) AS eq_gen ON eq_gen.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available icu_available, total icu_total, (total - available) icu_occupied FROM "Equipment" WHERE category = 'ICU' ORDER BY branch_id, time DESC ) AS eq_ICU ON eq_ICU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available hdu_available, total hdu_total, (total - available) hdu_occupied FROM "Equipment" WHERE category = 'HDU' ORDER BY branch_id, time DESC ) AS eq_HDU ON eq_HDU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available ventilators_available, total ventilators_total, (total - available) ventilators_occupied FROM "Equipment" WHERE category = 'vent' ORDER BY branch_id, time DESC ) AS eq_vent ON eq_vent.branch_id = hos.id ''' selections = ''' eq_HDU.hdu_available, eq_HDU.hdu_total, eq_HDU.hdu_occupied, eq_gen.general_available, eq_gen.general_total, eq_gen.general_occupied, eq_ICU.icu_available, eq_ICU.icu_total, eq_ICU.icu_occupied, eq_vent.ventilators_available, eq_vent.ventilators_total, eq_vent.ventilators_occupied, hos.name, hos.website, hos.phone, hos.location, hos.city, hos.district, hos.state, hos.country, hos.postal_code, hos.place_id, hos.address, hos.category, hos.locality_id, encode(('Hospital:' || hos.id)::bytea, 'base64') id, ST_X(hos.location::geometry) as longitude, ST_Y(hos.location::geometry) as latitude, ((hos."location" <-> %s::geometry) / 1000) AS distance ''' cursor = connection.cursor() if len(category_filters) > 0: where_claus = 'WHERE hos.name ILIKE %s AND hos.category IN %s' escaped_strings = [ str(coords), '%' + search_query + '%', tuple(category_filters) ] else: where_claus = 'WHERE hos.name ILIKE %s' escaped_strings = [str(coords), '%' + search_query + '%'] query = f''' SELECT * FROM ( SELECT {selections} FROM "Hospitals" AS hos {joins} {where_claus} ) data ORDER BY COALESCE({order}, {"''" if order == 'name' else 0}) {'DESC' if descending else 'ASC'} ''' cursor.execute(query, escaped_strings) return namedtuplefetch(cursor, "Hospital") o = order_by if o not in ("distance", "name"): o = o.split("_")[::-1] o = '_'.join(o) hospitals = get_hospitals(o) return hospitals def resolve_hospital(parent, info, id, lat, lon, **kwargs): coords = Point(lon, lat, srid=4326) def namedtuplefetch(cursor): desc = cursor.description nt_result = namedtuple('Hospital', [col[0] for col in desc]) return [nt_result(*row) for row in cursor.fetchall()] joins = ''' FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available general_available, total general_total, (total - available) general_occupied FROM "Equipment" WHERE category = 'gen' ORDER BY branch_id, time DESC ) AS eq_gen ON eq_gen.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available icu_available, total icu_total, (total - available) icu_occupied FROM "Equipment" WHERE category = 'ICU' ORDER BY branch_id, time DESC ) AS eq_ICU ON eq_ICU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available hdu_available, total hdu_total, (total - available) hdu_occupied FROM "Equipment" WHERE category = 'HDU' ORDER BY branch_id, time DESC ) AS eq_HDU ON eq_HDU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available ventilators_available, total ventilators_total, (total - available) ventilators_occupied FROM "Equipment" WHERE category = 'vent' ORDER BY branch_id, time DESC ) AS eq_vent ON eq_vent.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available oxygen_available, total oxygen_total, (total - available) oxygen_occupied FROM "Equipment" WHERE category = 'oxy' ORDER BY branch_id, time DESC ) AS eq_oxy ON eq_oxy.branch_id = hos.id ''' selections = ''' eq_HDU.hdu_available, eq_HDU.hdu_total, eq_HDU.hdu_occupied, eq_gen.general_available, eq_gen.general_total, eq_gen.general_occupied, eq_oxy.oxygen_available, eq_oxy.oxygen_total, eq_oxy.oxygen_occupied, eq_vent.ventilators_available, eq_vent.ventilators_total, eq_vent.ventilators_occupied, eq_ICU.icu_available, eq_ICU.icu_total, eq_ICU.icu_occupied, hos.name, hos.website, hos.phone, hos.location, hos.city, hos.district, hos.state, hos.country, hos.postal_code, hos.place_id, hos.address, hos.category, hos.locality_id, encode(('Hospital:' || hos.id)::bytea, 'base64') id, ST_X(hos.location::geometry) as longitude, ST_Y(hos.location::geometry) as latitude, ((hos."location" <-> %s::geometry) / 1000) AS distance ''' query = f''' SELECT {selections} FROM "Hospitals" AS hos {joins} WHERE id=%s ''' cursor = connection.cursor() cursor.execute(query, [str(coords), get_id(id)]) hospital = namedtuplefetch(cursor)[0] return hospital def resolve_localities(parent, info, **kwargs): localities = Locality.objects.raw(""" SELECT "Locality".*, MAX(c.time) as last_updated, SUM(c.total) total, SUM(c.available) available, SUM(c.occupied) occupied FROM "Locality" INNER JOIN ( SELECT hos.id, hos.name, hos.locality_id, SUM(available) available, SUM(total) total, SUM(total - available) occupied, a.time FROM "Hospitals" as hos INNER JOIN ( SELECT MAX(time) as time, branch_id FROM "Equipment" GROUP BY branch_id ) AS a ON a.branch_id = hos.id INNER JOIN ( SELECT available, total, category, branch_id, time FROM "Equipment" ) AS b on b.branch_id = hos.id AND b.time = a.time WHERE hos.category != 'pri covid' OR hos.category IS null GROUP BY hos.id, a.time ORDER BY hos.name ) c on "Locality".id = c.locality_id GROUP BY "Locality".id """) return localities def resolve_locality(parent, info, name, **kwargs): name = ' '.join(name.split('-')) locality = Locality.objects.raw( """ SELECT "Locality".*, MAX(c.time) as last_updated, SUM(c.total) total, SUM(c.available) available, SUM(c.occupied) occupied FROM "Locality" INNER JOIN ( SELECT hos.id, hos.name, hos.locality_id, SUM(available) available, SUM(total) total, SUM(total - available) occupied, a.time FROM "Hospitals" as hos INNER JOIN ( SELECT MAX(time) as time, branch_id FROM "Equipment" GROUP BY branch_id ) AS a ON a.branch_id = hos.id INNER JOIN ( SELECT available, total, category, branch_id, time FROM "Equipment" ) AS b on b.branch_id = hos.id AND b.time = a.time WHERE hos.category != 'pri covid' OR hos.category IS null GROUP BY hos.id, a.time ORDER BY hos.name ) c on "Locality".id = c.locality_id WHERE ("Locality".name || ' ' || "Locality".state ILIKE %s) GROUP BY "Locality".id """, [name]) if len(locality) == 0: raise KeyError("Invalid locality passed") return locality[0] def resolve_country(parent, info, **kwargs): query = """ SELECT SUM(total) total, SUM(available) available, SUM(occupied) occupied, MAX(last_updated) last_updated FROM ( SELECT "Locality".*, MAX(c.time) as last_updated, SUM(c.total) total, SUM(c.available) available, SUM(c.occupied) occupied FROM "Locality" INNER JOIN ( SELECT hos.id, hos.name, hos.locality_id, SUM(available) available, SUM(total) total, SUM(total - available) occupied, a.time FROM "Hospitals" as hos INNER JOIN ( SELECT MAX(time) as time, branch_id FROM "Equipment" GROUP BY branch_id ) AS a ON a.branch_id = hos.id INNER JOIN ( SELECT available, total, category, branch_id, time FROM "Equipment" ) AS b on b.branch_id = hos.id AND b.time = a.time GROUP BY hos.id, a.time ORDER BY hos.name ) c on "Locality".id = c.locality_id GROUP BY "Locality".id ) d """ cursor = connection.cursor() cursor.execute(query) return namedtuplefetch(cursor, "Country")[0]
class LocalityType(DjangoObjectType): total = graphene.Int() available = graphene.Int() occupied = graphene.Int() last_updated = graphene.Float() hospitals = relay.ConnectionField( HospitalConnection, order_by=graphene.Argument(HospitalSortField, required=False, default_value="distance"), descending=graphene.Boolean(default_value=False, required=False), category_filters=graphene.List(graphene.String, required=False, default_value=[]), lat=graphene.Float(required=False, default_value=0), lon=graphene.Float(required=False, default_value=0), search_query=graphene.String(required=False, default_value='')) def resolve_hospitals(locality, info, order_by, descending, category_filters, lat, lon, search_query, **kwargs): info.context.coords = {"lat": lat, "lon": lon} coords = Point(lon, lat, srid=4326) def get_hospitals(order): joins = ''' FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available general_available, total general_total, (total - available) general_occupied FROM "Equipment" WHERE category = 'gen' ORDER BY branch_id, time DESC ) AS eq_gen ON eq_gen.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available icu_available, total icu_total, (total - available) icu_occupied FROM "Equipment" WHERE category = 'ICU' ORDER BY branch_id, time DESC ) AS eq_ICU ON eq_ICU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available hdu_available, total hdu_total, (total - available) hdu_occupied FROM "Equipment" WHERE category = 'HDU' ORDER BY branch_id, time DESC ) AS eq_HDU ON eq_HDU.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available ventilators_available, total ventilators_total, (total - available) ventilators_occupied FROM "Equipment" WHERE category = 'vent' ORDER BY branch_id, time DESC ) AS eq_vent ON eq_vent.branch_id = hos.id FULL OUTER JOIN ( SELECT DISTINCT ON (branch_id) branch_id, available oxygen_available, total oxygen_total, (total - available) oxygen_occupied FROM "Equipment" WHERE category = 'oxy' ORDER BY branch_id, time DESC ) AS eq_oxy ON eq_oxy.branch_id = hos.id ''' selections = ''' eq_HDU.hdu_available, eq_HDU.hdu_total, eq_HDU.hdu_occupied, eq_gen.general_available, eq_gen.general_total, eq_gen.general_occupied, eq_oxy.oxygen_available, eq_oxy.oxygen_total, eq_oxy.oxygen_occupied, eq_ICU.icu_available, eq_ICU.icu_total, eq_ICU.icu_occupied, eq_vent.ventilators_available, eq_vent.ventilators_total, eq_vent.ventilators_occupied, hos.name, hos.website, hos.phone, hos.location, hos.city, hos.district, hos.state, hos.country, hos.postal_code, hos.place_id, hos.address, hos.category, hos.locality_id, encode(('Hospital:' || hos.id)::bytea, 'base64') id, ST_X(hos.location::geometry) as longitude, ST_Y(hos.location::geometry) as latitude, ((hos."location" <-> %s::geometry) / 1000) AS distance ''' cursor = connection.cursor() if len(category_filters) > 0: where_claus = 'WHERE hos.name ILIKE %s AND hos.category IN %s' escaped_strings = [ str(coords), '%' + search_query + '%', tuple(category_filters) ] else: where_claus = 'WHERE hos.name ILIKE %s' escaped_strings = [str(coords), '%' + search_query + '%'] query = f''' SELECT * FROM ( SELECT {selections} FROM "Hospitals" AS hos {joins} {where_claus} ) data WHERE data.locality_id = {locality.id} AND distance IS NOT NULL AND (data.category != 'pri covid' OR data.category IS null) AND (data.hdu_total IS NOT NULL OR data.icu_total IS NOT NULL OR data.ventilators_total IS NOT NULL or general_total IS NOT NULL) ORDER BY COALESCE({order}, {"''" if order == 'name' else 0}) {'DESC' if descending else 'ASC'} ''' cursor.execute(query, escaped_strings) return namedtuplefetch(cursor, "Hospital") o = order_by if o not in ("distance", "name"): o = o.split("_")[::-1] o = '_'.join(o) hospitals = get_hospitals(o) return hospitals class Meta: model = Locality name = "Locality" interfaces = (relay.Node, )
class Arguments: userInput = graphene.Argument(UserInput)
class Product(CountableDjangoObjectType): url = graphene.String(description='The storefront URL for the product.', required=True) thumbnail_url = graphene.String( description='The URL of a main thumbnail for a product.', size=graphene.Argument(graphene.Int, description='Size of thumbnail')) availability = graphene.Field( ProductAvailability, description="""Informs about product's availability in the storefront, current price and discounts.""") price = graphene.Field( Money, description="""The product's base price (without any discounts applied).""") attributes = graphene.List( SelectedAttribute, description='List of attributes assigned to this product.') purchase_cost = graphene.Field(MoneyRange) margin = graphene.Field(Margin) image_by_id = graphene.Field( lambda: ProductImage, id=graphene.Argument(graphene.ID, description='ID of a product image.'), description='Get a single product image by ID') class Meta: description = """Represents an individual item for sale in the storefront.""" interfaces = [relay.Node] model = models.Product def resolve_thumbnail_url(self, info, *, size=None): if not size: size = 255 return get_thumbnail(self.get_first_image(), size, method='thumbnail') def resolve_url(self, info): return self.get_absolute_url() def resolve_availability(self, info): context = info.context availability = get_availability(self, context.discounts, context.taxes, context.currency) return ProductAvailability(**availability._asdict()) def resolve_attributes(self, info): return resolve_attribute_list(self.attributes) def resolve_product_type(self, info): return self.product_type @permission_required('product.manage_products') def resolve_purchase_cost(self, info): purchase_cost, _ = get_product_costs_data(self) return purchase_cost @permission_required('product.manage_products') def resolve_margin(self, info): _, margin = get_product_costs_data(self) return Margin(margin[0], margin[1]) def resolve_image_by_id(self, info, id): pk = get_database_id(info, id, ProductImage) try: return self.images.get(pk=pk) except models.ProductImage.DoesNotExist: raise GraphQLError('Product image not found.')
class ProductChannelListing(CountableDjangoObjectType): discounted_price = graphene.Field( Money, description="The price of the cheapest variant (including discounts).") purchase_cost = graphene.Field(MoneyRange, description="Purchase cost of product.") margin = graphene.Field(Margin, description="Range of margin percentage value.") is_available_for_purchase = graphene.Boolean( description="Whether the product is available for purchase.") pricing = graphene.Field( "saleor.graphql.product.types.products.ProductPricingInfo", address=graphene.Argument( account_types.AddressInput, description= ("Destination address used to find warehouses where stock availability " "for this product is checked. If address is empty, uses " "`Shop.companyAddress` or fallbacks to server's " "`settings.DEFAULT_COUNTRY` configuration."), ), description= ("Lists the storefront product's pricing, the current price and discounts, " "only meant for displaying."), ) class Meta: description = "Represents product channel listing." model = models.ProductChannelListing interfaces = [graphene.relay.Node] only_fields = [ "id", "channel", "is_published", "publication_date", "visible_in_listings", "available_for_purchase", ] @staticmethod def resolve_channel(root: models.ProductChannelListing, info, **_kwargs): return ChannelByIdLoader(info.context).load(root.channel_id) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_purchase_cost(root: models.ProductChannelListing, info, *_kwargs): channel = ChannelByIdLoader(info.context).load(root.channel_id) def calculate_margin_with_variants(variants): def calculate_margin_with_channel(channel): def calculate_margin_with_channel_listings( variant_channel_listings): variant_channel_listings = list( filter(None, variant_channel_listings)) if not variant_channel_listings: return None has_variants = True if len( variant_ids_channel_slug) > 0 else False purchase_cost, _margin = get_product_costs_data( variant_channel_listings, has_variants, root.currency) return purchase_cost variant_ids_channel_slug = [(variant.id, channel.slug) for variant in variants] return (VariantChannelListingByVariantIdAndChannelSlugLoader( info.context).load_many(variant_ids_channel_slug).then( calculate_margin_with_channel_listings)) return channel.then(calculate_margin_with_channel) return (ProductVariantsByProductIdLoader(info.context).load( root.product_id).then(calculate_margin_with_variants)) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_margin(root: models.ProductChannelListing, info, *_kwargs): channel = ChannelByIdLoader(info.context).load(root.channel_id) def calculate_margin_with_variants(variants): def calculate_margin_with_channel(channel): def calculate_margin_with_channel_listings( variant_channel_listings): variant_channel_listings = list( filter(None, variant_channel_listings)) if not variant_channel_listings: return None has_variants = True if len( variant_ids_channel_slug) > 0 else False _purchase_cost, margin = get_product_costs_data( variant_channel_listings, has_variants, root.currency) return Margin(margin[0], margin[1]) variant_ids_channel_slug = [(variant.id, channel.slug) for variant in variants] return (VariantChannelListingByVariantIdAndChannelSlugLoader( info.context).load_many(variant_ids_channel_slug).then( calculate_margin_with_channel_listings)) return channel.then(calculate_margin_with_channel) return (ProductVariantsByProductIdLoader(info.context).load( root.product_id).then(calculate_margin_with_variants)) @staticmethod def resolve_is_available_for_purchase(root: models.ProductChannelListing, _info): return root.is_available_for_purchase() @staticmethod def resolve_pricing(root: models.ProductChannelListing, info, address=None): context = info.context country_code = get_user_country_context( address, info.context.site.settings.company_address) def calculate_pricing_info(discounts): def calculate_pricing_with_channel(channel): def calculate_pricing_with_product(product): def calculate_pricing_with_variants(variants): def calculate_pricing_with_variants_channel_listings( variants_channel_listing, ): def calculate_pricing_with_collections( collections): if not variants_channel_listing: return None availability = get_product_availability( product=product, product_channel_listing=root, variants=variants, variants_channel_listing= variants_channel_listing, collections=collections, discounts=discounts, channel=channel, manager=context.plugins, country=Country(country_code), local_currency=get_currency_for_country( country_code), ) from .products import ProductPricingInfo return ProductPricingInfo( **asdict(availability)) return (CollectionsByProductIdLoader(context).load( root.product_id).then( calculate_pricing_with_collections)) return ( VariantsChannelListingByProductIdAndChanneSlugLoader( context).load((root.product_id, channel.slug)). then( calculate_pricing_with_variants_channel_listings )) return (ProductVariantsByProductIdLoader(context).load( root.product_id).then(calculate_pricing_with_variants)) return (ProductByIdLoader(context).load( root.product_id).then(calculate_pricing_with_product)) return (ChannelByIdLoader(context).load( root.channel_id).then(calculate_pricing_with_channel)) return (DiscountsByDateTimeLoader(context).load( info.context.request_time).then(calculate_pricing_info))
class ProductVariant(CountableDjangoObjectType, MetadataObjectType): quantity = graphene.Int( required=True, description="Quantity of a product in the store's possession, " "including the allocated stock that is waiting for shipment.", deprecation_reason="This field will be removed in Saleor 2.11. " "Use the stock field instead.", ) quantity_allocated = graphene.Int( required=False, description="Quantity allocated for orders", deprecation_reason="This field will be removed in Saleor 2.11. " "Use the stock field instead.", ) stock_quantity = graphene.Int( required=True, description="Quantity of a product available for sale.", deprecation_reason="This field will be removed in Saleor 2.11. " "Use the stock field instead.", ) price_override = graphene.Field( Money, description= ("Override the base price of a product if necessary. A value of `null` " "indicates that the default product price is used."), ) pricing = graphene.Field( VariantPricingInfo, description= ("Lists the storefront variant's pricing, the current price and discounts, " "only meant for displaying."), ) is_available = graphene.Boolean( description="Whether the variant is in stock and visible or not.", deprecation_reason="This field will be removed in Saleor 2.11. " "Use the stock field instead.", ) attributes = gql_optimizer.field( graphene.List( graphene.NonNull(SelectedAttribute), required=True, description="List of attributes assigned to this variant.", )) cost_price = graphene.Field(Money, description="Cost price of the variant.") margin = graphene.Int(description="Gross margin percentage value.") quantity_ordered = graphene.Int(description="Total quantity ordered.") revenue = graphene.Field( TaxedMoney, period=graphene.Argument(ReportingPeriod), description= ("Total revenue generated by a variant in given period of time. Note: this " "field should be queried using `reportProductSales` query as it uses " "optimizations suitable for such calculations."), ) images = gql_optimizer.field( graphene.List(lambda: ProductImage, description="List of images for the product variant."), model_field="images", ) translation = TranslationField(ProductVariantTranslation, type_name="product variant") digital_content = gql_optimizer.field( graphene.Field(DigitalContent, description="Digital content for the product variant."), model_field="digital_content", ) stock = gql_optimizer.field( graphene.Field( graphene.List(Stock), description="Stocks for the product variant.", country=graphene.String(required=False), )) class Meta: description = ( "Represents a version of a product such as different size or color." ) only_fields = [ "id", "name", "product", "sku", "track_inventory", "weight" ] interfaces = [relay.Node] model = models.ProductVariant @staticmethod def resolve_stock(root: models.ProductVariant, info, country=None): if country is None: return gql_optimizer.query( root.stock.annotate_available_quantity().all(), info) return gql_optimizer.query( root.stock.annotate_available_quantity().for_country( "country").all(), info) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_digital_content(root: models.ProductVariant, *_args): return getattr(root, "digital_content", None) @staticmethod def resolve_stock_quantity(root: models.ProductVariant, info): country = info.context.country try: stock = stock_models.Stock.objects.get_variant_stock_for_country( country, root) except stock_models.Stock.DoesNotExist: return 0 return get_available_quantity_for_customer(stock) @staticmethod @gql_optimizer.resolver_hints(prefetch_related=[ "attributes__values", "attributes__assignment__attribute" ]) def resolve_attributes(root: models.ProductVariant, info): return resolve_attribute_list(root, user=info.context.user) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_margin(root: models.ProductVariant, *_args): return get_margin_for_variant(root) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_cost_price(root: models.ProductVariant, *_args): return root.cost_price @staticmethod def resolve_price(root: models.ProductVariant, *_args): return root.base_price @staticmethod @gql_optimizer.resolver_hints(prefetch_related=("product", ), only=["price_override_amount", "currency"]) def resolve_pricing(root: models.ProductVariant, info): context = info.context availability = get_variant_availability( root, context.discounts, context.country, context.currency, extensions=context.extensions, ) return VariantPricingInfo(**asdict(availability)) @staticmethod def resolve_is_available(root: models.ProductVariant, info): country = info.context.country return is_variant_in_stock(root, country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_price_override(root: models.ProductVariant, *_args): return root.price_override @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity(root: models.ProductVariant, info): return get_available_quantity(root, info.context.country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity_ordered(root: models.ProductVariant, *_args): # This field is added through annotation when using the # `resolve_report_product_sales` resolver. return getattr(root, "quantity_ordered", None) @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity_allocated(root: models.ProductVariant, info): country = info.context.country return get_quantity_allocated(root, country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_revenue(root: models.ProductVariant, *_args, period): start_date = reporting_period_to_date(period) return calculate_revenue_for_variant(root, start_date) @staticmethod def resolve_images(root: models.ProductVariant, *_args): return root.images.all() @classmethod def get_node(cls, info, id): user = info.context.user visible_products = models.Product.objects.visible_to_user( user).values_list("pk", flat=True) qs = cls._meta.model.objects.filter(product__id__in=visible_products) return cls.maybe_optimize(info, qs, id) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_private_meta(root, _info): return resolve_private_meta(root, _info) @staticmethod def resolve_meta(root, _info): return resolve_meta(root, _info) @staticmethod def __resolve_reference(root, _info, **_kwargs): return graphene.Node.get_node_from_global_id(_info, root.id)
class OrderLine(CountableDjangoObjectType): thumbnail = graphene.Field( Image, description="The main thumbnail for the ordered product.", size=graphene.Argument(graphene.Int, description="Size of thumbnail."), ) unit_price = graphene.Field( TaxedMoney, description="Price of the single item in the order line.") total_price = graphene.Field( TaxedMoney, description="Price of the order line.", ) variant = graphene.Field( ProductVariant, required=False, description= ("A purchased product variant. Note: this field may be null if the variant " "has been removed from stock at all."), ) translated_product_name = graphene.String( required=True, description="Product name in the customer's language") translated_variant_name = graphene.String( required=True, description="Variant name in the customer's language") allocations = graphene.List( graphene.NonNull(Allocation), description="List of allocations across warehouses.", ) class Meta: description = "Represents order line of particular order." model = models.OrderLine interfaces = [relay.Node] only_fields = [ "digital_content_url", "id", "is_shipping_required", "product_name", "variant_name", "product_sku", "quantity", "quantity_fulfilled", "tax_rate", ] @staticmethod def resolve_thumbnail(root: models.OrderLine, info, *, size=255): if not root.variant: return None image = root.variant.get_first_image() if image: url = get_product_image_thumbnail(image, size, method="thumbnail") alt = image.alt return Image(alt=alt, url=info.context.build_absolute_uri(url)) return None @staticmethod def resolve_unit_price(root: models.OrderLine, _info): return root.unit_price @staticmethod def resolve_total_price(root: models.OrderLine, _info): return root.total_price @staticmethod def resolve_translated_product_name(root: models.OrderLine, _info): return root.translated_product_name @staticmethod def resolve_translated_variant_name(root: models.OrderLine, _info): return root.translated_variant_name @staticmethod def resolve_variant(root: models.OrderLine, info): dataloader = ChannelByOrderLineIdLoader(info.context) return resolve_variant(info, root, dataloader) @staticmethod @one_of_permissions_required( [ProductPermissions.MANAGE_PRODUCTS, OrderPermissions.MANAGE_ORDERS]) def resolve_allocations(root: models.OrderLine, info): return AllocationsByOrderLineIdLoader(info.context).load(root.id)
class Attribute(CountableDjangoObjectType, MetadataObjectType): input_type = AttributeInputTypeEnum( description=AttributeDescriptions.INPUT_TYPE) name = graphene.String(description=AttributeDescriptions.NAME) slug = graphene.String(description=AttributeDescriptions.SLUG) values = gql_optimizer.field( graphene.List(AttributeValue, description=AttributeDescriptions.VALUES), model_field="values", ) value_required = graphene.Boolean( description=AttributeDescriptions.VALUE_REQUIRED, required=True) visible_in_storefront = graphene.Boolean( description=AttributeDescriptions.VISIBLE_IN_STOREFRONT, required=True) filterable_in_storefront = graphene.Boolean( description=AttributeDescriptions.FILTERABLE_IN_STOREFRONT, required=True) filterable_in_dashboard = graphene.Boolean( description=AttributeDescriptions.FILTERABLE_IN_DASHBOARD, required=True) available_in_grid = graphene.Boolean( description=AttributeDescriptions.AVAILABLE_IN_GRID, required=True) translation = graphene.Field( AttributeTranslation, language_code=graphene.Argument( LanguageCodeEnum, description="A language code to return the translation for.", required=True, ), description=("Returns translated Attribute fields " "for the given language code."), resolver=resolve_translation, ) storefront_search_position = graphene.Int( description=AttributeDescriptions.STOREFRONT_SEARCH_POSITION, required=True) class Meta: description = ( "Custom attribute of a product. Attributes can be assigned to products and " "variants at the product type level.") only_fields = ["id", "product_types", "product_variant_types"] interfaces = [relay.Node] model = models.Attribute @staticmethod def resolve_values(root: models.Attribute, *_args): return root.values.all() @staticmethod @permission_required("product.manage_products") def resolve_private_meta(root, _info): return resolve_private_meta(root, _info) @staticmethod def resolve_meta(root, _info): return resolve_meta(root, _info) @staticmethod @permission_required("product.manage_products") def resolve_value_required(root: models.Attribute, *_args): return root.value_required @staticmethod @permission_required("product.manage_products") def resolve_visible_in_storefront(root: models.Attribute, *_args): return root.visible_in_storefront @staticmethod @permission_required("product.manage_products") def resolve_filterable_in_storefront(root: models.Attribute, *_args): return root.filterable_in_storefront @staticmethod @permission_required("product.manage_products") def resolve_filterable_in_dashboard(root: models.Attribute, *_args): return root.filterable_in_dashboard @staticmethod @permission_required("product.manage_products") def resolve_storefront_search_position(root: models.Attribute, *_args): return root.storefront_search_position @staticmethod @permission_required("product.manage_products") def resolve_available_in_grid(root: models.Attribute, *_args): return root.available_in_grid
class Query: workouts = graphene.List( WorkoutType, status=graphene.Argument(WorkoutStatusesEnum), limit=graphene.Int(required=False), ) exercise_types = graphene.List(ExerciseTypeType) popular_exercise_types = graphene.List(ExerciseTypeType) exercises = graphene.List(ExerciseType, workout_id=graphene.Int(required=True)) sets = graphene.List(SetType, exercise_id=graphene.Int(required=True)) workout = graphene.Field(WorkoutType, workout_id=graphene.Int(required=True)) exercise = graphene.Field(ExerciseType, exercise_id=graphene.Int(required=True)) muscle_groups = graphene.List(MuscleGroupType) @staticmethod def resolve_muscle_groups(_, info): return MuscleGroup.objects.filter(is_active=True) @staticmethod def resolve_workouts(_, info, status=None, limit=None): user = info.context.user filter_args = {"user": user, "is_active": True} if status: filter_args["status"] = status qs = Workout.objects.filter(**filter_args) if limit and limit > 0: qs = qs[:limit] return qs @staticmethod def resolve_exercise_types(_, info): user = info.context.user user_types = ExerciseTypeModel.objects.filter(user=user, is_active=True) all_types = ExerciseTypeModel.objects.filter(is_active=True).exclude( user=user) return user_types | all_types @staticmethod def resolve_popular_exercise_types(_, info): user = info.context.user popular = (ExerciseTypeModel.objects.filter(is_active=True).annotate( num_exercises=Count("exercise")).order_by("-num_exercises")[:5]) return popular @staticmethod def resolve_exercises(_, info, workout_id): user = info.context.user return Exercise.objects.filter(is_active=True, workout_id=workout_id, user=user) @staticmethod def resolve_sets(_, info, exercise_id): user = info.context.user return Set.objects.filter(user=user, is_active=True, exercise_id=exercise_id) @staticmethod def resolve_workout(_, info, workout_id): user = info.context.user try: workout = Workout.objects.get(is_active=True, id=workout_id, user=user.id) except Workout.DoesNotExist: raise GraphQLError("Workout not found.") return workout @staticmethod def resolve_exercise(_, info, exercise_id): user = info.context.user try: exercise = Exercise.objects.get(is_active=True, id=exercise_id, user=user.id) except Exercise.DoesNotExist: raise GraphQLError("Exercise not found.") return exercise
class GraphenePartition(graphene.ObjectType): name = graphene.NonNull(graphene.String) partition_set_name = graphene.NonNull(graphene.String) solid_selection = graphene.List(graphene.NonNull(graphene.String)) mode = graphene.NonNull(graphene.String) runConfigOrError = graphene.NonNull(GraphenePartitionRunConfigOrError) tagsOrError = graphene.NonNull(GraphenePartitionTagsOrError) runs = graphene.Field( non_null_list(GrapheneRun), filter=graphene.Argument(GrapheneRunsFilter), cursor=graphene.String(), limit=graphene.Int(), ) status = graphene.Field(GrapheneRunStatus) class Meta: name = "Partition" def __init__(self, external_repository_handle, external_partition_set, partition_name): self._external_repository_handle = check.inst_param( external_repository_handle, "external_respository_handle", RepositoryHandle ) self._external_partition_set = check.inst_param( external_partition_set, "external_partition_set", ExternalPartitionSet ) self._partition_name = check.str_param(partition_name, "partition_name") super().__init__( name=partition_name, partition_set_name=external_partition_set.name, solid_selection=external_partition_set.solid_selection, mode=external_partition_set.mode, ) def resolve_runConfigOrError(self, graphene_info): return get_partition_config( graphene_info, self._external_repository_handle, self._external_partition_set.name, self._partition_name, ) def resolve_tagsOrError(self, graphene_info): return get_partition_tags( graphene_info, self._external_repository_handle, self._external_partition_set.name, self._partition_name, ) def resolve_runs(self, graphene_info, **kwargs): filters = kwargs.get("filter") partition_tags = { PARTITION_SET_TAG: self._external_partition_set.name, PARTITION_NAME_TAG: self._partition_name, } if filters is not None: filters = filters.to_selector() runs_filter = RunsFilter( run_ids=filters.run_ids, pipeline_name=filters.job_name, statuses=filters.statuses, tags=merge_dicts(filters.tags, partition_tags), ) else: runs_filter = RunsFilter(tags=partition_tags) return get_runs( graphene_info, runs_filter, cursor=kwargs.get("cursor"), limit=kwargs.get("limit") )
class Arguments: runId = graphene.NonNull(graphene.String) terminatePolicy = graphene.Argument(GrapheneTerminatePipelinePolicy)
class User(CountableDjangoObjectType): addresses = graphene.List(Address, description="List of all user's addresses.") checkout = graphene.Field( Checkout, description="Returns the last open checkout of this user.", deprecation_reason=( "Use the `checkout_tokens` field to fetch the user checkouts." ), ) checkout_tokens = graphene.List( graphene.NonNull(UUID), description="Returns the checkout UUID's assigned to this user.", channel=graphene.String( description="Slug of a channel for which the data should be returned." ), ) gift_cards = PrefetchingConnectionField( "saleor.graphql.giftcard.types.GiftCard", description="List of the user gift cards.", ) note = graphene.String(description="A note about the customer.") orders = PrefetchingConnectionField( "saleor.graphql.order.types.Order", description="List of user's orders." ) # deprecated, to remove in #5389 permissions = graphene.List( Permission, description="List of user's permissions.", deprecation_reason=( "Will be removed in Saleor 2.11." "Use the `userPermissions` instead." ), ) user_permissions = graphene.List( UserPermission, description="List of user's permissions." ) permission_groups = graphene.List( "saleor.graphql.account.types.Group", description="List of user's permission groups.", ) editable_groups = graphene.List( "saleor.graphql.account.types.Group", description="List of user's permission groups which user can manage.", ) avatar = graphene.Field(Image, size=graphene.Int(description="Size of the avatar.")) events = graphene.List( CustomerEvent, description="List of events associated with the user." ) stored_payment_sources = graphene.List( "saleor.graphql.payment.types.PaymentSource", description="List of stored payment sources.", ) store = graphene.Field( Store, id=graphene.Argument(graphene.ID, description="ID of the store."), slug=graphene.Argument(graphene.String, description="Slug of the store"), description="Look up a category by ID or slug.", ) class Meta: description = "Represents user data." interfaces = [relay.Node, ObjectWithMetadata] model = get_user_model() only_fields = [ "date_joined", "default_billing_address", "default_shipping_address", "email", "first_name", "id", "is_active", "is_staff", "is_supplier", "last_login", "last_name", "note", "store", ] @staticmethod def resolve_addresses(root: models.User, _info, **_kwargs): return root.addresses.annotate_default(root).all() @staticmethod def resolve_checkout(root: models.User, _info, **_kwargs): return get_user_checkout(root) @staticmethod def resolve_checkout_tokens(root: models.User, info, channel=None, **_kwargs): def return_checkout_tokens(checkouts): if not checkouts: return [] checkout_global_ids = [] for checkout in checkouts: checkout_global_ids.append(checkout.token) return checkout_global_ids if not channel: return ( CheckoutByUserLoader(info.context) .load(root.id) .then(return_checkout_tokens) ) return ( CheckoutByUserAndChannelLoader(info.context) .load((root.id, channel)) .then(return_checkout_tokens) ) @staticmethod def resolve_gift_cards(root: models.User, info, **_kwargs): return root.gift_cards.all() @staticmethod def resolve_permissions(root: models.User, _info, **_kwargs): # deprecated, to remove in #5389 from .resolvers import resolve_permissions return resolve_permissions(root) @staticmethod def resolve_user_permissions(root: models.User, _info, **_kwargs): from .resolvers import resolve_permissions return resolve_permissions(root) @staticmethod def resolve_permission_groups(root: models.User, _info, **_kwargs): return root.groups.all() @staticmethod def resolve_editable_groups(root: models.User, _info, **_kwargs): return get_groups_which_user_can_manage(root) @staticmethod @one_of_permissions_required( [AccountPermissions.MANAGE_USERS, AccountPermissions.MANAGE_STAFF] ) def resolve_note(root: models.User, info): return root.note @staticmethod @one_of_permissions_required( [AccountPermissions.MANAGE_USERS, AccountPermissions.MANAGE_STAFF] ) def resolve_events(root: models.User, info): return root.events.all() @staticmethod def resolve_orders(root: models.User, info, **_kwargs): viewer = info.context.user if viewer.has_perm(OrderPermissions.MANAGE_ORDERS): return root.orders.all() # type: ignore return root.orders.confirmed() # type: ignore @staticmethod def resolve_avatar(root: models.User, info, size=None, **_kwargs): if root.avatar: return Image.get_adjusted( image=root.avatar, alt=None, size=size, rendition_key_set="user_avatars", info=info, ) @staticmethod def resolve_stored_payment_sources(root: models.User, info): from .resolvers import resolve_payment_sources if root == info.context.user: return resolve_payment_sources(info, root) raise PermissionDenied() @staticmethod def resolve_wishlist(root: models.User, info, **_kwargs): return resolve_wishlist_items_from_user(root) @staticmethod def __resolve_reference(root, _info, **_kwargs): if root.id is not None: return graphene.Node.get_node_from_global_id(_info, root.id) return get_user_model().objects.get(email=root.email)
class Token(graphene.ObjectType): """ self = CommunityDB Object """ class Meta: description = "Representds an ERC-20 token contract in Band ecosystem, including Band native token and community tokens." address = graphene.String(required=True, description="This token's ERC-20 address.") community = graphene.Field( lambda: community_module.Community, description= "The community of this token, in the case of community token.", ) balances = graphene.List( lambda: graphene.NonNull(user_balance_module.UserBalance), filtered_by=graphene.Argument( lambda: user_balance_module.UserBalanceFilters), required=True, description="The list of user balances of this token.", ) transfer_history = graphene.List( lambda: transfer_module.Transfer, filtered_by=graphene.Argument(lambda: transfer_module.TransferFilters), required=True, description="The list of transfers of this token.", ) name = graphene.String(required=True, description="The name of this token.") symbol = graphene.String(required=True, description="The symbol of this token.") def resolve_address(self, info): contract = (db.session.query(Contract).filter( Contract.contract_type == "TOKEN").filter( Contract.community_id == self.id).one()) return contract.address def resolve_community(self, info): if self.id == 1: return None return self def resolve_balances(self, info, filtered_by={}): if "users" in filtered_by: return [(address, self) for address in filtered_by["users"]] addresses = (db.session.query(func.distinct( TransferDB.receiver)).filter( TransferDB.receiver != "0x0000000000000000000000000000000000000000").filter( TransferDB.community_id == self.id).all()) return [(address[0], self) for address in addresses] def resolve_transfer_history(self, info, filtered_by={}): return get_transfer_history(**filtered_by, tokens=[self]) def resolve_name(self, info): return self.name def resolve_symbol(self, info): return self.symbol
def get_all_votes_input_fields(): """Return the input fields needed by allVotes.""" return { 'filter': graphene.Argument(VoteFilter), }
class ProductVariant(CountableDjangoObjectType): quantity = graphene.Int( required=True, description="Quantity of a product available for sale.", deprecation_reason=( "Use the stock field instead. This field will be removed after 2020-07-31." ), ) quantity_allocated = graphene.Int( required=False, description="Quantity allocated for orders.", deprecation_reason=( "Use the stock field instead. This field will be removed after 2020-07-31." ), ) stock_quantity = graphene.Int( required=True, description="Quantity of a product available for sale.", deprecation_reason=( "Use the quantityAvailable field instead. " "This field will be removed after 2020-07-31." ), ) price_override = graphene.Field( Money, description=( "Override the base price of a product if necessary. A value of `null` " "indicates that the default product price is used." ), ) pricing = graphene.Field( VariantPricingInfo, description=( "Lists the storefront variant's pricing, the current price and discounts, " "only meant for displaying." ), ) is_available = graphene.Boolean( description="Whether the variant is in stock and visible or not.", deprecation_reason=( "Use the stock field instead. This field will be removed after 2020-07-31." ), ) attributes = graphene.List( graphene.NonNull(SelectedAttribute), required=True, description="List of attributes assigned to this variant.", ) cost_price = graphene.Field(Money, description="Cost price of the variant.") margin = graphene.Int(description="Gross margin percentage value.") quantity_ordered = graphene.Int(description="Total quantity ordered.") revenue = graphene.Field( TaxedMoney, period=graphene.Argument(ReportingPeriod), description=( "Total revenue generated by a variant in given period of time. Note: this " "field should be queried using `reportProductSales` query as it uses " "optimizations suitable for such calculations." ), ) images = graphene.List( lambda: ProductImage, description="List of images for the product variant." ) translation = TranslationField( ProductVariantTranslation, type_name="product variant" ) digital_content = graphene.Field( DigitalContent, description="Digital content for the product variant." ) stocks = graphene.Field( graphene.List(Stock), description="Stocks for the product variant.", country_code=graphene.Argument( CountryCodeEnum, description="Two-letter ISO 3166-1 country code.", required=False, ), ) quantity_available = graphene.Int( required=True, description="Quantity of a product available for sale in one checkout.", country_code=graphene.Argument( CountryCodeEnum, description=( "Two-letter ISO 3166-1 country code. When provided, the exact quantity " "from a warehouse operating in shipping zones that contain this " "country will be returned. Otherwise, it will return the maximum " "quantity from all shipping zones." ), ), ) class Meta: description = ( "Represents a version of a product such as different size or color." ) only_fields = ["id", "name", "product", "sku", "track_inventory", "weight"] interfaces = [relay.Node, ObjectWithMetadata] model = models.ProductVariant @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_stocks(root: models.ProductVariant, info, country_code=None): if not country_code: return root.stocks.annotate_available_quantity().all() return root.stocks.annotate_available_quantity().for_country(country_code).all() @staticmethod def resolve_quantity_available( root: models.ProductVariant, info, country_code=None ): return get_available_quantity_for_customer(root, country_code) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_digital_content(root: models.ProductVariant, *_args): return getattr(root, "digital_content", None) @staticmethod def resolve_stock_quantity(root: models.ProductVariant, info): return get_available_quantity_for_customer(root, info.context.country) @staticmethod def resolve_attributes(root: models.ProductVariant, info): return SelectedAttributesByProductVariantIdLoader(info.context).load(root.id) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_margin(root: models.ProductVariant, *_args): return get_margin_for_variant(root) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_cost_price(root: models.ProductVariant, *_args): return root.cost_price @staticmethod def resolve_price(root: models.ProductVariant, *_args): return root.base_price @staticmethod def resolve_pricing(root: models.ProductVariant, info): context = info.context product = ProductByIdLoader(context).load(root.product_id) collections = CollectionsByProductIdLoader(context).load(root.product_id) def calculate_pricing_info(discounts): def calculate_pricing_with_product(product): def calculate_pricing_with_collections(collections): availability = get_variant_availability( variant=root, product=product, collections=collections, discounts=discounts, country=context.country, local_currency=context.currency, plugins=context.plugins, ) return VariantPricingInfo(**asdict(availability)) return collections.then(calculate_pricing_with_collections) return product.then(calculate_pricing_with_product) return ( DiscountsByDateTimeLoader(context) .load(info.context.request_time) .then(calculate_pricing_info) ) @staticmethod def resolve_product(root: models.ProductVariant, info): return ProductByIdLoader(info.context).load(root.product_id) @staticmethod def resolve_is_available(root: models.ProductVariant, info): country = info.context.country return is_variant_in_stock(root, country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_price_override(root: models.ProductVariant, *_args): return root.price_override @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity(root: models.ProductVariant, info): return get_available_quantity(root, info.context.country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity_ordered(root: models.ProductVariant, *_args): # This field is added through annotation when using the # `resolve_report_product_sales` resolver. return getattr(root, "quantity_ordered", None) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_quantity_allocated(root: models.ProductVariant, info): country = info.context.country return get_quantity_allocated(root, country) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_revenue(root: models.ProductVariant, *_args, period): start_date = reporting_period_to_date(period) return calculate_revenue_for_variant(root, start_date) @staticmethod def resolve_images(root: models.ProductVariant, *_args): return root.images.all() @classmethod def get_node(cls, info, pk): user = info.context.user visible_products = models.Product.objects.visible_to_user(user).values_list( "pk", flat=True ) qs = cls._meta.model.objects.filter(product__id__in=visible_products) return qs.filter(pk=pk).first() @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_private_meta(root: models.ProductVariant, _info): return resolve_private_meta(root, _info) @staticmethod def resolve_meta(root: models.ProductVariant, _info): return resolve_meta(root, _info) @staticmethod def __resolve_reference(root, _info, **_kwargs): return graphene.Node.get_node_from_global_id(_info, root.id)
class Arguments: tag_data = graphene.Argument(TagCreateInput, required=True)
class Product(CountableDjangoObjectType): url = graphene.String( description="The storefront URL for the product.", required=True, deprecation_reason="This field will be removed after 2020-07-31.", ) thumbnail = graphene.Field( Image, description="The main thumbnail for a product.", size=graphene.Argument(graphene.Int, description="Size of thumbnail."), ) pricing = graphene.Field( ProductPricingInfo, description=( "Lists the storefront product's pricing, the current price and discounts, " "only meant for displaying." ), ) is_available = graphene.Boolean( description="Whether the product is in stock and visible or not." ) base_price = graphene.Field(Money, description="The product's default base price.") minimal_variant_price = graphene.Field( Money, description="The price of the cheapest variant (including discounts)." ) tax_type = graphene.Field( TaxType, description="A type of tax. Assigned by enabled tax gateway" ) attributes = graphene.List( graphene.NonNull(SelectedAttribute), required=True, description="List of attributes assigned to this product.", ) purchase_cost = graphene.Field(MoneyRange) margin = graphene.Field(Margin) image_by_id = graphene.Field( lambda: ProductImage, id=graphene.Argument(graphene.ID, description="ID of a product image."), description="Get a single product image by ID.", ) variants = graphene.List( ProductVariant, description="List of variants for the product." ) images = graphene.List( lambda: ProductImage, description="List of images for the product." ) collections = graphene.List( lambda: Collection, description="List of collections for the product." ) translation = TranslationField(ProductTranslation, type_name="product") class Meta: description = "Represents an individual item for sale in the storefront." interfaces = [relay.Node, ObjectWithMetadata] model = models.Product only_fields = [ "category", "charge_taxes", "description", "description_json", "id", "is_published", "name", "slug", "product_type", "publication_date", "seo_description", "seo_title", "updated_at", "weight", ] @staticmethod def resolve_category(root: models.Product, info): category_id = root.category_id if category_id is None: return None return CategoryByIdLoader(info.context).load(category_id) @staticmethod def resolve_tax_type(root: models.Product, info): tax_data = info.context.plugins.get_tax_code_from_object_meta(root) return TaxType(tax_code=tax_data.code, description=tax_data.description) @staticmethod def resolve_thumbnail(root: models.Product, info, *, size=255): def return_first_thumbnail(images): image = images[0] if images else None if image: url = get_product_image_thumbnail(image, size, method="thumbnail") alt = image.alt return Image(alt=alt, url=info.context.build_absolute_uri(url)) return None return ( ImagesByProductIdLoader(info.context) .load(root.id) .then(return_first_thumbnail) ) @staticmethod def resolve_url(root: models.Product, *_args): return "" @staticmethod def resolve_pricing(root: models.Product, info): context = info.context variants = ProductVariantsByProductIdLoader(context).load(root.id) collections = CollectionsByProductIdLoader(context).load(root.id) def calculate_pricing_info(discounts): def calculate_pricing_with_variants(variants): def calculate_pricing_with_collections(collections): availability = get_product_availability( product=root, variants=variants, collections=collections, discounts=discounts, country=context.country, local_currency=context.currency, plugins=context.plugins, ) return ProductPricingInfo(**asdict(availability)) return collections.then(calculate_pricing_with_collections) return variants.then(calculate_pricing_with_variants) return ( DiscountsByDateTimeLoader(context) .load(info.context.request_time) .then(calculate_pricing_info) ) @staticmethod def resolve_is_available(root: models.Product, info): country = info.context.country in_stock = is_product_in_stock(root, country) return root.is_visible and in_stock @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_base_price(root: models.Product, _info): return root.price @staticmethod def resolve_price(root: models.Product, info): context = info.context def calculate_price(discounts): price_range = root.get_price_range(discounts) price = info.context.plugins.apply_taxes_to_product( root, price_range.start, info.context.country ) return price.net return ( DiscountsByDateTimeLoader(context) .load(info.context.request_time) .then(calculate_price) ) @staticmethod def resolve_attributes(root: models.Product, info): return SelectedAttributesByProductIdLoader(info.context).load(root.id) @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_purchase_cost(root: models.Product, *_args): purchase_cost, _ = get_product_costs_data(root) return purchase_cost @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_margin(root: models.Product, *_args): _, margin = get_product_costs_data(root) return Margin(margin[0], margin[1]) @staticmethod def resolve_image_by_id(root: models.Product, info, id): pk = get_database_id(info, id, ProductImage) try: return root.images.get(pk=pk) except models.ProductImage.DoesNotExist: raise GraphQLError("Product image not found.") @staticmethod def resolve_images(root: models.Product, info, **_kwargs): return ImagesByProductIdLoader(info.context).load(root.id) @staticmethod def resolve_variants(root: models.Product, info, **_kwargs): return ProductVariantsByProductIdLoader(info.context).load(root.id) @staticmethod def resolve_collections(root: models.Product, *_args): return root.collections.all() @classmethod def get_node(cls, info, pk): if info.context: qs = cls._meta.model.objects.visible_to_user(info.context.user) return qs.filter(pk=pk).first() return None @staticmethod @permission_required(ProductPermissions.MANAGE_PRODUCTS) def resolve_private_meta(root: models.Product, _info): return resolve_private_meta(root, _info) @staticmethod def resolve_meta(root: models.Product, _info): return resolve_meta(root, _info) @staticmethod def __resolve_reference(root, _info, **_kwargs): return graphene.Node.get_node_from_global_id(_info, root.id)
class Arguments: ballot = graphene.ID(required=True) role = graphene.Argument(Role, required=True) student = graphene.ID(required=True) rank = graphene.Int(required=True)
class AccountQueries(graphene.ObjectType): address_validation_rules = graphene.Field( AddressValidationData, description="Returns address validation rules.", country_code=graphene.Argument( CountryCodeEnum, description="Two-letter ISO 3166-1 country code.", required=True, ), country_area=graphene.Argument( graphene.String, description="Designation of a region, province or state."), city=graphene.Argument(graphene.String, description="City or a town name."), city_area=graphene.Argument( graphene.String, description="Sublocality like a district."), ) address = graphene.Field( Address, id=graphene.Argument(graphene.ID, description="ID of an address.", required=True), description="Look up an address by ID.", ) customers = FilterInputConnectionField( User, filter=CustomerFilterInput( description="Filtering options for customers."), sort_by=UserSortingInput(description="Sort customers."), description="List of the shop's customers.", ) permission_groups = FilterInputConnectionField( Group, filter=PermissionGroupFilterInput( description="Filtering options for permission groups."), sort_by=PermissionGroupSortingInput( description="Sort permission groups."), description="List of permission groups.", ) permission_group = graphene.Field( Group, id=graphene.Argument(graphene.ID, description="ID of the group.", required=True), description="Look up permission group by ID.", ) me = graphene.Field(User, description="Return the currently authenticated user.") staff_users = FilterInputConnectionField( User, filter=StaffUserInput( description="Filtering options for staff users."), sort_by=UserSortingInput(description="Sort staff users."), description="List of the shop's staff users.", ) service_accounts = FilterInputConnectionField( ServiceAccount, filter=ServiceAccountFilterInput( description="Filtering options for service accounts."), sort_by=ServiceAccountSortingInput( description="Sort service accounts."), description="List of the service accounts.", deprecation_reason= ("Use the `apps` query instead. This field will be removed after 2020-07-31." ), ) service_account = graphene.Field( ServiceAccount, id=graphene.Argument(graphene.ID, description="ID of the service account.", required=True), description="Look up a service account by ID.", deprecation_reason= ("Use the `app` query instead. This field will be removed after 2020-07-31." ), ) user = graphene.Field( User, id=graphene.Argument(graphene.ID, description="ID of the user.", required=True), description="Look up a user by ID.", ) def resolve_address_validation_rules(self, info, country_code, country_area=None, city=None, city_area=None): return resolve_address_validation_rules( info, country_code, country_area=country_area, city=city, city_area=city_area, ) @permission_required(AppPermission.MANAGE_APPS) def resolve_service_accounts(self, info, **kwargs): return resolve_service_accounts(info, **kwargs) @permission_required(AppPermission.MANAGE_APPS) def resolve_service_account(self, info, id): return graphene.Node.get_node_from_global_id(info, id, ServiceAccount) @permission_required(AccountPermissions.MANAGE_USERS) def resolve_customers(self, info, query=None, **kwargs): return resolve_customers(info, query=query, **kwargs) @permission_required(AccountPermissions.MANAGE_STAFF) def resolve_permission_groups(self, info, query=None, **kwargs): return resolve_permission_groups(info, query=query, **kwargs) @permission_required(AccountPermissions.MANAGE_STAFF) def resolve_permission_group(self, info, id): return graphene.Node.get_node_from_global_id(info, id, Group) def resolve_me(self, info): user = info.context.user return user if user.is_authenticated else None @permission_required(AccountPermissions.MANAGE_STAFF) def resolve_staff_users(self, info, query=None, **kwargs): return resolve_staff_users(info, query=query, **kwargs) @one_of_permissions_required( [AccountPermissions.MANAGE_STAFF, AccountPermissions.MANAGE_USERS]) def resolve_user(self, info, id): return resolve_user(info, id) def resolve_address(self, info, id): return resolve_address(info, id)