Skip to content

feat(shopify): multi-tenant architecture + standardized account resolution#374

Open
engahmed1190 wants to merge 37 commits into
frappe:developfrom
BrainWise-DEV:develop
Open

feat(shopify): multi-tenant architecture + standardized account resolution#374
engahmed1190 wants to merge 37 commits into
frappe:developfrom
BrainWise-DEV:develop

Conversation

@engahmed1190
Copy link
Copy Markdown

Description:
This PR introduces major enhancements to the Shopify integration by adding multi-tenant support and standardizing account resolution logic across all modules.

Key Changes

  • Multi-Tenant Architecture

    • Introduced Shopify Account doctype for company-specific settings.
    • Enabled support for multiple Shopify stores with isolated configurations.
    • Updated product sync, order processing, inventory management, and fulfillment to be account-aware.
    • Webhook handling now routes events by shop domain.
    • Maintains backward compatibility with the legacy singleton configuration.
  • Standardized Account Resolution

    • Added resolve_account_context utility for consistent account resolution across modules.
    • Simplified temp_shopify_session decorator using the new account resolution flow.
  • UI & Developer Enhancements

    • Added account selection UI to the product import page.
    • Included comprehensive tests and documentation.

Impact

  • Enables multiple Shopify stores per ERPNext instance while keeping data and settings fully isolated.
  • Improves maintainability and reduces duplicated account resolution logic.
  • Backward compatible for existing single-store setups.

…ation

Add support for multiple Shopify stores with isolated configurations per company. Introduce Shopify Account doctype to replace legacy singleton settings. Update all core functions to be account-aware including product sync, order processing, inventory management, and webhook handling. Maintain backward compatibility with existing installations.

- Add Shopify Account doctype with company-specific settings
- Modify product, order, inventory, and fulfillment logic to support multi-tenancy
- Update webhook handling to route events by shop domain
- Add account selection UI to product import page
- Include comprehensive tests and documentation
Introduce resolve_account_context utility to handle account resolution consistently
Update all modules to use the new standardized account resolution
Simplify temp_shopify_session decorator with new account handling
@engahmed1190 engahmed1190 requested a review from ankush as a code owner August 13, 2025 17:08
@engahmed1190
Copy link
Copy Markdown
Author

@ankush can you review this PR to close #373

engahmed1190 and others added 15 commits August 13, 2025 18:11
- Update Shopify Account doctype with clearer authentication labels and add shop URL field
- Simplify old order sync logic by removing redundant checks
- Refactor location fetching to use direct session management
Move Shopify location fetching logic to a dedicated method with proper error handling and logging. This improves code organization and maintainability while providing better error tracking.
Replace reference_document parameter with account parameter in create_shopify_log calls
Update create_shopify_log to handle account context in message instead of reference_document
… inventory settings section for better organization
- Add required customer group field for customer sync
- Move fetch_shopify_locations to separate handler
- Clean up comments and redundant code
- Improve form query setup organization
…ments

- Add default_sales_tax_account and default_shipping_charges_account fields
- Set form intro description for better user guidance
- Make shop_domain read-only after save to prevent accidental changes
Pass account parameter through sync chain to ensure proper context
Update method name from import_all_products to queue_sync_all_products
Use centralized ecommerce_item.is_synced check for consistency
[CS-61 Fix the logic by adding setting.is_enabled() condition]
- Removed legacy singleton references and replaced with account-based settings for Shopify integration.
- Updated inventory synchronization logic to utilize user-specific Shopify accounts.
- Simplified functions for handling sales invoices and orders by eliminating account parameters where unnecessary.
- Enhanced product synchronization methods to operate without explicit account context.
- Improved error handling and logging for better traceability during synchronization processes.
- Streamlined JavaScript code for product import to remove account selection, focusing on a single account context.
- Added utility functions to fetch Shopify accounts based on user permissions and company associations.
- Add company support for multi-tenant.
- Complete integration functionalities including shopify hooks.
- improve logging
@tomemmerson
Copy link
Copy Markdown

Hi @engahmed1190,
Will this also work with the new app system in shopify (ClientID + Secret), given legacy custom apps will now be unavailable from January 2026?

Thanks
Tom

goondeal and others added 10 commits November 17, 2025 15:08
…companies

Cs 86 shopify support multi companies
…-with-prices

set shopify product price as a shopify_selling_rate in the newly created erpnext item
…-with-prices

Enhance retry functionality and Shopify account handling in Ecommerce Integration Log
fixing issue with create item to check first if company account is ex…
…ccount

Shopify requires OAuth 2.0 Client Credentials for new custom apps created
via the Dev Dashboard from Jan 1, 2026. Static Access Tokens still work
for older apps. This adds dual auth support per Shopify Account row,
keeping multi-tenancy intact.

- New oauth.py: token generation/refresh, 5-min expiry buffer, single
  retry on transient failure. Operates per Shopify Account doc.
- Shopify Account doctype: authentication_method (default Static Token),
  client_id, client_secret, hidden oauth_access_token + token_expires_at.
  password/shared_secret depend on Static Token method.
- Shopify Account controller: validates required fields per auth method,
  pre-generates token in before_save on credential change, branches
  webhook registration to use the right token.
- connection.py: _get_access_token branches per auth method;
  store_request_data picks client_secret for OAuth accounts and
  shared_secret for static-token accounts when verifying webhook HMAC.
- Migration patch: defaults existing rows to Static Token.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
engahmed1190 and others added 10 commits May 3, 2026 15:56
Add ONBOARDING.md walking implementers through bringing a new Shopify
store online: prerequisites, account setup with both Static Token and
OAuth 2.0 Client Credentials auth, per-account configuration, sync
setup, pricing flows (ERPNext shopify_selling_rate), day-2 operations,
troubleshooting, and a field reference. Includes a printable per-client
onboarding template.

Embedded UI screenshots captured live from a working install:
list empty-state, Static Token form, OAuth 2.0 form, and full layout.

Also gitignore .claude/settings.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…alidation issues

Three small fixes uncovered during end-to-end shake-out:

- product.py: item_group is a Document, not a dict — use attribute assignment
  instead of __setitem__ so product imports with a new product_type don't crash
  with TypeError on item creation.
- order.py: pass shopify_order.currency through to the Sales Order so ERPNext
  doesn't fall back to frappe.defaults.get_default('currency'), which mismatches
  the company Receivable account currency on multi-currency setups.
- shopify_account.json: drop mandatory_depends_on from the taxes child table.
  The integration falls back to default_sales_tax_account / default_shipping_charges_account
  for unmapped titles, so the table is genuinely optional. Marking it mandatory
  created an impossible UI state (empty row → row fields required → fill or delete →
  table empty required).

Doc updates:
- ONBOARDING.md §3.2: Shopify retired the legacy 'Develop apps' page; Dev Dashboard
  is the only path now. Documents the scope-change/reinstall flow and how to invalidate
  the cached OAuth token after a scope update.
- ONBOARDING.md §4.3: tax table is optional; emphasise the two default-account
  fields as the actually-required runtime setting.
- New docs/SESSION-NOTES-2026-05-04.md: session log capturing the bench-level
  fixes, demo data, tunnel/webhook setup, scope changes, and known sharp edges.

Misc: gitignore .playwright-mcp/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a dedicated Shopify workspace and a 6-step onboarding wizard so first-time
operators can stand up a store without leaving the desk.

Workspace layout:
- Quick Access shortcuts: Shopify Account, Shopify Sales Orders (filtered by
  shopify_order_id is set), Shopify Import Products, Integration Log Errors
  (filtered by status=Error).
- Three cards: Setup (Shopify Account, Ecommerce Item, Item, Customer),
  Documents (Sales Order, Sales Invoice, Delivery Note, Stock Reconciliation),
  Monitoring (Ecommerce Integration Log, Scheduled Job Type, Server Script).
- Embedded onboarding wizard at the top of the workspace.
- Roles: System Manager, Sales Manager.

Onboarding steps (6, in order):
1. Create Shopify Account — Create Entry action; auto-completes on first
   record.
2. Connect and Enable Shopify — Update Settings; validates enable_shopify=1.
3. Map Shopify Locations — Update Settings; auto-completes on action click
   (Frappe v15 doesn't support a delegated row-existence validator).
4. Configure Tax and Shipping Defaults — Update Settings; validates
   default_sales_tax_account is set.
5. Configure Sync Settings — Update Settings; validates sales_order_series is
   set.
6. Run Initial Product Import — Go to Page; opens shopify-import-products.

Wording uses "Nexus" rather than "ERPNext" per the platform branding on this
site.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The URL was a guess — pointed at frappe/ecommerce_integrations:develop, but
ONBOARDING.md only exists on the feat/shopify-oauth-multi-tenant branch and
the public mirror layout isn't settled. Better to ship without a broken link;
re-add once the doc has a stable canonical URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updated the refresh_oauth_token function to avoid reloading the setting document, preventing loss of unsaved changes. Introduced a persisted copy for secure retrieval of client secrets and ensured the caller's document remains in sync without forcing a reload. This enhances the reliability of the OAuth token management process.
Updated the temp_shopify_session function to check for a linked Shopify account. If no account is found, a user-friendly error message is thrown, prompting the user to configure their Shopify Account and User Permissions before proceeding with product imports.
- Updated the `syncAll` method to include asynchronous handling and job monitoring for product synchronization, improving user feedback during the sync process.
- Introduced `startJobFailureMonitor` and `stopJobFailureMonitor` methods to track job status and handle failures gracefully.
- Enhanced the `import_all_products` function to ensure a linked Shopify account is available before proceeding with imports, throwing a user-friendly error if not.
- Added logic to recover from accidental character-split account values in the `temp_shopify_session` function.
- Improved the `get_product_count` function to accept a Shopify account parameter for better context during product count retrieval.
…able_shopify-in-Shopify-Account

Pn 55 fix issue with save enable shopify in shopify account
fix: update custom_company attribute check in upload_erpnext_item fun…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants