@spree/docs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- package/package.json +27 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Spree CLI
|
|
3
|
+
sidebarTitle: Overview
|
|
4
|
+
description: Manage your Spree Commerce project from the command line.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The Spree CLI (`@spree/cli`) manages Docker-based Spree projects created with [create-spree-app](/developer/create-spree-app/quickstart).
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
The CLI is included automatically when you scaffold a project with `create-spree-app`. You can also install it globally:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @spree/cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Then run commands from your project directory:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
spree dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or use `npx` without installing:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @spree/cli dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
### `spree init`
|
|
32
|
+
|
|
33
|
+
First-run setup. Starts Docker services, seeds the database, generates an API key, and optionally loads sample data.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
spree init
|
|
37
|
+
spree init --no-sample-data # Skip sample data
|
|
38
|
+
spree init --no-open # Skip opening browser
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### `spree dev`
|
|
42
|
+
|
|
43
|
+
Start services and stream logs.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
spree dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `spree stop`
|
|
50
|
+
|
|
51
|
+
Stop all services.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
spree stop
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `spree update`
|
|
58
|
+
|
|
59
|
+
Pull the latest Spree Docker image and recreate containers. Migrations run automatically on startup.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
spree update
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `spree eject`
|
|
66
|
+
|
|
67
|
+
Switch from the prebuilt Docker image to building from your local `backend/` directory. This lets you customize the Rails app — add gems, override models, add migrations, etc.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
spree eject
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
After ejecting, the Docker image is built from `backend/Dockerfile`. Edit files in `backend/` and run `spree dev` to rebuild and restart with your changes.
|
|
74
|
+
|
|
75
|
+
See [Customizing the Backend](/developer/create-spree-app/quickstart#customizing-the-backend) for details on what you can customize.
|
|
76
|
+
|
|
77
|
+
### `spree logs`
|
|
78
|
+
|
|
79
|
+
Stream service logs.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
spree logs # Web service (default)
|
|
83
|
+
spree logs worker # Worker service
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `spree console`
|
|
87
|
+
|
|
88
|
+
Open a Rails console.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
spree console
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### `spree open`
|
|
95
|
+
|
|
96
|
+
Open the admin dashboard in the browser.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
spree open
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `spree seed`
|
|
103
|
+
|
|
104
|
+
Seed the database.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
spree seed
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### `spree sample-data`
|
|
111
|
+
|
|
112
|
+
Load sample products, categories, and images.
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
spree sample-data
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `spree user create`
|
|
119
|
+
|
|
120
|
+
Create an admin user. Prompts for email and password interactively, or pass them as flags:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
spree user create
|
|
124
|
+
spree user create --email admin@example.com --password secret123
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `spree api-key`
|
|
128
|
+
|
|
129
|
+
Manage Store and Admin API keys.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
spree api-key list # List all keys
|
|
133
|
+
spree api-key create # Interactive
|
|
134
|
+
spree api-key create --name "Storefront" --type publishable # Store API key
|
|
135
|
+
spree api-key create --name "Admin" --type secret # Admin API key
|
|
136
|
+
spree api-key revoke <id> # Revoke a key
|
|
137
|
+
```
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Creating an Extension
|
|
3
|
+
description: Learn how to create a Spree extension.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
[Spree Extensions](/developer/customization/extensions) are a way to add new functionality to your Spree store. They are a great way to extend the functionality of Spree and add new features. You can share them with Spree community on Github so anyone can use them, contribute back and share your improvements.
|
|
9
|
+
|
|
10
|
+
> **INFO:** This tutorial uses decorators for extending Spree models. For extensions that need to react to events (sync with external services, send notifications, etc.), consider using [Events subscribers](/developer/core-concepts/events) instead - they're easier to test and maintain. See [Customization Quickstart](/developer/customization/quickstart) for guidance on choosing the right approach.
|
|
11
|
+
|
|
12
|
+
## Getting Started
|
|
13
|
+
|
|
14
|
+
Let's build a simple extension. Suppose we want the ability to mark certain products as being on sale. We'd like to be able to set a sale price on a product and show products that are on sale on a separate products page. This is a great example of how an extension can be used to build on the solid Spree foundation.
|
|
15
|
+
|
|
16
|
+
Run the following command from a directory of your choice outside of our Spree application:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
spree extension simple_sales
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This creates a `spree_simple_sales` directory with several additional files and directories. After generating the extension make sure you change to its directory:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cd spree_simple_sales
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Adding a Sale Price to Variants
|
|
29
|
+
|
|
30
|
+
The first thing we need to do is create a migration that adds a sale_price column to [variants](/developer/core-concepts/products#variants).
|
|
31
|
+
|
|
32
|
+
We can do this with the following command:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bin/rails g migration add_sale_price_to_spree_variants sale_price:decimal
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Because we are dealing with prices, we need to now edit the generated migration to ensure the correct precision and scale. Edit the file `db/migrate/XXXXXXXXXXX_add_sale_price_to_spree_variants.rb` so that it contains the following:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
class AddSalePriceToSpreeVariants < ActiveRecord::Migration[7.1]
|
|
42
|
+
def change
|
|
43
|
+
add_column :spree_variants, :sale_price, :decimal, precision: 8, scale: 2
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Adding Our Extension to the Spree Application
|
|
49
|
+
|
|
50
|
+
Before we continue development of our extension, let's add it to the Spree application.
|
|
51
|
+
|
|
52
|
+
Within the `my_store` application directory, add the following line to the bottom of our `Gemfile`:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
gem 'spree_simple_sales', path: '../spree_simple_sales'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
You may have to adjust the path somewhat depending on where you created the extension. You want this to be the path relative to the location of the `my_store` application.
|
|
59
|
+
|
|
60
|
+
Once you have added the gem, it's time to bundle:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bundle install
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Finally, let's run the `spree_simple_sales` install generator to copy over the migration we just created answer **yes** if prompted to run migrations:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# context: Your Spree store's app root (i.e. Rails.root); not the extension's root path.
|
|
70
|
+
bin/rails g spree_simple_sales:install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Adding a Controller Action to HomeController
|
|
74
|
+
|
|
75
|
+
Now we need to extend `Spree::HomeController` and add an action that selects "on sale" products.
|
|
76
|
+
|
|
77
|
+
Note for the sake of this example that \`Spree::HomeController\` is only included in spree_storefront so you need to make it a dependency on your extensions \*.gemspec file.
|
|
78
|
+
|
|
79
|
+
Make sure you are in the `spree_simple_sales` root directory and run the following command to create the directory structure for our controller decorator:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mkdir -p app/controllers/spree_simple_sales
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Next, create a new file in the directory we just created called `home_controller_decorator.rb` and add the following content to it:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
module SpreeSimpleSales
|
|
89
|
+
module HomeControllerDecorator
|
|
90
|
+
def sale
|
|
91
|
+
@products = Spree::Product.joins(:variants_including_master).where.not(sale_price: nil).distinct
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
Spree::HomeController.prepend SpreeSimpleSales::HomeControllerDecorator
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This will select just the products that have a variant with a `sale_price` set.
|
|
100
|
+
|
|
101
|
+
We also need to add a route to this action in our `config/routes.rb` file. Let's do this now. Update the routes file to contain the following:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
Spree::Core::Engine.routes.draw do
|
|
105
|
+
get "/sale" => "home#sale"
|
|
106
|
+
end
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Viewing On Sale Products
|
|
110
|
+
|
|
111
|
+
### Setting the Sale Price for a Variant
|
|
112
|
+
|
|
113
|
+
Now that our variants have the attribute `sale_price` available to them, let's update the sample data so we have at least one product that is on sale in our application. We will need to do this in the rails console for the time being, as we have no admin interface to set sale prices for variants. So, in order to do this, first open up the rails console:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bin/rails c
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Now, follow the steps I take in selecting a product and updating its master variant to have a sale price. Note, you may not be editing the exact same product as I am, but this is not important. We just need one "on sale" product to display on the sales page.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
> product = Spree::Product.first
|
|
123
|
+
=> #<Spree::Product id: 107377505, name: "Spree Bag", description: "Lorem ipsum dolor sit amet, consectetuer adipiscing...", available_on: "2013-02-13 18:30:16", deleted_at: nil, permalink: "spree-bag", meta_description: nil, meta_keywords: nil, tax_category_id: 25484906, shipping_category_id: nil, count_on_hand: 10, created_at: "2013-02-13 18:30:16", updated_at: "2013-02-13 18:30:16", on_demand: false>
|
|
124
|
+
|
|
125
|
+
> variant = product.master
|
|
126
|
+
=> #<Spree::Variant id: 833839126, sku: "SPR-00012", weight: nil, height: nil, width: nil, depth: nil, deleted_at: nil, is_master: true, product_id: 107377505, count_on_hand: 10, cost_price: #<BigDecimal:7f8dda5eebf0,'0.21E2',9(36)>, position: nil, lock_version: 0, on_demand: false, cost_currency: nil, sale_price: nil>
|
|
127
|
+
|
|
128
|
+
> variant.sale_price = 8.00
|
|
129
|
+
=> 8.0
|
|
130
|
+
|
|
131
|
+
> variant.save
|
|
132
|
+
=> true
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Decorating Variants
|
|
136
|
+
|
|
137
|
+
Let's fix our extension so that it uses the `sale_price` when it is present.
|
|
138
|
+
|
|
139
|
+
Next, create the file `app/models/spree_simple_sales/variant_decorator.rb` and add the following content to it:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
module SpreeSimpleSales
|
|
143
|
+
module VariantDecorator
|
|
144
|
+
def price_in(currency)
|
|
145
|
+
return super unless sale_price.present?
|
|
146
|
+
Spree::Price.new(variant_id: self.id, amount: self.sale_price, currency: currency)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
Spree::Variant.prepend SpreeSimpleSales::VariantDecorator
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
If there is a `sale_price` present on the product's master variant, we return that price. Otherwise, we call the original implementation of `price_in` using `return super`.
|
|
155
|
+
|
|
156
|
+
## Testing Our Decorator
|
|
157
|
+
|
|
158
|
+
It's always a good idea to test your code. We should be extra careful to write tests for our Variant decorator since we are modifying core Spree functionality. Let's write a couple of simple unit tests for `variant_decorator.rb`
|
|
159
|
+
|
|
160
|
+
### Generating the Test App
|
|
161
|
+
|
|
162
|
+
An extension is not a full Rails application, so we need something to test our extension against. By running the Spree `test_app` rake task, we can generate a barebones Spree application within our `spec` directory to run our tests against.
|
|
163
|
+
|
|
164
|
+
We can do this with the following command from the root directory of our extension:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
bundle exec rake test_app
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
After this command completes, you should be able to run `rspec` and see the following output:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
No examples found.
|
|
174
|
+
|
|
175
|
+
Finished in 0.00005 seconds
|
|
176
|
+
0 examples, 0 failures
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Great! We're ready to start adding some tests. Let's replicate the extension's directory structure in our spec directory by running the following command
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
mkdir -p spec/models/spree
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Now, let's create a new file in this directory called `variant_decorator_spec.rb` and add the following tests to it:
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
require 'spec_helper'
|
|
189
|
+
|
|
190
|
+
describe Spree::Variant do
|
|
191
|
+
describe "#price_in" do
|
|
192
|
+
it "returns the sale price if it is present" do
|
|
193
|
+
variant = create(:variant, sale_price: 8.00)
|
|
194
|
+
expected = Spree::Price.new(variant_id: variant.id, currency: "USD", amount: variant.sale_price)
|
|
195
|
+
|
|
196
|
+
result = variant.price_in("USD")
|
|
197
|
+
|
|
198
|
+
expect(result.variant_id).to eq(expected.variant_id)
|
|
199
|
+
expect(result.amount.to_f).to eq(expected.amount.to_f)
|
|
200
|
+
expect(result.currency).to eq(expected.currency)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
it "returns the normal price if it is not on sale" do
|
|
204
|
+
variant = create(:variant, price: 15.00)
|
|
205
|
+
expected = Spree::Price.new(variant_id: variant.id, currency: "USD", amount: variant.price)
|
|
206
|
+
|
|
207
|
+
result = variant.price_in("USD")
|
|
208
|
+
|
|
209
|
+
expect(result.variant_id).to eq(expected.variant_id)
|
|
210
|
+
expect(result.amount.to_f).to eq(expected.amount.to_f)
|
|
211
|
+
expect(result.currency).to eq(expected.currency)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
These specs test that the `price_in` method we overrode in our `VariantDecorator` returns the correct price both when the sale price is present and when it is not.
|
|
218
|
+
|
|
219
|
+
## Summary
|
|
220
|
+
|
|
221
|
+
In this tutorial, you learned how to both install extensions and create your own. A lot of core Spree development concepts were covered and you gained exposure to some of the Spree internals.
|
|
222
|
+
|
|
223
|
+
## Alternative Approaches
|
|
224
|
+
|
|
225
|
+
While this tutorial uses decorators to extend Spree's core behavior, modern Spree provides additional patterns that may be more appropriate depending on your use case:
|
|
226
|
+
|
|
227
|
+
| Use Case | Recommended Approach |
|
|
228
|
+
|----------|---------------------|
|
|
229
|
+
| Structural changes (associations, validations) | Decorators (as shown in this tutorial) |
|
|
230
|
+
| React to model changes | [Events subscribers](/developer/core-concepts/events) |
|
|
231
|
+
| External service integration | [Webhooks](/developer/core-concepts/webhooks) |
|
|
232
|
+
| Replace core services | [Dependencies injection](/developer/customization/dependencies) |
|
|
233
|
+
| Add admin UI elements | [Admin Partials](/developer/admin/extending-ui) |
|
|
234
|
+
| Add admin menu items | [Admin Navigation](/developer/admin/navigation) |
|
|
235
|
+
|
|
236
|
+
For example, if your extension needs to sync data with an external service when products are updated, use an Events subscriber instead of a decorator callback:
|
|
237
|
+
|
|
238
|
+
```ruby app/subscribers/my_extension/product_sync_subscriber.rb
|
|
239
|
+
module MyExtension
|
|
240
|
+
class ProductSyncSubscriber < Spree::Subscriber
|
|
241
|
+
subscribes_to 'product.updated'
|
|
242
|
+
|
|
243
|
+
def handle(event)
|
|
244
|
+
product = Spree::Product.find_by(id: event.payload['id'])
|
|
245
|
+
return unless product
|
|
246
|
+
|
|
247
|
+
ExternalService.sync(product)
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Related Documentation
|
|
254
|
+
|
|
255
|
+
- [Events](/developer/core-concepts/events) - Subscribe to Spree events
|
|
256
|
+
- [Webhooks](/developer/core-concepts/webhooks) - HTTP callbacks for external integrations
|
|
257
|
+
- [Dependencies](/developer/customization/dependencies) - Replace core services
|
|
258
|
+
- [Customization Quickstart](/developer/customization/quickstart) - Choose the right approach
|