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
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.
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_userruns for every user.A gateway with
match_userruns 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_useris 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_userfrom 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 clearingmatch_user.
Example — single region
Example — multi-region (Emarsys TR + FR)
With this setup:
A user whose
country_codeattribute isTRis synced toemarsys_tr.A user whose
country_codeattribute isFRis synced toemarsys_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 inSUBSCRIPTION_GATEWAYS.SUBSCRIPTION_ACTIVE— master switch. Whenfalse, 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:
category
Category pages
flat_page
Static pages
landing_page
Landing pages
product
Product pages
special_page
Special pages
Common fields for each content type:
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:
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 pagesinclude_stock_out_products: true→ Out-of-stock products remain in the sitemap, preserving SEO continuitySetting
limittoo low may leave thousands of URLs out of the sitemapExcessively high
changefreq+prioritywastes search engine crawl budgeti18n: truegenerates 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'sklassis imported and called withdefaultsmerged 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.forms —
SetPasswordForm.clean_password2()andAllAuthSetPasswordForm.clean_password2():auth_password_validators = dj_dynamic_settings.AUTH_PASSWORD_VALIDATORS; thenvalidate_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_TEMPLATEbefore callingsuper().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 undertemplates/emails/password_reset.html.Noneor 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 ofcontact_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'); iftois a list/tuple it is used as-is, if a string it is wrapped in a single-element tuple. Thattois used as the email To list (and optionally combined with the user email perCONTACT_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.conf —
AvailableCurrenciesvalidators ensurelen(currencies) == len(set(currencies))anddynamic_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_CURRENCIESfor 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.validators —
regex = dynamic_settings.USER_PHONE_REGEX; used to validate phone input.omnishop.users.service —
regex = 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_REGEXfor 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; ifactive_subscription_gatewaysis truthy, the method returns it; otherwise returns[subscription_gateway]. The returned names are then used to instantiate gateways viaget_gateway_settings(name)andget_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_GATEWAYis 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; whenACTIVE_SUBSCRIPTION_GATEWAYSis empty, the method returns[subscription_gateway]. That name is later passed toget_gateway_settings(gateway_name)which doesdj_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 theemarsysentry inSUBSCRIPTION_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_ACTIVEis 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_loginis set:if dynamic_settings.SUBSCRIPTION_ACTIVE and not created and instance.last_login:thensubscribe_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.list —
favourite_sku_is_active = dynamic_settings.FAVOURITE_SKU_IS_ACTIVE; thendistinct_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 byproduct_id(each variant counts separately).false— favourites are keyed bybase_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.validate —
user_collection_max_product = dynamic_settings.MAX_PRODUCT_PER_USER_COLLECTION;total_products = self.Meta.model.objects.filter(usercollection=attrs['usercollection']).count(); iftotal_products >= user_collection_max_productthenValidationErroris 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 vialambda 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 withUSER_PHONE_REGEXif 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.get —
anonymous_allowed = dynamic_settings.CHECKOUT_WITH_TOKEN_ALLOW_ANONYMOUS; ifnot user and (not anonymous_allowed or not getattr(request.session, "session_key", None))thenraise 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 withis_anonymous_allowedso 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_days —
return dynamic_settings.ORDERS_REFUNDABLE_DAYS.omnishop.orders.models.OrderItem.refundable_days —
return 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.index —
gift_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_box —
GiftBoxPreCondition.is_validandGiftBoxPage.is_gift_box_activeusegift_box_conf.get('is_active').GiftBoxPage.get_page_contextandprocess_pre_orderbuild aGiftBoxwithGiftBox(..., **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
skumust 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; iflanguage == site_language and not include_default_languagethenlanguage_code = none_language, elselanguage_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 whenFORCE_NOT_REDIRECT_FOR_I18Nis true, the block that callsget_localized_urlandredirect_responseis 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_activeisTrueonly whendynamic_settings.PROMOTION_GATEWAY_ACTIVEandself.promotion_gatewaysare both truthy;query()returns an empty list ifnot 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)returnsdj_dynamic_settings.SMS_GATEWAYS.get(sms_gateway);_get_gateway()uses that config to instantiate the backend viaimport_string(gateway_config.get('klass'))(**gateway_config.get('conf')). WhenSMS_GATEWAYis"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()readsdj_dynamic_settings.SMS_GATEWAY; when it is"console"it returnsSmsBackend; otherwise it looks up the config inSMS_GATEWAYSand instantiates the configured backend. Used bysend_sms,send_otp, andverify_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.CaptchaField —
site_key = property(lambda self: dj_dynamic_settings.RECAPTCHA_SITE_KEY); passed to the widget asdata-sitekey. BothRECAPTCHA_SITE_KEYandRECAPTCHA_SECRET_KEYmust be set or the field raisesImproperlyConfigured.
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.CaptchaField —
secret_keyproperty andvalidate(): POST to siteverify withsecretandresponse; 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
patchhandler:if not dynamic_settings.SELF_ANONYMIZATION_ENABLEDthenraise 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:thento += (email,). Reply-To is set separately byCONTACT_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:thenreply_to = (email,); otherwisereply_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; ifnot KVKK_GATEWAY or not verified_userthe method returns without calling the gateway; otherwise it callsupdate_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 indynamic_settings.AVAILABLE_CURRENCIES.AVAILABLE_CURRENCIESin turn validates that it containsDEFAULT_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.MobilDevService —
gatewayproperty builds the Mobildev gateway withMobilDev(**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_verificationis set toNoneso 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:
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:
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, thedefaults.statusfield 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:
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__: readsdynamic_settings.ADDRESS_SERIALIZER_FIELDS; selects the list bycountry.codeor falls back to"default"; for each entry adds or updates the field (with optional validators). Also respectsADDRESS_DISTRICT_REQUIREDfor 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.OmnitronApiClient —
get_data()readsgetattr(dynamic_settings, 'OMNITRON_API', {})forhost,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_count —
basket_max_item_count = dj_dynamic_settings.BASKET_MAX_ITEM_COUNT; ifbasket.get_total_quantity() > basket_max_item_countthenraise 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 withis_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 usesettings.NO_REPLY_EMAILorgetattr(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_EMAILfor 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_CONFIGURATIONthenconf.update(**kwargs)andsuper().__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 checksgetattr(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.PushNotificationService —
gatewayproperty:gateway_name = dj_dynamic_settings.PUSH_NOTIFICATION_GATEWAY,gateway_settings = dj_dynamic_settings.PUSH_NOTIFICATION_GATEWAYS.get(gateway_name); thenklass = import_string(gateway_settings['klass']),gateway = klass(**gateway_settings['conf']). Used fornotify_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.PushNotificationService —
gatewayproperty looks updj_dynamic_settings.PUSH_NOTIFICATION_GATEWAYS.get(gateway_name)and instantiates the backend fromklassandconf.
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_SIGNALthenDeletedItem.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);confis used e.g. forgenerate_tracking_urlon 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.

