Replaced `float` with `Decimal` for monetary calculations to prevent precision loss and enhance accuracy. Updated related models, serializers, and utility functions accordingly.
112 lines
3.1 KiB
Python
112 lines
3.1 KiB
Python
from constance import config
|
|
from django.conf import settings
|
|
|
|
from engine.core.models import Product
|
|
|
|
|
|
def org_schema():
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "Organization",
|
|
"name": config.COMPANY_NAME,
|
|
"url": f"https://{settings.BASE_DOMAIN}/",
|
|
"logo": f"https://{settings.BASE_DOMAIN}/static/logo.png",
|
|
}
|
|
|
|
|
|
def website_schema():
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "WebSite",
|
|
"name": settings.PROJECT_NAME,
|
|
"url": f"https://{settings.BASE_DOMAIN}/",
|
|
"potentialAction": {
|
|
"@type": "SearchAction",
|
|
"target": f"https://{settings.BASE_DOMAIN}/search?q={{query}}",
|
|
"query-input": "required name=query",
|
|
},
|
|
}
|
|
|
|
|
|
def breadcrumb_schema(items):
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "BreadcrumbList",
|
|
"itemListElement": [
|
|
{"@type": "ListItem", "position": i + 1, "name": name, "item": url}
|
|
for i, (name, url) in enumerate(items)
|
|
],
|
|
}
|
|
|
|
|
|
def item_list_schema(urls):
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "ItemList",
|
|
"itemListElement": [
|
|
{"@type": "ListItem", "position": i + 1, "url": u}
|
|
for i, u in enumerate(urls)
|
|
],
|
|
}
|
|
|
|
|
|
def product_schema(product, images, rating=None):
|
|
offers = []
|
|
for stock in product.stocks.all():
|
|
offers.append(
|
|
{
|
|
"@type": "Offer",
|
|
"price": float(round(stock.price, 2)),
|
|
"priceCurrency": settings.CURRENCY_CODE,
|
|
"availability": "https://schema.org/InStock"
|
|
if stock.quantity > 0
|
|
else "https://schema.org/OutOfStock",
|
|
"sku": stock.sku,
|
|
"url": f"https://{settings.BASE_DOMAIN}/product/{product.slug}",
|
|
}
|
|
)
|
|
data = {
|
|
"@context": "https://schema.org",
|
|
"@type": "Product",
|
|
"name": product.name,
|
|
"description": product.description or "",
|
|
"sku": product.partnumber or "",
|
|
"brand": {"@type": "Brand", "name": product.brand.name}
|
|
if product.brand
|
|
else None,
|
|
"image": [img.image.url for img in images] or [],
|
|
"offers": offers[:1] if offers else None,
|
|
}
|
|
if rating and rating["count"] > 0:
|
|
data["aggregateRating"] = {
|
|
"@type": "AggregateRating",
|
|
"ratingValue": rating["value"],
|
|
"reviewCount": rating["count"],
|
|
}
|
|
return {k: v for k, v in data.items() if v not in (None, [], {})}
|
|
|
|
|
|
def category_schema(category, url):
|
|
return {
|
|
"@context": "https://schema.org",
|
|
"@type": "CollectionPage",
|
|
"name": category.name,
|
|
"description": category.description or "",
|
|
"url": url,
|
|
}
|
|
|
|
|
|
def brand_schema(brand, url, logo_url=None):
|
|
data = {
|
|
"@context": "https://schema.org",
|
|
"@type": "Brand",
|
|
"name": brand.name,
|
|
"url": url,
|
|
}
|
|
if logo_url:
|
|
data["logo"] = logo_url
|
|
return data
|
|
|
|
|
|
def any_non_digital() -> bool:
|
|
return Product.objects.filter(is_digital=False).exists()
|