Skip to content

Commit

Permalink
Merge pull request saleor#5178 from mirumee/5028/Unify_meta_mutations
Browse files Browse the repository at this point in the history
Unify meta mutations
  • Loading branch information
maarcingebala authored Feb 21, 2020
2 parents c063595 + 67a46a3 commit 8a01591
Show file tree
Hide file tree
Showing 63 changed files with 6,375 additions and 1,321 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ All notable, unreleased changes to this project will be documented in this file.
- Customer shouldn't be able to see draft orders by token - #5259 by @fowczarek
- Customer shouldn't be able to query checkout with another customer - #5268 by @fowczarek
- Added integration support of Jaeger Tracing - #5282 by @NyanKiyoshi
- Customer shouldn't be able to see draft orders by token - #5259 by @fowczarek
- Return `null` when querying `me` as an anonymous user - #5231 as @maarcingebala
- Unify saleor metadata - #5178 by @fowczarek


## 2.9.0

Expand Down
27 changes: 27 additions & 0 deletions saleor/account/migrations/0039_auto_20200221_0257.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions saleor/checkout/migrations/0025_auto_20200221_0257.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions saleor/checkout/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,6 @@ def __repr__(self):
def __iter__(self):
return iter(self.lines.all())

def __len__(self):
return self.lines.count()

def get_customer_email(self) -> str:
return self.user.email if self.user else self.email

Expand Down
4 changes: 2 additions & 2 deletions saleor/checkout/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,8 @@ def create_order(
checkout.payments.update(order=order)

# copy metadata from the checkout into the new order
order.meta = checkout.meta
order.private_meta = checkout.private_meta
order.metadata = checkout.metadata
order.private_metadata = checkout.private_metadata
order.save()

order_created(order=order, user=user)
Expand Down
6 changes: 6 additions & 0 deletions saleor/core/error_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ class ShopErrorCode(Enum):
NOT_FOUND = "not_found"
REQUIRED = "required"
UNIQUE = "unique"


class MetadataErrorCode(Enum):
GRAPHQL_ERROR = "graphql_error"
INVALID = "invalid"
NOT_FOUND = "not_found"
126 changes: 126 additions & 0 deletions saleor/core/migrations/0001_migrate_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Generated by Django 2.2.9 on 2020-02-07 07:32

from django.db import migrations


def flatten_model_metadata(model_with_metadata):
updated_fields = []
public_meta = model_with_metadata.metadata
private_meta = model_with_metadata.private_metadata
if public_meta:
model_with_metadata.metadata = flatten_metadata(public_meta)
updated_fields.append("metadata")
if private_meta:
model_with_metadata.private_metadata = flatten_metadata(private_meta)
updated_fields.append("private_metadata")
if updated_fields:
model_with_metadata.save(update_fields=updated_fields)


def flatten_metadata(metadata):
flattened_metadata = {}
for _, namespace in metadata.items():
for client_name, client in namespace.items():
for key, value in client.items():
flattened_key = client_name + "." + key
if flattened_key in flattened_metadata:
raise Exception(f"Meta key {flattened_key} is duplicated.")
flattened_metadata[flattened_key] = value
return flattened_metadata


def flatten_attributes_metadata(apps, _schema_editor):
Attribute = apps.get_model("product", "Attribute")
for attribute in Attribute.objects.iterator():
flatten_model_metadata(attribute)


def flatten_categories_metadata(apps, _schema_editor):
Category = apps.get_model("product", "Category")
for category in Category.objects.iterator():
flatten_model_metadata(category)


def flatten_checkouts_metadata(apps, _schema_editor):
Checkout = apps.get_model("checkout", "Checkout")
for checkout in Checkout.objects.iterator():
flatten_model_metadata(checkout)


def flatten_collections_metadata(apps, _schema_editor):
Collection = apps.get_model("product", "Collection")
for collection in Collection.objects.iterator():
flatten_model_metadata(collection)


def flatten_digital_contents_metadata(apps, _schema_editor):
DigitalContent = apps.get_model("product", "DigitalContent")
for digital_content in DigitalContent.objects.iterator():
flatten_model_metadata(digital_content)


def flatten_fulfillments_metadata(apps, _schema_editor):
Fulfillment = apps.get_model("order", "Fulfillment")
for fulfillment in Fulfillment.objects.iterator():
flatten_model_metadata(fulfillment)


def flatten_orders_metadata(apps, _schema_editor):
Order = apps.get_model("order", "Order")
for order in Order.objects.iterator():
flatten_model_metadata(order)


def flatten_products_metadata(apps, _schema_editor):
Product = apps.get_model("product", "Product")
for product in Product.objects.iterator():
flatten_model_metadata(product)


def flatten_product_types_metadata(apps, _schema_editor):
ProductType = apps.get_model("product", "ProductType")
for product_type in ProductType.objects.iterator():
flatten_model_metadata(product_type)


def flatten_product_variants_metadata(apps, _schema_editor):
ProductVariant = apps.get_model("product", "ProductVariant")
for product_variant in ProductVariant.objects.iterator():
flatten_model_metadata(product_variant)


def flatten_service_accounts_metadata(apps, _schema_editor):
ServiceAccount = apps.get_model("account", "ServiceAccount")
for service_account in ServiceAccount.objects.iterator():
flatten_model_metadata(service_account)


def flatten_users_metadata(apps, _schema_editor):
User = apps.get_model("account", "User")
for user in User.objects.iterator():
flatten_model_metadata(user)


class Migration(migrations.Migration):

dependencies = [
("account", "0039_auto_20200221_0257"),
("checkout", "0025_auto_20200221_0257"),
("order", "0078_auto_20200221_0257"),
("product", "0115_auto_20200221_0257"),
]

operations = [
migrations.RunPython(flatten_attributes_metadata),
migrations.RunPython(flatten_categories_metadata),
migrations.RunPython(flatten_checkouts_metadata),
migrations.RunPython(flatten_collections_metadata),
migrations.RunPython(flatten_digital_contents_metadata),
migrations.RunPython(flatten_fulfillments_metadata),
migrations.RunPython(flatten_orders_metadata),
migrations.RunPython(flatten_products_metadata),
migrations.RunPython(flatten_product_types_metadata),
migrations.RunPython(flatten_product_variants_metadata),
migrations.RunPython(flatten_service_accounts_metadata),
migrations.RunPython(flatten_users_metadata),
]
45 changes: 27 additions & 18 deletions saleor/core/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
from typing import Any

from django.contrib.postgres.fields import JSONField
from django.db import models
Expand Down Expand Up @@ -74,32 +75,40 @@ def is_visible(self):


class ModelWithMetadata(models.Model):
private_meta = JSONField(
private_metadata = JSONField(
blank=True, null=True, default=dict, encoder=CustomJsonEncoder
)
meta = JSONField(blank=True, null=True, default=dict, encoder=CustomJsonEncoder)
metadata = JSONField(blank=True, null=True, default=dict, encoder=CustomJsonEncoder)

class Meta:
abstract = True

def get_private_meta(self, namespace: str, client: str) -> dict:
return self.private_meta.get(namespace, {}).get(client, {})
def get_value_from_private_metadata(self, key: str, default: Any = None) -> Any:
return self.private_metadata.get(key, default)

def store_private_meta(self, namespace: str, client: str, item: dict):
if namespace not in self.private_meta:
self.private_meta[namespace] = {}
self.private_meta[namespace][str(client)] = item
def store_value_in_private_metadata(self, items: dict):
if not self.private_metadata:
self.private_metadata = {}
self.private_metadata.update(items)

def clear_stored_private_meta_for_client(self, namespace: str, client: str):
self.private_meta.get(namespace, {}).pop(client, None)
def clear_private_metadata(self):
self.private_metadata = {}

def get_meta(self, namespace: str, client: str) -> dict:
return self.meta.get(namespace, {}).get(client, {})
def delete_value_from_private_metadata(self, key: str):
if key in self.private_metadata:
del self.private_metadata[key]

def store_meta(self, namespace: str, client: str, item: dict):
if namespace not in self.meta:
self.meta[namespace] = {}
self.meta[namespace][str(client)] = item
def get_value_from_metadata(self, key: str, default: Any = None) -> Any:
return self.metadata.get(key, default)

def clear_stored_meta_for_client(self, namespace: str, client: str):
self.meta.get(namespace, {}).pop(client, None)
def store_value_in_metadata(self, items: dict):
if not self.metadata:
self.metadata = {}
self.metadata.update(items)

def clear_metadata(self):
self.metadata = {}

def delete_value_from_metadata(self, key: str):
if key in self.metadata:
del self.metadata[key]
8 changes: 4 additions & 4 deletions saleor/core/utils/anonymization.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ def anonymize_order(order: "Order") -> "Order":
anonymized_order.shipping_address = generate_fake_address()
anonymized_order.billing_address = generate_fake_address()
anonymized_order.customer_note = fake.paragraph()
anonymized_order.meta = fake.pystruct(count=1)
anonymized_order.private_meta = fake.pystruct(count=1)
anonymized_order.metadata = fake.pystruct(count=1)
anonymized_order.private_metadata = fake.pystruct(count=1)
return anonymized_order


Expand All @@ -77,6 +77,6 @@ def anonymize_checkout(checkout: "Checkout") -> "Checkout":
anonymized_checkout.shipping_address = generate_fake_address()
anonymized_checkout.billing_address = generate_fake_address()
anonymized_checkout.note = fake.paragraph()
anonymized_checkout.meta = fake.pystruct(count=1)
anonymized_checkout.private_meta = fake.pystruct(count=1)
anonymized_checkout.metadata = fake.pystruct(count=1)
anonymized_checkout.private_metadata = fake.pystruct(count=1)
return anonymized_checkout
8 changes: 4 additions & 4 deletions saleor/extensions/plugins/avatax/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@

logger = logging.getLogger(__name__)

META_FIELD = "avatax"
META_NAMESPACE = "taxes"
META_CODE_KEY = "avatax.code"
META_DESCRIPTION_KEY = "avatax.description"
CACHE_TIME = 60 * 60 # 1 hour
TAX_CODES_CACHE_TIME = 60 * 60 * 24 * 7 # 7 days
CACHE_KEY = "avatax_request_id_"
Expand Down Expand Up @@ -447,6 +447,6 @@ def get_cached_tax_codes_or_fetch(


def retrieve_tax_code_from_meta(obj: Union["Product", "ProductVariant", "ProductType"]):
tax = obj.meta.get("taxes", {}).get(META_FIELD, {})
# O9999999 - "Temporary Unmapped Other SKU - taxable default"
return tax.get("code", "O9999999")
tax_code = obj.get_value_from_metadata(META_CODE_KEY, "O9999999")
return tax_code
17 changes: 7 additions & 10 deletions saleor/extensions/plugins/avatax/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from ...base_plugin import BasePlugin
from ...error_codes import ExtensionsErrorCode
from . import (
META_FIELD,
META_NAMESPACE,
META_CODE_KEY,
META_DESCRIPTION_KEY,
AvataxConfiguration,
CustomerErrors,
TransactionType,
Expand Down Expand Up @@ -383,12 +383,8 @@ def assign_tax_code_to_object_meta(
return

tax_description = codes[tax_code]
tax_item = {"code": tax_code, "description": tax_description}
stored_tax_meta = obj.get_meta(namespace=META_NAMESPACE, client=META_FIELD)
stored_tax_meta.update(tax_item)
obj.store_meta(
namespace=META_NAMESPACE, client=META_FIELD, item=stored_tax_meta
)
tax_item = {META_CODE_KEY: tax_code, META_DESCRIPTION_KEY: tax_description}
obj.store_value_in_metadata(items=tax_item)
obj.save()

def get_tax_code_from_object_meta(
Expand All @@ -398,8 +394,9 @@ def get_tax_code_from_object_meta(

if not self.active:
return previous_value
tax = obj.get_meta(namespace=META_NAMESPACE, client=META_FIELD)
return TaxType(code=tax.get("code", ""), description=tax.get("description", ""))
tax_code = obj.get_value_from_metadata(META_CODE_KEY, "")
tax_description = obj.get_value_from_metadata(META_DESCRIPTION_KEY, "")
return TaxType(code=tax_code, description=tax_description,)

def show_taxes_on_storefront(self, previous_value: bool) -> bool:
self._initialize_plugin_configuration()
Expand Down
19 changes: 7 additions & 12 deletions saleor/extensions/plugins/vatlayer/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@

class VatlayerPlugin(BasePlugin):
PLUGIN_NAME = "Vatlayer"
META_FIELD = "vatlayer"
META_NAMESPACE = "taxes"
META_CODE_KEY = "vatlayer.code"
META_DESCRIPTION_KEY = "vatlayer.description"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -253,14 +253,8 @@ def assign_tax_code_to_object_meta(
if tax_code not in dict(TaxRateType.CHOICES):
return previous_value

tax_item = {"code": tax_code, "description": tax_code}
stored_tax_meta = obj.get_meta(
namespace=self.META_NAMESPACE, client=self.META_FIELD
)
stored_tax_meta.update(tax_item)
obj.store_meta(
namespace=self.META_NAMESPACE, client=self.META_FIELD, item=stored_tax_meta
)
tax_item = {self.META_CODE_KEY: tax_code, self.META_DESCRIPTION_KEY: tax_code}
obj.store_value_in_metadata(items=tax_item)
obj.save()
return previous_value

Expand All @@ -276,8 +270,9 @@ def get_tax_code_from_object_meta(
def __get_tax_code_from_object_meta(
self, obj: Union["Product", "ProductType"]
) -> "TaxType":
tax = obj.get_meta(namespace=self.META_NAMESPACE, client=self.META_FIELD)
return TaxType(code=tax.get("code", ""), description=tax.get("description", ""))
tax_code = obj.get_value_from_metadata(self.META_CODE_KEY, "")
tax_description = obj.get_value_from_metadata(self.META_DESCRIPTION_KEY, "")
return TaxType(code=tax_code, description=tax_description,)

def get_tax_rate_percentage_value(
self, obj: Union["Product", "ProductType"], country: Country, previous_value
Expand Down
Loading

0 comments on commit 8a01591

Please sign in to comment.