For the complete documentation index, see llms.txt. This page is also available as Markdown.

Dynamic Settings

Dynamic settings allow for the flexible and customizable management of various aspects of your system. This document provides an overview of the key configurations available through dynamic settings, each designed to address specific operational needs and enhance the functionality of your platform.

1. Subscription Gateways

Defines the subscription / marketing gateways (e.g. Emarsys, Setrow, Insider, EuroMessage, Mobildev) used to sync users and their consent / preference data to external CRM and newsletter providers. Each entry is keyed by a gateway slug and holds the configuration (credentials, endpoint URLs, options, optional user-matching rule) needed to talk to one provider account.

A single store can host multiple regional or brand accounts of the same provider side by side. Attaching a match_user rule to an entry scopes that gateway to a subset of users, so the same shop can fan out to several regional accounts (for example one Emarsys account for Turkey and another for France) without writing duplicate records to the wrong account.

Key: SUBSCRIPTION_GATEWAYS Type: object (dict of gateway slug → gateway config)

Entry fields

Field
Type
Required
Description

klass

string

Yes

Identifier of the gateway implementation to use. Must be one of the supported provider values.

dispatch_klass

string

Yes

Identifier of the dispatch handler that routes calls to the gateway. Most providers use the generic dispatcher; Setrow uses its own.

conf

object

Yes

Provider-specific configuration: credentials, endpoints, unique field, and any other provider options.

conf.auth

object

Yes

Credentials block (e.g. username / secret, API key) required by the provider.

conf.match_user

object

No

Optional rule that limits this gateway to users whose attributes match (see below).

match_user — user-based routing for multi-region setups

When match_user is present, the gateway is invoked for a user only if that user's attribute equals the configured value. Entries without match_user keep the legacy single-region behaviour and run for every user.

Field
Type
Required
Description

attribute

string

Yes

Name of the user attribute to check (e.g. country_code). Cannot be empty.

equals

string

Yes

Value the attribute must equal for this gateway to be selected. Cannot be empty.

Routing behaviour

  • A gateway without match_user runs for every user.

  • A gateway with match_user runs only when the user's attribute equals the configured value; non-matching users are skipped.

  • When the subscription call has no user context (anonymous newsletter signup using only an email), every gateway that defines match_user is skipped. Without knowing which region the user belongs to, sending the request to all regional accounts would create duplicate records — so the safer default is to skip.

  • Removing match_user from an entry that previously had one silently widens the gateway to all users and starts writing into the wrong regional account. To retire a region, delete the entry entirely instead of clearing match_user.

Example — single region

Example — multi-region (Emarsys TR + FR)

With this setup:

  • A user whose country_code attribute is TR is synced to emarsys_tr.

  • A user whose country_code attribute is FR is synced to emarsys_fr.

  • A user with no country_code (or a different value) is not synced to either gateway.

  • An anonymous email-only subscription is not synced to either gateway, preventing cross-region duplicate records.

Related settings

  • ACTIVE_SUBSCRIPTION_GATEWAYS — list of gateway slugs that are turned on. Only entries listed here participate in dispatch; it does not have to include every key in SUBSCRIPTION_GATEWAYS.

  • SUBSCRIPTION_ACTIVE — master switch. When false, no subscription dispatch runs regardless of the configuration here.

2. Default Country Code

The ISO country code (e.g. tr, pl, en) used as the default market for the brand. It must match an existing Country record (by code). This value is used to pre-select the country on address forms, resolve country-dependent resources (e.g. LCW SSO), and provide a default country in loyalty/subscription flows (e.g. Emarsys). It affects checkout address pages, user resources, and SSO gateways that need a single default country.

Usage: Used in omnishop.orders.pages.address and omnishop.users.resources.views via CountryService().get_country(dynamic_settings.DEFAULT_COUNTRY_CODE); in omnishop.address.jinja_globals for templates; and in subscription gateways (e.g. Emarsys) when a default country is required.

Key: DEFAULT_COUNTRY_CODE Type: string

Example: "tr" (Turkey), "pl" (Poland), "en" (if used as a country code in your data).

3. Identity Number Validator

Dotted path to the callable that validates the address identity number (e.g. national ID). The validator is invoked when address data is validated; it receives the identity number value and must raise if invalid. Use this to enforce country-specific rules (e.g. Turkish ID format) or to disable validation.

Usage: Loaded in omnishop.address.resources.serializers with import_string(dynamic_settings.IDENTITY_NUMBER_VALIDATOR) and called during address validation.

Key: IDENTITY_NUMBER_VALIDATOR Type: string (dotted path)

Example:

  • omnicore.address.validators.null_identity_validator — no validation.

  • omnicore.address.validators.tc_identity_number_validator — Turkish Republic identity number format.

4. Default Shipping Cost

Fallback shipping cost (numeric or string that parses to decimal) used when no matching ShippingCost rule is found for the given address (country, city, township, district) and currency. If a rule exists for a more specific region it overrides this; otherwise the checkout and shipping calculator use this value so the order still has a defined shipping amount.

Usage: In omnishop.address.service.ShippingCostService.get_cost(): if there is no shipping address, or no ShippingCost row matches the address hierarchy, the method returns Decimal(dynamic_settings.DEFAULT_SHIPPING_COST).

Key: DEFAULT_SHIPPING_COST Type: number (int/float) or string

Example: 0, "0.00", or 9.99.

5. Sitemap Configuration

Configures XML sitemap generation comprehensively. Each content type (product, category, page, etc.) can be individually enabled/disabled with its own crawl frequency, priority, limit, and filters. When this setting is saved, the sitemap is automatically regenerated.

Post-Save Behaviour: When this value is saved, the sitemap is automatically regenerated.

Key: SITEMAP_CONFIGURATION Type: object (nested dict) Validation: Each sitemap type is validated with its own rules

Top-level keys:

Key
Content type

category

Category pages

flat_page

Static pages

landing_page

Landing pages

product

Product pages

special_page

Special pages

Common fields for each content type:

Field
Type
Default
Description

enabled

boolean

Whether this content type is included in the sitemap

changefreq

string

Crawl frequency hint for search engines

priority

float

Crawl priority (0.0 – 1.0)

limit

integer

Maximum URL count per page (1 – 50000)

template

string

"sitemap.xml"

Sitemap template to use

i18n

boolean

Generate a separate sitemap per language

should_generate

boolean

true

Whether generation is triggered

excludes

dict

{}

Filter for records to exclude from sitemap

filters

dict

{}

Filter for records to include in sitemap

Valid changefreq values: always · hourly · daily · weekly · monthly · yearly · never

Additional fields for product:

Field
Type
Description

include_stock_out_products

boolean

Include out-of-stock products in the sitemap

max_image_count

integer

Maximum number of images per product in the sitemap

include_seller_id_param

boolean

When true, appends ?seller_id=<id> to each product URL using the cheapest active offer's seller ID. If no active offer exists, the URL is listed without the parameter. Defaults to false.

Special validation rule: When product uses template: "sitemap_with_images.xml", the limit must not exceed 20000.

SEO and performance considerations:

  • enabled: false → All URLs for that content type are removed from the sitemap; search engines cannot rediscover those pages

  • include_stock_out_products: true → Out-of-stock products remain in the sitemap, preserving SEO continuity

  • Setting limit too low may leave thousands of URLs out of the sitemap

  • Excessively high changefreq + priority wastes search engine crawl budget

  • i18n: true generates a separate sitemap per language — required for multi-language projects

Example:

6. Customer Loyalty Card Service

Selects the loyalty-card backend and its options. The klass is the dotted path of the service class (e.g. default, Akipay, Zubizu, Tefal, Obase, Como, Giz, Loccitane, Nebim, Rapidpromo); conf is a free-form object used for API URLs, auth, minimum basket amount, JWT path, etc. This service is used for loyalty views (create/update cards, query points), promotion flows that need card data, and user views that show or link loyalty information.

Usage: Read in omnishop.loyaltycard.views, omnishop.loyaltycard.client, omnishop.promotions.service, and omnishop.users.views; the client uses conf for auth (e.g. auth.auth_url, jwt_token_path) and optional minimum_basket_amount (decimal, ≥ 0).

Key: CUSTOMER_LOYALTY_CARD_SERVICE Type: object

Example:

7. Cash Register Authentication Configuration

Credentials used to authenticate requests that originate from a Cash Register (e.g. creating or accessing a pre-order by order number). The incoming request’s username and password are compared to this setting; only when both match is the operation allowed. This protects cash-register-only endpoints from unauthorized use.

Usage: In omnishop.orders.resources.views.check_user_name(): conf = dynamic_settings.CASH_REGISTER_AUTH_CONF and validation succeeds when data.get("username") == conf['username'] and data.get("password") == conf['password']. Referenced from supervising/API views that need to expose or validate this key.

Key: CASH_REGISTER_AUTH_CONF Type: object

Example:

8. Three D Secure Enabled

Master switch for 3D Secure (3DS) on payment flows. When true, the payment pipeline may require a 3DS step (e.g. redirect to issuer) depending on POS/card configuration and THREE_D_SECURE_RULES. When false, 3DS is not applied regardless of rules. Used together with POS/card three_d_enabled and the rule functions that decide per request whether to trigger 3DS (e.g. by amount, guest user, currency).

Usage: Checked in omnishop.orders.rules.check_three_d_secure(): if not dynamic_settings.THREE_D_SECURE_ENABLED the function returns False and 3DS is skipped. Also used in is_first_order and related tests.

Key: THREE_D_SECURE_ENABLED Type: boolean

Example: true to enable 3DS when rules and POS/card allow; false to disable globally.

9. Three D Secure Rules

List of rule entries that decide whether to apply 3D Secure for a given payment. Each entry has klass (dotted path to a rule function) and defaults (kwargs passed to that function). 3DS is applied only when THREE_D_SECURE_ENABLED is true, POS/card allow it, and at least one rule returns true (or the list is empty). Rule functions receive payment context (pos, user, amount, currency, etc.) and return a boolean.

Where it is used

  • omnishop.orders.rules.check_three_d_secure()rules = dynamic_settings.THREE_D_SECURE_RULES; each rule's klass is imported and called with defaults merged with kwargs; results are ORed. Used to enforce 3DS by amount, guest user, first order, currency, POS list, or trial limits.

Key: THREE_D_SECURE_RULES Type: array of objects

Example

1. Amount Limit Rule

3D Secure is required when the payment amount is above a given limit.

2. Masterpass Amount Limit Rule

3D Secure is required when the payment amount with Masterpass is above a given limit.

3. Three-D Pos List Rule

3D Secure is required for payments when the POS slug is in the configured list.

4. Trial Limit per User Rule

A trial limit per user email is applied within a time window. If the user exceeds the number of trials in that period, 3D Secure is required.

timeout is in seconds (e.g. 3600 = 1 hour).

5. Trial Limit per IP Address Rule

A trial limit per remote (IP) address is applied within a time window. If the limit is exceeded, 3D Secure is required.

timeout is in seconds (e.g. 3600 = 1 hour).

6. Guest User Rule

Guest (unauthenticated) users are always required to perform 3D Secure.

7. First Order Rule

3D Secure is required when the order is the user's first order. For guests, the behaviour depends on THREE_D_SECURE_ENABLED. For registered users, if the user has no orders, 3D Secure is required.

8. Payment currency Rule

3D Secure is required for payments in specific currencies.

Supported currency codes

10. Identity Number Required Amount

Order total threshold (numeric) above which the shipping address must have an identity number. If set (e.g. 300), checkout validation compares the pre-order total (with interest) to this value; when the total is greater and the selected shipping address has no identity number, a validation error is raised so the user must provide it. Set to null or omit to not require identity number by amount.

Usage: In omnishop.orders.serializers.input_serializers (e.g. address/checkout input validation): amount_limit = dynamic_settings.IDENTITY_NUMBER_REQUIRED_AMOUNT; if amount_limit is not None and pre_order.get_total_amount_with_interest() > amount_limit and the shipping address has no identity_number, a ValidationError is raised for the identity number field.

Key: IDENTITY_NUMBER_REQUIRED_AMOUNT Type: number (int/float) or null

Example: 300 — require identity number for orders over 300 (in the order currency); null — do not enforce by amount.

11. Anonymous Address Expire Seconds

Lifetime in seconds for anonymous users’ session-stored address references. When an anonymous user adds, updates, or deletes an address, the session stores the address hash(es) and an expiry timestamp set to now + this value. When reading addresses, the service returns them only if the stored expiry time is still in the future; after that, the addresses are no longer returned (effectively expired). Logged-in users are not affected.

Usage: In omnishop.utils.sessions.AnonymousUserAddressService: on add/update/delete of anonymous address, request.session[address_expire_key] = time.time() + dynamic_settings.ANONYMOUS_ADDRESS_EXPIRE_SECONDS; in get_anonymous_addresses(), addresses are returned only when expire_time and (expire_time > time.time()).

Key: ANONYMOUS_ADDRESS_EXPIRE_SECONDS Type: number (int)

Example: 1800 (30 minutes); default is 60 * 30 if not set in Django settings.

12. Offer Show Listing Kwargs

When true, queries that fetch active basket offers (campaigns) for product listing or detail use select_related for promotion, condition, benefit, and their product_collection relations so that full offer details are loaded in one go. When false, those relations are not eagerly loaded, reducing query size and cost but requiring extra queries if listing code needs promotion/condition/benefit data. Use true when listing or product APIs need to expose promotion, condition, and benefit information per product.

Usage: Read in omnishop.promotions.models.get_basket_offers_from_cache(), omnishop.products.managers (active offers prefetch), and omnishop.products.resources.serializers; when true, the queryset is extended with .select_related("promotion", "condition", "benefit", "condition__product_collection", "benefit__product_collection").

Key: OFFER_SHOW_LISTING_KWARGS Type: boolean

Example: true to include full offer details in listing/campaign queries; false (default) to avoid extra joins.

13. Test User Emails

List of email addresses that are treated as “test users” for visibility of hidden products. If a product is marked hidden (is_hidden), the product detail view allows access only when the request user is authenticated and the user’s email is in this list; otherwise the view raises Http404. Use this to let internal or test accounts view products that are hidden from normal users.

Usage: In omnishop.products.resources.views (product detail): when product.is_hidden, access is allowed only if request.user.is_authenticated and request.user.email in dj_dynamic_settings.TEST_USER_EMAILS; otherwise raise Http404.

Key: TEST_USER_EMAILS Type: array (list of strings)

Example: ["qa@example.com", "test@test.com"]. Default: [].

14. Product End Of Life Attribute

Product attribute key (e.g. end_of_life) whose value indicates that the product is no longer sold. For a single product: if this attribute is truthy and the product has no stock, the product detail view returns Http404. For a grouped product: if this attribute is truthy, the view returns Http404 regardless of stock. Use it to hide discontinued or end-of-life products from the storefront.

Usage: In omnishop.products.resources.views: on product detail, eol_attr = dj_dynamic_settings.PRODUCT_END_OF_LIFE_ATTRIBUTE; if product.attributes.get(eol_attr) is truthy and (for single product) not product.has_any_stock(), or for grouped product if the attribute is set, the view raises Http404. Same attribute is used on grouped product detail view.

Key: PRODUCT_END_OF_LIFE_ATTRIBUTE Type: string

Example: "end_of_life" or "discontinued" — the product’s attributes dict must contain this key with a truthy value (and no stock for single products) to trigger 404.

15. Pass Stock Check on Detail

When true, the product detail page service is called with pass_stock_check=True, so the detail can be returned even when the product would normally fail a stock or listability check (e.g. out of stock). When false, the usual stock check applies and the detail may not be shown or may redirect if the product is not listable. Use true to allow viewing detail for out-of-stock or otherwise non-listable products (e.g. for SEO or “notify me” flows).

Usage: In omnishop.products.resources.views (product detail): pass_stock_check = dj_dynamic_settings.PASS_STOCK_CHECK_ON_DETAIL is passed to self.service.get_detail_page(..., pass_stock_check=pass_stock_check); the service uses it to skip or relax stock checks when building the detail response.

Key: PASS_STOCK_CHECK_ON_DETAIL Type: boolean

Example: true to show detail regardless of stock; false (default) to enforce stock/listability on detail.

16. Category Detail Max Depth

Maximum category depth at which the category page is shown as a “landing” view (e.g. with subcategory tiles). If the current category’s depth is greater than this value (and force_landing is not set), the view switches to a listing/facet view that shows products in that category instead of a deeper landing. So lower values (e.g. 2) make more categories behave as listing pages; higher values allow deeper categories to still show as landing pages with subcategories.

Usage: In omnishop.products.resources.views.CategoryDetailPageView.get(): max_depth = dj_dynamic_settings.CATEGORY_DETAIL_MAX_DEPTH; if category_node.depth > max(1, max_depth) and not force_landing, a facet view is used (listing); otherwise the category landing is used.

Key: CATEGORY_DETAIL_MAX_DEPTH Type: number (int)

Example: 2 — categories at depth 3 or more show as listing; 3 — only depth 4+ show as listing. Default: 2.

17. Product Stock Out Visibility Enabled

When true, search and listing queries do not filter out out-of-stock products: the base Elasticsearch query uses an “exists” clause on the stock field instead of “stock > 0”, so products with zero stock can appear in results. When false, only products with stock > 0 are returned. Also controls what gets indexed: the search indexer includes or excludes out-of-stock products according to this setting. Changing it triggers a post-save action to refresh the index.

Usage: In omnishop.search.utils.get_base_es_query(): if true, stock_q = Q("exists", field=stock_field); otherwise stock_q = Q("range", stock_field: {"gt": 0}). Used in omnishop.search.services, omnishop.search.indexer for indexing and query building. Has a post_save_action to update index (e.g. refresh sitemap/stock visibility).

Key: PRODUCT_STOCK_OUT_VISIBILITY_ENABLED Type: boolean

Example: true to show out-of-stock products in search and listing; false (default) to hide them.

18. Search Default Page Size

Default number of results per page for search and catalog listing views when the client does not send a page size. Must be at least 1. Used as the default for pagination in search API and category/search result pages.

Usage: In omnishop.search.resources.views: default_page_size = property(lambda self: dynamic_settings.SEARCH_DEFAULT_PAGE_SIZE); this value is used when building paginated search/catalog responses. Validated with MinValueValidator(1) in omnishop.search.settings.conf.

Key: SEARCH_DEFAULT_PAGE_SIZE Type: number (int), minimum 1

Example: 20 (default); 12 or 24 for smaller/larger pages.

19. Slot Days Count

Number of days to generate delivery slots for, starting from the first allowed slot date (which is determined by DEFERRED_SLOT_DAYS_COUNT). For example, if this is 5 and the first slot day is Wednesday, slots are generated for Wednesday through Sunday. Passed to the slot service as the days argument when building the list of selectable delivery time ranges.

Usage: In omnishop.slots.resources.views and omnishop.orders.pages.slots: slot_days_count = dynamic_settings.SLOT_DAYS_COUNT is passed to slot_service.generate_slots(days=slot_days_count, deferred_days=deferred_slot_days_count, ...) to control how many days of slots are offered.

Key: SLOT_DAYS_COUNT Type: number (int)

Example: 2 — two days of slots; 5 — five days. Default: 2.

20. Deferred Slot Days Count

Number of days to skip from today before the first available delivery slot day. For example, if today is Monday and this is 2, the first slot day is Wednesday; slots are then generated for the next SLOT_DAYS_COUNT days starting from Wednesday. Passed to the slot service as deferred_days so that delivery options start from a future date (e.g. to account for preparation or cutoff rules).

Usage: In omnishop.slots.resources.views and omnishop.orders.pages.slots: deferred_slot_days_count = dynamic_settings.DEFERRED_SLOT_DAYS_COUNT is passed to slot_service.generate_slots(..., deferred_days=deferred_slot_days_count, ...). Can be combined with DEFERRED_SLOT_IGNORED_DAYS for more control.

Key: DEFERRED_SLOT_DAYS_COUNT Type: number (int)

Example: 0 — first slot is today (default); 2 — first slot is in 2 days (e.g. Monday → Wednesday).

21. Auth Password Validators

Defines the list of password validators applied when a user sets or changes their password. Each item is an object with NAME (dotted path to a class that extends Django BasePasswordValidator) and optional OPTIONS (kwargs passed to the validator). The same list is used in registration, password-change forms, and profile/serializer password validation so strength rules (length, capitals, numbers, common passwords, etc.) are applied consistently.

Where it is used

  • omnishop.users.formsSetPasswordForm.clean_password2() and AllAuthSetPasswordForm.clean_password2(): auth_password_validators = dj_dynamic_settings.AUTH_PASSWORD_VALIDATORS; then validate_password(password, user=..., password_validators=get_password_validators(auth_password_validators)).

  • omnishop.users.resources.serializers — When validating password in user serializers (e.g. registration or profile update): validators are built from this setting and run against the submitted password.

Allowed validator names (NAME) Built-in choices in PasswordValidatorSerializer include: MinimumLengthValidator, CommonPasswordValidator, NumericPasswordValidator, UserAttributeSimilarityValidator (Django); MaximumLengthValidator, MinimumCapitalLetterValidator, MinimumLowerCaseLetterValidator, MinimumLetterValidator, MinimumNumberValidator, MinimumSpecialCharacterValidator, PreviouslyUsedPasswordValidator (omnicore); OldPasswordValidator (omnishop).

Key: AUTH_PASSWORD_VALIDATORS Type: array of objects (each: NAME string, OPTIONS object) Default: from Django settings AUTH_PASSWORD_VALIDATORS

Example

23. Reset Email Html Template

Template name (path) used for the HTML part of the password reset email sent when a user requests a password reset. If set, Django's PasswordResetForm.send_mail() is called with html_email_template_name set to this value, so the reset link email can use your custom HTML layout instead of the default.

Where it is used

  • omnishop.users.forms.PasswordResetForm — In send_mail(): kwargs['html_email_template_name'] = dj_dynamic_settings.RESET_EMAIL_HTML_TEMPLATE before calling super().send_mail(*args, **kwargs). Only has effect if the form sends HTML; the template receives the same context as the plain-text reset email (e.g. user, reset link).

Key: RESET_EMAIL_HTML_TEMPLATE Type: string (template path) Default: getattr(settings, "RESET_EMAIL_HTML_TEMPLATE", None) (often None)

Example

  • "emails/password_reset.html" — use a project template under templates/emails/password_reset.html.

  • None or unset — no HTML part or Django default behaviour.

24. Phone Number Unique Validator Active

When true, the phone number field is validated so that it is unique across active users (no other active user can have the same phone). When false, the UniqueValidator for phone is not applied and duplicate phone numbers are allowed. Use this to enforce one-phone-per-account in registration and profile updates, or disable it to allow shared/duplicate phones (e.g. family or test data).

Where it is used

  • omnishop.users.resources.serializers — Phone field validators use ConditionalValidator(lambda: dj_dynamic_settings.PHONE_NUMBER_UNIQUE_VALIDATOR_ACTIVE, UniqueValidator(queryset=User.objects.filter(is_active=True), message=_('Phone number is already in use with another account.'))). So when the setting is true, the uniqueness check runs; when false, it is skipped. Used on RegisterSerializer and any profile/serializer that includes the phone field (e.g. around lines 89, 249, 461).

Key: PHONE_NUMBER_UNIQUE_VALIDATOR_ACTIVE Type: boolean Default: False

Example

  • true — registration and profile update will fail if the phone is already used by another active user.

  • false — duplicate phone numbers are allowed.

25. Contact Us Email To

Maps operation (or context) keys to the recipient email address(es) for the Contact Us form. Each value must be a single email string or a list of email strings; all are validated as valid emails. The form submits an operation (e.g. defaults, contact_us, franchise); the service looks up CONTACT_US_EMAIL_TO[operation] or falls back to CONTACT_US_EMAIL_TO['defaults'] to build the To list for the email. Optional behaviour: CONTACT_US_SEND_USER adds the submitter to To; CONTACT_US_REPLY_TO_ONLY_USER sets Reply-To to the submitter only.

Where it is used

  • omnishop.users.resources.serializers — In validate_operation(): contact_us_emails = dj_dynamic_settings.CONTACT_US_EMAIL_TO; the submitted operation must be one of contact_us_emails.keys(), otherwise a validation error is raised.

  • omnishop.users.service — When sending the Contact Us email: contact_us_emails = dj_dynamic_settings.CONTACT_US_EMAIL_TO; to = contact_us_emails.get(operation) or contact_us_emails.get('defaults'); if to is a list/tuple it is used as-is, if a string it is wrapped in a single-element tuple. That to is used as the email To list (and optionally combined with the user email per CONTACT_US_SEND_USER / CONTACT_US_REPLY_TO_ONLY_USER).

Key: CONTACT_US_EMAIL_TO Type: object (dict: key → string or list of strings, all valid emails) Default: {"defaults": "contactus@akinon.com"} (or from Django settings)

Example

The operation chosen in the form (e.g. franchise) selects the value for that key; if the key is missing, defaults is used.

26. Available Currencies

List of currency codes that the shop supports (e.g. ["try", "usd", "eur"]). Validation rules: the list must contain no duplicates and must include the value of DEFAULT_CURRENCY. Used to validate user-selected currency (e.g. in serializers) and to expose which currencies the frontend can offer in the API.

Where it is used

  • omnishop.users.settings.confAvailableCurrencies validators ensure len(currencies) == len(set(currencies)) and dynamic_settings.DEFAULT_CURRENCY in currencies.

  • omnishop.users.resources.serializers — Currency choice validation checks that the value is in dj_dynamic_settings.AVAILABLE_CURRENCIES (e.g. lambda currency_code: (currency_code in dj_dynamic_settings.AVAILABLE_CURRENCIES)).

  • omnishop.utils.currency — Asserts that the currency is in dynamic_settings.AVAILABLE_CURRENCIES.

  • omnishop.users.resources.views — Response includes "available_currencies": dynamic_settings.AVAILABLE_CURRENCIES for the client.

Key: AVAILABLE_CURRENCIES Type: array (list of strings; choices from CurrencyType.choices()) Default: [settings.DEFAULT_CURRENCY_TYPE]

Example

Must include the value of DEFAULT_CURRENCY (e.g. if default is try, try must be in the list).

27. User Phone Regex

Regular expression used to validate user phone numbers (format and length). Applied in validators, services, and allauth adapter; also exposed in the API so the frontend can show the expected format or run client-side validation. Some code strips the leading ^ for use in DB or display patterns.

Where it is used

  • omnishop.users.validatorsregex = dynamic_settings.USER_PHONE_REGEX; used to validate phone input.

  • omnishop.users.serviceregex = dynamic_settings.USER_PHONE_REGEX.replace("^", "") for formatting/validation logic.

  • omnishop.users.allauth_adapter — Same regex (with ^ stripped) for phone handling.

  • omnishop.users.resources.views — Response includes "user_phone_regex": dynamic_settings.USER_PHONE_REGEX for the client.

Key: USER_PHONE_REGEX Type: string Default: r'^(05)\d{9}$' (Turkish mobile: 05 + 9 digits)

Example

  • ^(05)\d{9}$ — Turkish mobile (05xxxxxxxxx).

  • ^(09)\d{9}$ — Alternative 09-prefix format.

  • ^\+90\d{10}$ — E.164-style Turkish.

28. User Phone Format

Example phone string displayed in validation error messages so the user sees the expected format (e.g. placeholder or hint). Human-readable only; actual validation is done with USER_PHONE_REGEX. Use a value that matches your regex (e.g. same length and pattern).

Where it is used

  • Used where phone validation errors are raised so the message can include this format (e.g. "Phone must match format: {USER_PHONE_FORMAT}").

  • Default ensures a sensible Turkish-style example when the setting is not overridden.

Key: USER_PHONE_FORMAT Type: string Default: "05999999999"

Example

  • 05999999999 — Turkish mobile placeholder.

  • 05123456789 — Alternative example matching the same regex.

29. Active Subscription Gateways

List of subscription gateway names (strings) that are currently active. Resolution order in get_subscription_gateways(): (1) if CMS gateways of type subscription exist, those are used; (2) else if this list is non-empty, this list is returned; (3) else [SUBSCRIPTION_GATEWAY] is returned. Each name in this list must exist as a key in SUBSCRIPTION_GATEWAYS so that get_gateway_settings(gateway_name) can load klass and conf. Use multiple names to run several gateways (e.g. Emarsys + Insider); use an empty list to rely on the single SUBSCRIPTION_GATEWAY.

Where it is used

  • omnishop.users.service — In get_subscription_gateways(): active_subscription_gateways = dj_dynamic_settings.ACTIVE_SUBSCRIPTION_GATEWAYS; if active_subscription_gateways is truthy, the method returns it; otherwise returns [subscription_gateway]. The returned names are then used to instantiate gateways via get_gateway_settings(name) and get_subscription_gateway(name).

Key: ACTIVE_SUBSCRIPTION_GATEWAYS Type: array (list of strings) Default: getattr(settings, "ACTIVE_SUBSCRIPTION_GATEWAYS", [])

Example

  • Two gateways active; both must have entries in SUBSCRIPTION_GATEWAYS.

  • [] — no active list; SUBSCRIPTION_GATEWAY is used as the single gateway.

30. Subscription Gateway

Single subscription gateway name used when ACTIVE_SUBSCRIPTION_GATEWAYS is empty. Must match a key in SUBSCRIPTION_GATEWAYS. The subscription service calls get_gateway_settings(this_name) to get the config dict (from DB or from SUBSCRIPTION_GATEWAYS[name]), then instantiates the gateway with klass and conf. Typical values are gateway slugs such as emarsys, insider, revotas, setrow, euromessage.

Where it is used

  • omnishop.users.service — In get_subscription_gateways(): subscription_gateway = dj_dynamic_settings.SUBSCRIPTION_GATEWAY; when ACTIVE_SUBSCRIPTION_GATEWAYS is empty, the method returns [subscription_gateway]. That name is later passed to get_gateway_settings(gateway_name) which does dj_dynamic_settings.SUBSCRIPTION_GATEWAYS.get(gateway_name, None) if not found in CMS Gateway model.

Key: SUBSCRIPTION_GATEWAY Type: string Default: getattr(settings, "SUBSCRIPTION_GATEWAY", None)

Example

  • emarsys — use the emarsys entry in SUBSCRIPTION_GATEWAYS.

  • revotas — use Revotas gateway config.

  • insider — use Insider gateway config.

The value must exist as a key in SUBSCRIPTION_GATEWAYS (or be provided by CMS Gateway settings).

31. Subscription Active

Master switch for subscription/membership features (newsletter, CRM sync, consent gateways). When false, subscription-related views or logic may be skipped (e.g. the decorated view does nothing, or the post-login sync is not triggered). When true, subscription gateways and sign-up flows operate as configured; the receiver can trigger subscribe_user_pk_task after user login.

Where it is used

  • omnishop.utils.decorators.subscription_activated — Wraps a view so it runs only when dynamic_settings.SUBSCRIPTION_ACTIVE is true: if dynamic_settings.SUBSCRIPTION_ACTIVE: return fn(self, *args, **kwargs); otherwise the wrapped function is not called.

  • omnishop.users.receivers.user_subscription_receiver_on_save — On user save (not create) when instance.last_login is set: if dynamic_settings.SUBSCRIPTION_ACTIVE and not created and instance.last_login: then subscribe_user_pk_task.delay(instance.pk) is enqueued to sync the user with subscription gateways.

Key: SUBSCRIPTION_ACTIVE Type: boolean Default: getattr(settings, "SUBSCRIPTION_ACTIVE", False)

Example

  • true — subscription views and post-login subscription sync are active.

  • false — subscription flows are disabled (default).

32. Favourite SKU is Active

Controls which product identifier is used when listing or deduplicating favourite (wishlist) products. When true, the favourite list is distinct by product_id (one row per product ID). When false, it is distinct by product__base_code (one row per base code, so variants can be grouped). Affects both the order_by/distinct() clause and the meaning of "same product" in the favourites list.

Where it is used

  • omnishop.wishlists.resources.views.FavouriteProductViewSet.listfavourite_sku_is_active = dynamic_settings.FAVOURITE_SKU_IS_ACTIVE; then distinct_query = 'product_id' if favourite_sku_is_active else 'product__base_code'; the queryset is ordered and distinct by that field so the list shows one entry per product ID or per base code.

Key: FAVOURITE_SKU_IS_ACTIVE Type: boolean Default: from Django settings

Example

  • true — favourites are keyed by product_id (each variant counts separately).

  • false — favourites are keyed by base_code (variants of the same base product grouped).

33. Max Product per User Collection

Maximum number of products allowed in a single user collection (e.g. a wishlist or custom list). When the user adds an item, the serializer counts existing items in that collection; if total_products >= MAX_PRODUCT_PER_USER_COLLECTION, a validation error is raised and the add is rejected. The error message can include the limit (e.g. "You can not add more than {0} products to collection.").

Where it is used

  • omnishop.wishlists.serializers.UserCollectionItemSerializer.validateuser_collection_max_product = dynamic_settings.MAX_PRODUCT_PER_USER_COLLECTION; total_products = self.Meta.model.objects.filter(usercollection=attrs['usercollection']).count(); if total_products >= user_collection_max_product then ValidationError is raised with the configured message.

Key: MAX_PRODUCT_PER_USER_COLLECTION Type: number (int) Default: from Django settings (often 50 in comments)

Example

  • 50 — up to 50 products per collection.

  • 100 — more per list. Use a lower value (e.g. 2) in tests to assert the limit.

34. AddressPhoneMinLength

Minimum number of characters required for the address phone number in the Address serializer. The phone field is validated with Django's MinLengthValidator(ADDRESS_PHONE_MIN_LENGTH); values shorter than this are rejected. Use it to enforce a minimum length (e.g. 11 for Turkish mobile) without tying to a specific regex.

Where it is used

  • omnishop.address.resources.serializers — The address phone field has a validator: MinLengthValidator(dynamic_settings.ADDRESS_PHONE_MIN_LENGTH)(value) (or equivalent via lambda value: MinLengthValidator(dynamic_settings.ADDRESS_PHONE_MIN_LENGTH)(value)). Applied when validating address data (e.g. checkout or profile address).

Key: ADDRESS_PHONE_MIN_LENGTH Type: number (int) Default: 11

Example

  • 11 — Turkish mobile length (05xxxxxxxxx).

  • 10 — Shorter format. Should be consistent with USER_PHONE_REGEX if both are used.

35. CheckoutWithTokenAllowAnonymous

When true, anonymous users can open the checkout-with-token flow (e.g. from a QR code or one-time link): the view allows access when there is no user from the token but the session exists and this setting is true. When false, token checkout requires an authenticated user from the token; otherwise 404 or "not allowed" is returned. Also controls whether checkout URLs with token are generated for anonymous sessions (e.g. in-store flow).

Where it is used

  • omnishop.orders.views.CheckoutWithTokenView.getanonymous_allowed = dynamic_settings.CHECKOUT_WITH_TOKEN_ALLOW_ANONYMOUS; if not user and (not anonymous_allowed or not getattr(request.session, "session_key", None)) then raise Http404. So anonymous access is allowed only when this is true and a session exists.

  • omnishop.orders.service — In get_checkout_urls_with_token: is_anonymous_allowed = dj_dynamic_settings.CHECKOUT_WITH_TOKEN_ALLOW_ANONYMOUS; _is_user_allowed(request, is_anonymous_allowed) decides whether to return checkout URL and token; the query string is built with is_anonymous_allowed so the frontend can show the right behaviour.

Key: CHECKOUT_WITH_TOKEN_ALLOW_ANONYMOUS Type: boolean Default: false

Example

  • true — QR/one-time-link checkout works for guest users (with session).

  • false — only logged-in user from token can use the link (default).

36. OrdersRefundableDays

Number of days after order (or order item) placement during which the order is eligible for return/refund. Exposed as a property on the order and on order items so refund/return logic can decide whether to allow the action. Past this window, return or refund options are typically disabled. null means no day-based limit is enforced by this setting (downstream logic may still allow or deny).

Where it is used

  • omnishop.orders.models.Order.refundable_daysreturn dynamic_settings.ORDERS_REFUNDABLE_DAYS.

  • omnishop.orders.models.OrderItem.refundable_daysreturn dynamic_settings.ORDERS_REFUNDABLE_DAYS. Refund/return code compares order age (e.g. days since creation) to this value to decide eligibility.

Key: ORDERS_REFUNDABLE_DAYS Type: number (int) or null Default: getattr(settings, "ORDERS_REFUNDABLE_DAYS", None)

Example

  • 30 — returns/refunds allowed within 30 days of order.

  • 14 — shorter window.

  • null — no day limit from this setting; business logic may still restrict returns.

37. GiftBoxConfigurations

Config for the optional gift-box product in checkout: sku — product SKU used to resolve the gift box product and its price; is_active — boolean to show/hide the gift box step and offer. When is_active is true, the checkout index page and gift box page use this config; the GiftBox helper is instantiated with **dj_dynamic_settings.GIFT_BOX_CONFIGURATIONS so it can load price and attach the gift box to the pre_order.

Where it is used

  • omnishop.orders.pages.indexgift_box_conf = dj_dynamic_settings.GIFT_BOX_CONFIGURATIONS; context includes 'has_gift_box': gift_box_conf.get('is_active') or False.

  • omnishop.orders.pages.gift_boxGiftBoxPreCondition.is_valid and GiftBoxPage.is_gift_box_active use gift_box_conf.get('is_active'). GiftBoxPage.get_page_context and process_pre_order build a GiftBox with GiftBox(..., **dj_dynamic_settings.GIFT_BOX_CONFIGURATIONS) to get price and attach to pre_order.

Key: GIFT_BOX_CONFIGURATIONS Type: object (keys: sku, is_active) Default: {"sku": null, "is_active": false}

Example

  • sku must match a product SKU in the catalog; that product is used as the gift box and for pricing.

38. PrettyUrlIncludeDefaultLanguage

When true, pretty URL generation includes the default/site language in the path even when the language is the default (e.g. /en/products/... for default English). When false, the default language is represented with a "none" language code so the path can omit the language prefix (e.g. /products/... for default). Used inside the prettyurls language decorator when building language_code for URL generation.

Where it is used

  • omnishop.prettyurls.generators — In the decorator that injects language into URL generation: include_default_language = dynamic_settings.PRETTY_URL_INCLUDE_DEFAULT_LANGUAGE; if language == site_language and not include_default_language then language_code = none_language, else language_code = get_language_prefix(language).lower(). So the generated path includes or omits the language segment based on this setting.

Key: PRETTY_URL_INCLUDE_DEFAULT_LANGUAGE Type: boolean Default: false

Example

  • true — default language still appears in URL (e.g. /en/...).

  • false — default language has no prefix in the path (e.g. /...).

39. ForceNotRedirectForI18N

When true, the I18N middleware skips the logic that redirects the user to a URL with the correct language prefix (e.g. when PRETTY_URL_MULTI_LANGUAGE is true and the path language does not match the active language or site default). When false, that redirect runs so users are sent to the localized path. Use true to disable automatic language redirects (e.g. for API or when you handle language elsewhere).

Where it is used

  • omnicore.utils.middleware — The condition for performing the language redirect is getattr(settings, 'PRETTY_URL_MULTI_LANGUAGE', False) and not getattr(dynamic_settings, 'FORCE_NOT_REDIRECT_FOR_I18N', False). So when FORCE_NOT_REDIRECT_FOR_I18N is true, the block that calls get_localized_url and redirect_response is skipped and no redirect is made.

Key: FORCE_NOT_REDIRECT_FOR_I18N Type: boolean Default: false

Example

  • true — no automatic redirect to language-prefixed URL.

  • false — middleware may redirect to the localized URL when multi-language pretty URLs are enabled.

40. RetailStoreFilterStrategy

Dotted path to the strategy class that filters which retail stores (e.g. click-and-collect) are shown for a basket. Strategies: FullySatisfiedQuantityFilterStrategy — only stores that can fulfill the full basket quantity; PartiallySatisfiedQuantityFilterStrategy — stores that can fulfill at least part; NotSatisfiedQuantityFilterStrategy — all stores regardless of stock.

Where it is used

  • omnishop.products.backend.gateways.service — In get_strategy(): klass = import_string(dynamic_settings.RETAIL_STORE_FILTER_STRATEGY)(); the returned strategy instance is used when resolving store list for the basket (e.g. for pickup or click-and-collect).

Key: RETAIL_STORE_FILTER_STRATEGY Type: string (dotted path) Default: NotSatisfiedQuantityFilterStrategy

Choices

  • omnishop.products.backend.gateways.filter_strategies.FullySatisfiedQuantityFilterStrategy — only stores that fully satisfy basket quantity.

  • omnishop.products.backend.gateways.filter_strategies.PartiallySatisfiedQuantityFilterStrategy — stores that partially satisfy.

  • omnishop.products.backend.gateways.filter_strategies.NotSatisfiedQuantityFilterStrategy — all stores (no stock filter).

Example

Use FullySatisfiedQuantityFilterStrategy to show only stores that can fulfill the entire basket; use NotSatisfiedQuantityFilterStrategy to show all stores regardless of stock.

41. PromotionGatewayActiveSettings

When true, the promotion gateway is considered active and virtual offers (e.g. from brand-specific integrations like Ayakkabı Dünyası) can be queried and applied. When false, the gateway is off and no external promotion queries run.

Where it is used

  • omnishop.promotions.backend.gateways.service — In the gateway service: is_active is True only when dynamic_settings.PROMOTION_GATEWAY_ACTIVE and self.promotion_gateways are both truthy; query() returns an empty list if not self.is_active, otherwise it fetches offers from configured promotion gateways.

Key: PROMOTION_GATEWAY_ACTIVE Type: boolean Default: false

Example

Set to True when using a promotion gateway (e.g. Erencard, Softtouch, Hitit); leave False if you do not use external promotion gateways.

42. SmsGateways

Dictionary mapping SMS gateway names to their configuration objects. Each entry typically has klass (dotted path to the backend class) and conf (gateway-specific options, e.g. verify_message for OTP text). The gateway actually used is selected by SMS_GATEWAY. Used for sending SMS (OTP, notifications).

Where it is used

  • omnishop.orders.service.SmsService_get_sms_gateway_settings(sms_gateway) returns dj_dynamic_settings.SMS_GATEWAYS.get(sms_gateway); _get_gateway() uses that config to instantiate the backend via import_string(gateway_config.get('klass'))(**gateway_config.get('conf')). When SMS_GATEWAY is "console", a built-in console backend is used instead.

Key: SMS_GATEWAYS Type: object Default: {"console": {"conf": {"verify_message": "Verification code: {}"}}}

Example

43. SmsGateway

Name of the active SMS gateway. If set to "console", SMS/OTP are logged to the console (no real sending). Otherwise this value must exist as a key in SMS_GATEWAYS; that entry's klass and conf are used to send SMS.

Where it is used

  • omnishop.orders.service.SmsService_get_gateway() reads dj_dynamic_settings.SMS_GATEWAY; when it is "console" it returns SmsBackend; otherwise it looks up the config in SMS_GATEWAYS and instantiates the configured backend. Used by send_sms, send_otp, and verify_otp.

Key: SMS_GATEWAY Type: string Default: "console"

Example

Use "console" for local/testing; use the same slug as a key in SMS_GATEWAYS (e.g. "provider_slug") for production SMS.

44. ReCaptchaSiteKey

Google reCAPTCHA v2 site key (public key) shown in the browser. The frontend uses it to render the reCAPTCHA widget; the user response token is then verified on the server using RECAPTCHA_SECRET_KEY.

Where it is used

  • omnishop.users.forms.CaptchaFieldsite_key = property(lambda self: dj_dynamic_settings.RECAPTCHA_SITE_KEY); passed to the widget as data-sitekey. Both RECAPTCHA_SITE_KEY and RECAPTCHA_SECRET_KEY must be set or the field raises ImproperlyConfigured.

Key: RECAPTCHA_SITE_KEY Type: string Default: ''

Example

Set to the site key from Google reCAPTCHA admin (e.g. "6Lc...") when using reCAPTCHA on registration or contact forms.

45. ReCaptchaSecretKey

Google reCAPTCHA secret key used for server-side verification. The backend sends this with the user's response token to https://www.google.com/recaptcha/api/siteverify to validate the captcha.

Where it is used

  • omnishop.users.forms.CaptchaFieldsecret_key property and validate(): POST to siteverify with secret and response; both keys must be defined for the field to work.

Key: RECAPTCHA_SECRET_KEY Type: string Default: ''

Example

Set to the secret key from the same reCAPTCHA admin; keep it server-side only and never expose it in the frontend.

46. SelfAnonymizationEnabled

When true, authenticated users can trigger self-anonymization (account data anonymized and session logged out). When false, the self-anonymization API returns 403.

Where it is used

  • omnishop.users.views — In the self-anonymization patch handler: if not dynamic_settings.SELF_ANONYMIZATION_ENABLED then raise PermissionDenied(); otherwise the service anonymizes the user and logs them out.

Key: SELF_ANONYMIZATION_ENABLED Type: boolean Default: false

Example

Enable when you offer a "Delete my data" or "Anonymize my account" self-service option; disable if only admins should perform anonymization.

47. ContactUsSendUser

When true, the Contact Us form submitter's email is added to the email's To list (in addition to CONTACT_US_EMAIL_TO). When false, only the configured recipients receive the email.

Where it is used

  • omnishop.users.service — When sending the Contact Us email: if dj_dynamic_settings.CONTACT_US_SEND_USER and email: then to += (email,). Reply-To is set separately by CONTACT_US_REPLY_TO_ONLY_USER.

Key: CONTACT_US_SEND_USER Type: boolean Default: false

Example

Set to true so the user gets a copy of the message or is visible as a recipient; set to false to send only to internal addresses.

48. ContactUsReplyToOnlyUser

When true, the Contact Us email's Reply-To is set only to the submitter's email so that "Reply" goes to the user. When false, Reply-To is the same as the To list.

Where it is used

  • omnishop.users.service — When building the email: if dj_dynamic_settings.CONTACT_US_REPLY_TO_ONLY_USER and email: then reply_to = (email,); otherwise reply_to = tuple(to).

Key: CONTACT_US_REPLY_TO_ONLY_USER Type: boolean Default: false

49. KvkkGateway

Configuration for the KVKK (GDPR) consent gateway. When set, the system can sync consent/permission changes (SMS, email, call, ETK share) to an external gateway for verified users. Structure is validated by KvkkGatewaySerializer (typically name and conf or similar fields).

Where it is used

  • omnishop.users.service — In update_kvkk_permissions(): KVKK_GATEWAY = dj_dynamic_settings.KVKK_GATEWAY; if not KVKK_GATEWAY or not verified_user the method returns without calling the gateway; otherwise it calls update_permissions() with the gateway (e.g. for Mobildev).

Key: KVKK_GATEWAY Type: object Default: null

Example

Configure when using a KVKK/consent provider (e.g. Mobildev); leave null if you do not sync consent to an external gateway.

50. DefaultCurrency

Default currency code for the shop (e.g. try, usd). Must be one of the values in AVAILABLE_CURRENCIES. Used for pricing, basket, and order defaults when no other currency is selected.

Where it is used

  • omnishop.users.settings.conf — Validated via FunctionThroughValidator: value must be in dynamic_settings.AVAILABLE_CURRENCIES. AVAILABLE_CURRENCIES in turn validates that it contains DEFAULT_CURRENCY.

  • Orders, promotions, wishlists, segmentation, loyalty — Tests and services use it as the default currency (e.g. override_dynamic_settings(DEFAULT_CURRENCY="try"), basket/order currency fallback).

Key: DEFAULT_CURRENCY Type: string Default: from Django settings (e.g. DEFAULT_CURRENCY_TYPE)

Example

Set to the primary store currency (e.g. "try", "usd"); must appear in AVAILABLE_CURRENCIES.

51. MobildevConf

Mobildev integration configuration (validated by MobildevConfSerializer). Typically holds a conf object with credentials and options used to communicate with the Mobildev API for KVKK/consent, user sync, or subscription features.

Where it is used

  • omnishop.libs.kvkk_gateways.mobildev.service.MobilDevServicegateway property builds the Mobildev gateway with MobilDev(**settings.MOBILDEV_CONF['conf']); used for sending confirmation codes, blacklist, and permission sync.

  • omnishop.users.tests.test_tasks — KVKK tasks may override with Mobildev config for testing.

Key: MOBILDEV_CONF Type: object Default: {} (from Django MOBILDEV_CONF)

Example

Configure when using Mobildev for KVKK/consent or user sync; structure must match MobildevConfSerializer (e.g. conf with API credentials).

52. ShouldSendVerificationEmail

When true, the system sends a verification email after guest user registration (and when applicable after order). When false, EMAIL_VERIFICATION is forced to None so no verification email is sent.

Where it is used

  • omnishop.users.service — When creating a guest user: should_send_mail = dj_dynamic_settings.SHOULD_SEND_VERIFICATION_EMAIL; if not set, email_verification is set to None so allauth does not send the verification email.

Key: SHOULD_SEND_VERIFICATION_EMAIL Type: boolean Default: true

Example

Set to false to disable verification emails for guest signups; set to true for normal verification flow.

53. UniqueValidatorPhoneMessage

Error message shown when phone uniqueness validation fails (e.g. user or loyalty card registration with a phone number that already exists).

Where it is used

  • omnishop.users.resources.serializers — Raised as serializers.ValidationError(_(dj_dynamic_settings.UNIQUE_VALIDATOR_PHONE_MESSAGE)) when phone is duplicate (e.g. in user profile, registration, or loyalty serializers).

  • omnishop.loyaltycard.resources.serializers — Same message when phone uniqueness fails for loyalty card.

Key: UNIQUE_VALIDATOR_PHONE_MESSAGE Type: string Default: ""

Example

e.g. "This phone number is already registered." or a localized message key.

53.1. User Profile Validations

Dynamically defines business rule validators that run during user registration and profile updates. When left empty, no additional validation is applied.

Key: USER_PROFILE_VALIDATIONS Type: array of objects Validation: Each element must have a klass and optionally a defaults field Default: []

Valid klass options:

Value
Business Rule

omnishop.users.helpers.check_orders

Blocks profile changes when the user has pending/awaiting-confirmation orders. Prevents critical profile data from changing during payment flows. Use defaults.status to restrict to a specific order status (e.g. "350" for confirmation_waiting).

omnishop.users.helpers.check_unique_phone

Prevents the same phone number from being used on multiple accounts.

Element structure:

Field
Type
Required
Description

klass

string (choice)

Yes

Validator to execute

defaults

dict

No

Additional parameters passed to the validator

Important behaviour:

  • Validators run only during profile updates, not during registration (registration validations are managed by a separate setting)

  • When validation fails, an error is returned to the user and the operation is not completed

  • For check_orders, the defaults.status field is required; omitting it will cause a system error

Order status codes

When using check_orders, the defaults.status value refers to one of the following order statuses:

Code
Enum name
Description

50

cancellation_waiting

Cancellation waiting

100

cancelled

Cancelled

200

waiting

Waiting

300

payment_waiting

Payment waiting

350

confirmation_waiting

Confirmation waiting

400

approved

Approved

450

preparing

Preparing

500

shipped

Shipped

510

shipped_and_informed

Shipped and informed

520

ready_for_pickup

Ready for pickup

540

attempted_delivery

Attempted delivery

544

review_started

Review started

545

review_waiting

Review waiting

546

waiting_for_payment

Waiting for payment (trade-in)

547

paid

Paid (trade-in)

550

delivered

Delivered

600

refunded

Refunded

Example:

In the example above, check_orders with "status": "350" validates against orders that are in confirmation_waiting status.

54. AddressSerializerField

Per-country configuration for extra or customized fields on the address serializer. Structure: dict keyed by country code (e.g. "tr", "default"), each value a list of field configs with field, optional kwargs, and optional validators (klass + kwargs). Used to add or override address fields and validators by country.

Where it is used

  • omnishop.address.resources.serializers.AddressSerializer — In __init__: reads dynamic_settings.ADDRESS_SERIALIZER_FIELDS; selects the list by country.code or falls back to "default"; for each entry adds or updates the field (with optional validators). Also respects ADDRESS_DISTRICT_REQUIRED for district.

Key: ADDRESS_SERIALIZER_FIELDS Type: object (dict: country code to list of field configs) Default: {"default": []}

Example

{"default": [], "tr": [{"field": "district", "kwargs": {"required": true}, "validators": [{"klass": "...", "kwargs": {"message": "..."}}]}]}

55. TmpSapCRMMobildevActivationSetting

When true, enables temporary logic that uses Mobildev user data (e.g. mobildev_id from user attributes) in SAP/Hana CRM flows. When false, that behaviour is disabled.

Where it is used

  • omnishop.libs.crm_gateways.hana.service — When syncing or building CRM payloads: if getattr(dynamic_settings, "TMP_SAP_CRM_MOBILDEV_ACTIVATION_SETTING", False): then e.g. mobildev_id = user.attributes.get("mobildev_id") is used.

  • omnishop.libs.crm_gateways.hana.gateway — Same check for Mobildev activation in gateway code.

Key: TMP_SAP_CRM_MOBILDEV_ACTIVATION_SETTING Type: boolean Default: false

Example

Set to true only when SAP CRM integration is configured to use Mobildev IDs; treat as temporary until a permanent integration is in place.

56. CRMConf

CRM integration configuration. Typically a dict with a conf key holding gateway-specific options (e.g. SAP/Hana CRM credentials and endpoints). Used when syncing orders or customers to an external CRM.

Where it is used

  • omnishop.libs.crm_gateways.hana.service — Gateway is built with HanaCrmGateway(**dynamic_settings.CRM_CONF['conf']); used for order/customer sync to Hana CRM.

Key: CRM_CONF Type: object Default: {} (from Django CRM_CONF)

Example

Structure must match what the CRM gateway expects (e.g. {"conf": {"base_url": "...", ...}} for Hana).

57. OmnitronAPI

Omnitron API credentials and endpoints (validated by OmnitronAPISerializer). Used by the Omnitron API client for auth, orders, cancellation, shipping cost, etc.

Where it is used

  • omnishop.libs.api_clients.omnitron.client.OmnitronApiClientget_data() reads getattr(dynamic_settings, 'OMNITRON_API', {}) for host, oms_host, auth_url (derived from host), username, passwd, email, channel_id. Used for authentication and all API requests (orders, cancellation, bank account, etc.).

  • omnishop.orders.service, omnishop.orders.resources.views, omnishop.orders.pages.base, omnishop.orders.tasks — Use OmnitronApiClient() which relies on this setting.

Key: OMNITRON_API Type: object Default: {} (from Django OMNITRON_API)

Example

e.g. {"host": "https://...", "username": "...", "passwd": "...", "email": "..."}; may include oms_host, channel_id depending on serializer.

58. SecuritycopIpBanTimeout

Duration in seconds that an IP ban lasts (e.g. after too many failed login or suspicious attempts). After this time, the IP is no longer treated as banned and the cache key expires.

Where it is used

  • omnicore_project.omnicore.security.services.SecurityCop — In catch(): _IP_BAN_TIMEOUT = getattr(dynamic_settings, "SECURITYCOP_IP_BAN_TIMEOUT", 60 * 60 * 6); that value is used as the cache TTL when marking the client IP as needing verification (cache.set(cache_key, True, _IP_BAN_TIMEOUT)). Used to decide how long the IP remains "suspicious" before the ban expires.

Key: SECURITYCOP_IP_BAN_TIMEOUT Type: int Default: 21600 (6 hours)

Example

Use a smaller value (e.g. 3600) for shorter bans, or a larger one for stricter security.

59. BasketMaxItemCount

Maximum total quantity of items allowed in a single basket (sum of all line quantities). When exceeded, the basket condition raises BasketMaxItemCount and adding/updating items is blocked.

Where it is used

  • omnishop.baskets.conditions.basket_item_max_countbasket_max_item_count = dj_dynamic_settings.BASKET_MAX_ITEM_COUNT; if basket.get_total_quantity() > basket_max_item_count then raise exceptions.BasketMaxItemCount(params=(basket_max_item_count,)). Used when evaluating basket conditions (e.g. before adding to cart).

Key: BASKET_MAX_ITEM_COUNT Type: int Default: 80

Example

Lower the value (e.g. 10) to enforce a stricter cap; raise it for high-quantity B2B baskets.

60. GroupedProductPriceSelector

Dotted path to the callable that selects the displayed price for a grouped product (e.g. min, max, or sum of variant prices).

Where it is used

  • omnishop.catalogs.selector.get_group_product_price_selector — Returns import_string(dynamic_settings.GROUPED_PRODUCT_PRICE_SELECTOR); that callable is used when resolving the price to show for a grouped product (e.g. in catalog/price logic).

Key: GROUPED_PRODUCT_PRICE_SELECTOR Type: string (dotted path) Default: omnishop.catalogs.selector.group_product_min_price_selector

Example

  • omnishop.catalogs.selector.group_product_min_price_selector — show minimum variant price.

  • omnishop.catalogs.selector.group_product_max_price_selector — show maximum variant price.

  • omnishop.catalogs.selector.group_product_sum_price_selector — show sum of variant prices.

61. ListSimpleInsteadOfMeta

When true, a simple (child) product can be chosen as the listable product for a group instead of the meta (parent). When false, the listable product is the meta product. Affects which product is used for listing/display and URL generation.

Where it is used

  • omnishop.products.service — In product creation and meta creation: list_simple = dynamic_settings.LIST_SIMPLE_INSTEAD_OF_META; when true, listable is resolved from children with is_listable=True; when false, product_listable = parent. Also in _create_product_meta: is_listable = not is_listable and not list_simple.

Key: LIST_SIMPLE_INSTEAD_OF_META Type: boolean Default: false

Example

Set to true when you want the listable product in listing pages to be a specific variant (simple) rather than the group (meta).

62. NoReplyEmail

Sender (From) address used for system emails that should not receive replies (e.g. order confirmations, shipping notifications, verification codes). Validated as a valid email.

Where it is used

  • omnishop.users.service — Verification code email: from_email = dj_dynamic_settings.NO_REPLY_EMAIL. Other code paths use settings.NO_REPLY_EMAIL or getattr(settings, 'NO_REPLY_EMAIL', 'noreply@akinon.com') for order/shipping/contact emails (Django settings; dynamic value can override at runtime if wired).

  • omnishop.orders.service — Multiple email sends use from_email=settings.NO_REPLY_EMAIL for order and shipping emails.

Key: NO_REPLY_EMAIL Type: string Default: noreply@akinon.com

Example

Set to your no-reply address (e.g. noreply@yourdomain.com).

63. EmailSmtpConfiguration

SMTP connection settings for sending email (validated by EmailSmtpConfigurationSerializer). Typically includes host, port, username, password, use_tls, use_ssl, ssl_certfile, ssl_keyfile, timeout. Passed to the Django SMTP backend so sending uses these values instead of or in addition to Django EMAIL_* settings.

Where it is used

  • omnishop.cms.email.backends.smtp.EmailBackend — In __init__: conf = dynamic_settings.EMAIL_SMTP_CONFIGURATION then conf.update(**kwargs) and super().__init__(**conf); the backend is thus configured from this setting.

Key: EMAIL_SMTP_CONFIGURATION Type: object Default: derived from Django EMAIL_HOST, EMAIL_PORT, etc.

Example

Override at runtime for different SMTP credentials or TLS/SSL without changing Django settings.

64. PushNotificationActive

When true, push notification dispatch is enabled (order created, status changed, basket offer, etc.). When false, the notification decorator skips sending.

Where it is used

  • omnishop.libs.push_notification_gateways.service.NotificationDispatchService — Methods are decorated with @notification_activated; the decorator checks getattr(dynamic_settings, 'PUSH_NOTIFICATION_ACTIVE', False) and only runs the method (e.g. notify_order_created, notify_order_status_changed) when true.

Key: PUSH_NOTIFICATION_ACTIVE Type: boolean Default: false

Example

Set to true when using a push gateway (EuroMessage, Webinstats, etc.); ensure PUSH_NOTIFICATION_GATEWAY and PUSH_NOTIFICATION_GATEWAYS are configured.

65. PushNotificationGateway

Name of the active push notification gateway. Must match a key in PUSH_NOTIFICATION_GATEWAYS. The gateway is instantiated with that entry's klass and conf.

Where it is used

  • omnishop.users.service.PushNotificationServicegateway property: gateway_name = dj_dynamic_settings.PUSH_NOTIFICATION_GATEWAY, gateway_settings = dj_dynamic_settings.PUSH_NOTIFICATION_GATEWAYS.get(gateway_name); then klass = import_string(gateway_settings['klass']), gateway = klass(**gateway_settings['conf']). Used for notify_order_created, notify_order_status_changed, etc.

Key: PUSH_NOTIFICATION_GATEWAY Type: string Default: null (from Django PUSH_NOTIFICATION_GATEWAY)

Example

e.g. "euro_message" or "webinstats"; must exist as a key in PUSH_NOTIFICATION_GATEWAYS.

66. PushNotificationGateways

Dictionary mapping push notification gateway names to their configuration (typically klass and conf). The active gateway is selected by PUSH_NOTIFICATION_GATEWAY.

Where it is used

  • omnishop.users.service.PushNotificationServicegateway property looks up dj_dynamic_settings.PUSH_NOTIFICATION_GATEWAYS.get(gateway_name) and instantiates the backend from klass and conf.

Key: PUSH_NOTIFICATION_GATEWAYS Type: object Default: {} (from Django PUSH_NOTIFICATION_GATEWAYS)

Example

e.g. {"euro_message": {"klass": "...", "conf": {...}}, "webinstats": {...}}.

67. IgnoreDeletedItemsSignalConfig

List of model labels (e.g. app_label.ModelName) for which delete signals are ignored. When a model in this list is deleted, a DeletedItem record is not created in the datawarehouse (used to avoid syncing certain internal deletions).

Where it is used

  • omnishop.datawarehouse.receivers.item_delete_receiver — On delete: if sender._meta.label not in dynamic_settings.IGNORE_DELETED_ITEMS_SIGNAL then DeletedItem.objects.create(...); otherwise the deletion is ignored for the datawarehouse.

Key: IGNORE_DELETED_ITEMS_SIGNAL Type: array (list of model labels) Default: from Django IGNORE_DELETED_ITEMS_SIGNAL (e.g. includes AuditEvent, Session, DeletedItem)

Example

Add model labels (e.g. "sessions.Session") to avoid creating DeletedItem records for those models.

68. ShippingProvidersSetting

Configuration for shipping providers (carriers). Keys are provider identifiers (e.g. carrier enum values); each entry typically has conf with provider-specific options (e.g. tracking URL generation). Used when resolving tracking URLs and carrier behaviour.

Where it is used

  • omnicore_project.omnicore.orders.enums — In get_tracking_url(): provider = settings.SHIPPING_PROVIDERS.get(self.value); conf is used e.g. for generate_tracking_url on the extension provider.

  • omnishop.orders.settings.conf — Setting defined here; tests and shippings use it for provider config.

Key: SHIPPING_PROVIDERS Type: object Default: {} (from Django SHIPPING_PROVIDERS)

Example

Dict keyed by carrier identifier with conf (and optionally other keys) per provider.

69. EasyReturnPackageStrategy