@spree/docs 0.1.292 → 0.1.294
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/dist/api-reference/store.yaml +529 -44
- package/dist/api-reference/webhooks-events.md +20 -5
- package/dist/developer/core-concepts/events.md +11 -1
- package/dist/developer/core-concepts/webhooks.md +59 -15
- package/dist/developer/customization/model-preferences.md +26 -3
- package/dist/developer/deployment/environment_variables.md +1 -1
- package/dist/developer/how-to/custom-payment-method.md +7 -1
- package/dist/developer/upgrades/5.6-to-6.0.md +56 -2
- package/package.json +1 -1
|
@@ -13241,6 +13241,141 @@ components:
|
|
|
13241
13241
|
- amount
|
|
13242
13242
|
- display_amount
|
|
13243
13243
|
x-typelizer: true
|
|
13244
|
+
ExchangeLineItem:
|
|
13245
|
+
type: object
|
|
13246
|
+
properties:
|
|
13247
|
+
id:
|
|
13248
|
+
type: string
|
|
13249
|
+
quantity:
|
|
13250
|
+
type: number
|
|
13251
|
+
received_quantity:
|
|
13252
|
+
type: number
|
|
13253
|
+
resellable:
|
|
13254
|
+
type: boolean
|
|
13255
|
+
original_price:
|
|
13256
|
+
type: string
|
|
13257
|
+
new_variant_price:
|
|
13258
|
+
type: string
|
|
13259
|
+
price_difference:
|
|
13260
|
+
type: string
|
|
13261
|
+
original_variant_id:
|
|
13262
|
+
type: string
|
|
13263
|
+
nullable: true
|
|
13264
|
+
new_variant_id:
|
|
13265
|
+
type: string
|
|
13266
|
+
nullable: true
|
|
13267
|
+
line_item_id:
|
|
13268
|
+
type: string
|
|
13269
|
+
nullable: true
|
|
13270
|
+
fulfillment_item_id:
|
|
13271
|
+
type: string
|
|
13272
|
+
nullable: true
|
|
13273
|
+
original_variant:
|
|
13274
|
+
"$ref": "#/components/schemas/Variant"
|
|
13275
|
+
new_variant:
|
|
13276
|
+
"$ref": "#/components/schemas/Variant"
|
|
13277
|
+
required:
|
|
13278
|
+
- id
|
|
13279
|
+
- quantity
|
|
13280
|
+
- received_quantity
|
|
13281
|
+
- resellable
|
|
13282
|
+
- original_price
|
|
13283
|
+
- new_variant_price
|
|
13284
|
+
- price_difference
|
|
13285
|
+
- original_variant_id
|
|
13286
|
+
- new_variant_id
|
|
13287
|
+
- line_item_id
|
|
13288
|
+
- fulfillment_item_id
|
|
13289
|
+
x-typelizer: true
|
|
13290
|
+
Exchange:
|
|
13291
|
+
type: object
|
|
13292
|
+
properties:
|
|
13293
|
+
id:
|
|
13294
|
+
type: string
|
|
13295
|
+
number:
|
|
13296
|
+
type: string
|
|
13297
|
+
status:
|
|
13298
|
+
anyOf:
|
|
13299
|
+
- type: string
|
|
13300
|
+
enum:
|
|
13301
|
+
- requested
|
|
13302
|
+
- approved
|
|
13303
|
+
- received
|
|
13304
|
+
- fulfilled
|
|
13305
|
+
- canceled
|
|
13306
|
+
- type: string
|
|
13307
|
+
description: The values listed are the built-in ones; extensions may add
|
|
13308
|
+
more.
|
|
13309
|
+
order_id:
|
|
13310
|
+
type: string
|
|
13311
|
+
nullable: true
|
|
13312
|
+
reason_id:
|
|
13313
|
+
type: string
|
|
13314
|
+
nullable: true
|
|
13315
|
+
price_difference:
|
|
13316
|
+
type: string
|
|
13317
|
+
display_price_difference:
|
|
13318
|
+
type: string
|
|
13319
|
+
approved_at:
|
|
13320
|
+
type: string
|
|
13321
|
+
nullable: true
|
|
13322
|
+
received_at:
|
|
13323
|
+
type: string
|
|
13324
|
+
nullable: true
|
|
13325
|
+
fulfilled_at:
|
|
13326
|
+
type: string
|
|
13327
|
+
nullable: true
|
|
13328
|
+
canceled_at:
|
|
13329
|
+
type: string
|
|
13330
|
+
nullable: true
|
|
13331
|
+
reason:
|
|
13332
|
+
"$ref": "#/components/schemas/ReturnReason"
|
|
13333
|
+
exchange_line_items:
|
|
13334
|
+
type: array
|
|
13335
|
+
items:
|
|
13336
|
+
"$ref": "#/components/schemas/ExchangeLineItem"
|
|
13337
|
+
required:
|
|
13338
|
+
- id
|
|
13339
|
+
- number
|
|
13340
|
+
- status
|
|
13341
|
+
- order_id
|
|
13342
|
+
- reason_id
|
|
13343
|
+
- price_difference
|
|
13344
|
+
- display_price_difference
|
|
13345
|
+
- approved_at
|
|
13346
|
+
- received_at
|
|
13347
|
+
- fulfilled_at
|
|
13348
|
+
- canceled_at
|
|
13349
|
+
x-typelizer: true
|
|
13350
|
+
Export:
|
|
13351
|
+
type: object
|
|
13352
|
+
properties:
|
|
13353
|
+
id:
|
|
13354
|
+
type: string
|
|
13355
|
+
number:
|
|
13356
|
+
type: string
|
|
13357
|
+
format:
|
|
13358
|
+
type: string
|
|
13359
|
+
nullable: true
|
|
13360
|
+
created_at:
|
|
13361
|
+
type: string
|
|
13362
|
+
updated_at:
|
|
13363
|
+
type: string
|
|
13364
|
+
type:
|
|
13365
|
+
type: string
|
|
13366
|
+
nullable: true
|
|
13367
|
+
user_id:
|
|
13368
|
+
type: string
|
|
13369
|
+
nullable: true
|
|
13370
|
+
required:
|
|
13371
|
+
- id
|
|
13372
|
+
- number
|
|
13373
|
+
- format
|
|
13374
|
+
- created_at
|
|
13375
|
+
- updated_at
|
|
13376
|
+
- type
|
|
13377
|
+
- user_id
|
|
13378
|
+
x-typelizer: true
|
|
13244
13379
|
Fee:
|
|
13245
13380
|
type: object
|
|
13246
13381
|
properties:
|
|
@@ -13545,6 +13680,111 @@ components:
|
|
|
13545
13680
|
- expired
|
|
13546
13681
|
- active
|
|
13547
13682
|
x-typelizer: true
|
|
13683
|
+
ImportRow:
|
|
13684
|
+
type: object
|
|
13685
|
+
properties:
|
|
13686
|
+
id:
|
|
13687
|
+
type: string
|
|
13688
|
+
row_number:
|
|
13689
|
+
type: number
|
|
13690
|
+
status:
|
|
13691
|
+
anyOf:
|
|
13692
|
+
- type: string
|
|
13693
|
+
enum:
|
|
13694
|
+
- pending
|
|
13695
|
+
- processing
|
|
13696
|
+
- completed
|
|
13697
|
+
- failed
|
|
13698
|
+
- type: string
|
|
13699
|
+
description: The values listed are the built-in ones; extensions may add
|
|
13700
|
+
more.
|
|
13701
|
+
validation_errors:
|
|
13702
|
+
type: string
|
|
13703
|
+
nullable: true
|
|
13704
|
+
created_at:
|
|
13705
|
+
type: string
|
|
13706
|
+
updated_at:
|
|
13707
|
+
type: string
|
|
13708
|
+
import_id:
|
|
13709
|
+
type: string
|
|
13710
|
+
nullable: true
|
|
13711
|
+
item_type:
|
|
13712
|
+
type: string
|
|
13713
|
+
nullable: true
|
|
13714
|
+
item_id:
|
|
13715
|
+
type: string
|
|
13716
|
+
nullable: true
|
|
13717
|
+
required:
|
|
13718
|
+
- id
|
|
13719
|
+
- row_number
|
|
13720
|
+
- status
|
|
13721
|
+
- validation_errors
|
|
13722
|
+
- created_at
|
|
13723
|
+
- updated_at
|
|
13724
|
+
- import_id
|
|
13725
|
+
- item_type
|
|
13726
|
+
- item_id
|
|
13727
|
+
x-typelizer: true
|
|
13728
|
+
Import:
|
|
13729
|
+
type: object
|
|
13730
|
+
properties:
|
|
13731
|
+
id:
|
|
13732
|
+
type: string
|
|
13733
|
+
number:
|
|
13734
|
+
type: string
|
|
13735
|
+
rows_count:
|
|
13736
|
+
type: number
|
|
13737
|
+
created_at:
|
|
13738
|
+
type: string
|
|
13739
|
+
updated_at:
|
|
13740
|
+
type: string
|
|
13741
|
+
type:
|
|
13742
|
+
type: string
|
|
13743
|
+
nullable: true
|
|
13744
|
+
description: 'Import type. Built-in: products, product_translations, customers,
|
|
13745
|
+
price_list_prices. Extensions may register more.'
|
|
13746
|
+
status:
|
|
13747
|
+
anyOf:
|
|
13748
|
+
- type: string
|
|
13749
|
+
enum:
|
|
13750
|
+
- pending
|
|
13751
|
+
- mapping
|
|
13752
|
+
- completed_mapping
|
|
13753
|
+
- processing
|
|
13754
|
+
- completed
|
|
13755
|
+
- failed
|
|
13756
|
+
- type: string
|
|
13757
|
+
description: The values listed are the built-in ones; extensions may add
|
|
13758
|
+
more.
|
|
13759
|
+
store_id:
|
|
13760
|
+
type: string
|
|
13761
|
+
nullable: true
|
|
13762
|
+
seller_id:
|
|
13763
|
+
type: string
|
|
13764
|
+
nullable: true
|
|
13765
|
+
owner_type:
|
|
13766
|
+
type: string
|
|
13767
|
+
nullable: true
|
|
13768
|
+
owner_id:
|
|
13769
|
+
type: string
|
|
13770
|
+
nullable: true
|
|
13771
|
+
user_id:
|
|
13772
|
+
type: string
|
|
13773
|
+
nullable: true
|
|
13774
|
+
required:
|
|
13775
|
+
- id
|
|
13776
|
+
- number
|
|
13777
|
+
- rows_count
|
|
13778
|
+
- created_at
|
|
13779
|
+
- updated_at
|
|
13780
|
+
- type
|
|
13781
|
+
- status
|
|
13782
|
+
- store_id
|
|
13783
|
+
- seller_id
|
|
13784
|
+
- owner_type
|
|
13785
|
+
- owner_id
|
|
13786
|
+
- user_id
|
|
13787
|
+
x-typelizer: true
|
|
13548
13788
|
Invitation:
|
|
13549
13789
|
type: object
|
|
13550
13790
|
properties:
|
|
@@ -13917,6 +14157,32 @@ components:
|
|
|
13917
14157
|
- xlarge_url
|
|
13918
14158
|
- og_image_url
|
|
13919
14159
|
x-typelizer: true
|
|
14160
|
+
NewsletterSubscriberRequestEvent:
|
|
14161
|
+
type: object
|
|
14162
|
+
properties:
|
|
14163
|
+
id:
|
|
14164
|
+
type: string
|
|
14165
|
+
email:
|
|
14166
|
+
type: string
|
|
14167
|
+
verification_token:
|
|
14168
|
+
type: string
|
|
14169
|
+
unsubscribe_token:
|
|
14170
|
+
type: string
|
|
14171
|
+
store_id:
|
|
14172
|
+
type: string
|
|
14173
|
+
nullable: true
|
|
14174
|
+
customer_id:
|
|
14175
|
+
type: string
|
|
14176
|
+
nullable: true
|
|
14177
|
+
redirect_url:
|
|
14178
|
+
type: string
|
|
14179
|
+
required:
|
|
14180
|
+
- id
|
|
14181
|
+
- email
|
|
14182
|
+
- unsubscribe_token
|
|
14183
|
+
- store_id
|
|
14184
|
+
- customer_id
|
|
14185
|
+
x-typelizer: true
|
|
13920
14186
|
NewsletterSubscriber:
|
|
13921
14187
|
type: object
|
|
13922
14188
|
properties:
|
|
@@ -14329,6 +14595,26 @@ components:
|
|
|
14329
14595
|
- gift_card
|
|
14330
14596
|
- market
|
|
14331
14597
|
x-typelizer: true
|
|
14598
|
+
PasswordResetRequestedEvent:
|
|
14599
|
+
type: object
|
|
14600
|
+
properties:
|
|
14601
|
+
id:
|
|
14602
|
+
type: string
|
|
14603
|
+
email:
|
|
14604
|
+
type: string
|
|
14605
|
+
reset_token:
|
|
14606
|
+
type: string
|
|
14607
|
+
store_id:
|
|
14608
|
+
type: string
|
|
14609
|
+
nullable: true
|
|
14610
|
+
redirect_url:
|
|
14611
|
+
type: string
|
|
14612
|
+
required:
|
|
14613
|
+
- id
|
|
14614
|
+
- email
|
|
14615
|
+
- reset_token
|
|
14616
|
+
- store_id
|
|
14617
|
+
x-typelizer: true
|
|
14332
14618
|
PaymentMethod:
|
|
14333
14619
|
type: object
|
|
14334
14620
|
properties:
|
|
@@ -14955,6 +15241,40 @@ components:
|
|
|
14955
15241
|
- original_price
|
|
14956
15242
|
- seller_id
|
|
14957
15243
|
x-typelizer: true
|
|
15244
|
+
ProductSubmission:
|
|
15245
|
+
type: object
|
|
15246
|
+
properties:
|
|
15247
|
+
id:
|
|
15248
|
+
type: string
|
|
15249
|
+
status:
|
|
15250
|
+
anyOf:
|
|
15251
|
+
- type: string
|
|
15252
|
+
enum:
|
|
15253
|
+
- pending
|
|
15254
|
+
- approved
|
|
15255
|
+
- rejected
|
|
15256
|
+
- withdrawn
|
|
15257
|
+
- type: string
|
|
15258
|
+
description: The values listed are the built-in ones; extensions may add
|
|
15259
|
+
more.
|
|
15260
|
+
review_note:
|
|
15261
|
+
type: string
|
|
15262
|
+
nullable: true
|
|
15263
|
+
reviewed_at:
|
|
15264
|
+
type: string
|
|
15265
|
+
nullable: true
|
|
15266
|
+
created_at:
|
|
15267
|
+
type: string
|
|
15268
|
+
product_id:
|
|
15269
|
+
type: string
|
|
15270
|
+
required:
|
|
15271
|
+
- id
|
|
15272
|
+
- status
|
|
15273
|
+
- review_note
|
|
15274
|
+
- reviewed_at
|
|
15275
|
+
- created_at
|
|
15276
|
+
- product_id
|
|
15277
|
+
x-typelizer: true
|
|
14958
15278
|
ProductType:
|
|
14959
15279
|
type: object
|
|
14960
15280
|
properties:
|
|
@@ -14985,6 +15305,46 @@ components:
|
|
|
14985
15305
|
- description
|
|
14986
15306
|
- code
|
|
14987
15307
|
x-typelizer: true
|
|
15308
|
+
PurchaseOrderEvent:
|
|
15309
|
+
type: object
|
|
15310
|
+
properties:
|
|
15311
|
+
id:
|
|
15312
|
+
type: string
|
|
15313
|
+
number:
|
|
15314
|
+
type: string
|
|
15315
|
+
status:
|
|
15316
|
+
type: string
|
|
15317
|
+
ordered_at:
|
|
15318
|
+
type: string
|
|
15319
|
+
nullable: true
|
|
15320
|
+
received_at:
|
|
15321
|
+
type: string
|
|
15322
|
+
nullable: true
|
|
15323
|
+
closed_short_at:
|
|
15324
|
+
type: string
|
|
15325
|
+
nullable: true
|
|
15326
|
+
created_at:
|
|
15327
|
+
type: string
|
|
15328
|
+
updated_at:
|
|
15329
|
+
type: string
|
|
15330
|
+
supplier_id:
|
|
15331
|
+
type: string
|
|
15332
|
+
nullable: true
|
|
15333
|
+
destination_location_id:
|
|
15334
|
+
type: string
|
|
15335
|
+
nullable: true
|
|
15336
|
+
required:
|
|
15337
|
+
- id
|
|
15338
|
+
- number
|
|
15339
|
+
- status
|
|
15340
|
+
- ordered_at
|
|
15341
|
+
- received_at
|
|
15342
|
+
- closed_short_at
|
|
15343
|
+
- created_at
|
|
15344
|
+
- updated_at
|
|
15345
|
+
- supplier_id
|
|
15346
|
+
- destination_location_id
|
|
15347
|
+
x-typelizer: true
|
|
14988
15348
|
Refund:
|
|
14989
15349
|
type: object
|
|
14990
15350
|
properties:
|
|
@@ -15152,6 +15512,37 @@ components:
|
|
|
15152
15512
|
- refunded_at
|
|
15153
15513
|
- canceled_at
|
|
15154
15514
|
x-typelizer: true
|
|
15515
|
+
SavedReportEvent:
|
|
15516
|
+
type: object
|
|
15517
|
+
properties:
|
|
15518
|
+
id:
|
|
15519
|
+
type: string
|
|
15520
|
+
name:
|
|
15521
|
+
type: string
|
|
15522
|
+
description:
|
|
15523
|
+
type: string
|
|
15524
|
+
nullable: true
|
|
15525
|
+
query:
|
|
15526
|
+
type: object
|
|
15527
|
+
seeded:
|
|
15528
|
+
type: boolean
|
|
15529
|
+
created_at:
|
|
15530
|
+
type: string
|
|
15531
|
+
updated_at:
|
|
15532
|
+
type: string
|
|
15533
|
+
user_id:
|
|
15534
|
+
type: string
|
|
15535
|
+
nullable: true
|
|
15536
|
+
required:
|
|
15537
|
+
- id
|
|
15538
|
+
- name
|
|
15539
|
+
- description
|
|
15540
|
+
- query
|
|
15541
|
+
- seeded
|
|
15542
|
+
- created_at
|
|
15543
|
+
- updated_at
|
|
15544
|
+
- user_id
|
|
15545
|
+
x-typelizer: true
|
|
15155
15546
|
Seller:
|
|
15156
15547
|
type: object
|
|
15157
15548
|
properties:
|
|
@@ -15193,11 +15584,6 @@ components:
|
|
|
15193
15584
|
properties:
|
|
15194
15585
|
id:
|
|
15195
15586
|
type: string
|
|
15196
|
-
source:
|
|
15197
|
-
type: string
|
|
15198
|
-
enum:
|
|
15199
|
-
- purchased
|
|
15200
|
-
- uploaded
|
|
15201
15587
|
status:
|
|
15202
15588
|
anyOf:
|
|
15203
15589
|
- type: string
|
|
@@ -15211,26 +15597,12 @@ components:
|
|
|
15211
15597
|
carrier:
|
|
15212
15598
|
type: string
|
|
15213
15599
|
nullable: true
|
|
15214
|
-
carrier_name:
|
|
15215
|
-
type: string
|
|
15216
|
-
nullable: true
|
|
15217
15600
|
service:
|
|
15218
15601
|
type: string
|
|
15219
15602
|
nullable: true
|
|
15220
15603
|
tracking_number:
|
|
15221
15604
|
type: string
|
|
15222
15605
|
nullable: true
|
|
15223
|
-
currency:
|
|
15224
|
-
type: string
|
|
15225
|
-
nullable: true
|
|
15226
|
-
format:
|
|
15227
|
-
type: string
|
|
15228
|
-
nullable: true
|
|
15229
|
-
external_id:
|
|
15230
|
-
type: string
|
|
15231
|
-
nullable: true
|
|
15232
|
-
metadata:
|
|
15233
|
-
type: object
|
|
15234
15606
|
refunded_at:
|
|
15235
15607
|
type: string
|
|
15236
15608
|
nullable: true
|
|
@@ -15243,42 +15615,19 @@ components:
|
|
|
15243
15615
|
owner_type:
|
|
15244
15616
|
type: string
|
|
15245
15617
|
enum:
|
|
15246
|
-
-
|
|
15247
|
-
-
|
|
15248
|
-
cost:
|
|
15249
|
-
type: string
|
|
15250
|
-
display_cost:
|
|
15251
|
-
type: string
|
|
15252
|
-
integration_id:
|
|
15253
|
-
type: string
|
|
15254
|
-
nullable: true
|
|
15255
|
-
file_pending:
|
|
15256
|
-
type: boolean
|
|
15257
|
-
download_url:
|
|
15258
|
-
type: string
|
|
15259
|
-
nullable: true
|
|
15618
|
+
- fulfillment
|
|
15619
|
+
- return
|
|
15260
15620
|
required:
|
|
15261
15621
|
- id
|
|
15262
|
-
- source
|
|
15263
15622
|
- status
|
|
15264
15623
|
- carrier
|
|
15265
|
-
- carrier_name
|
|
15266
15624
|
- service
|
|
15267
15625
|
- tracking_number
|
|
15268
|
-
- currency
|
|
15269
|
-
- format
|
|
15270
|
-
- external_id
|
|
15271
|
-
- metadata
|
|
15272
15626
|
- refunded_at
|
|
15273
15627
|
- created_at
|
|
15274
15628
|
- updated_at
|
|
15275
15629
|
- owner_id
|
|
15276
15630
|
- owner_type
|
|
15277
|
-
- cost
|
|
15278
|
-
- display_cost
|
|
15279
|
-
- integration_id
|
|
15280
|
-
- file_pending
|
|
15281
|
-
- download_url
|
|
15282
15631
|
x-typelizer: true
|
|
15283
15632
|
State:
|
|
15284
15633
|
type: object
|
|
@@ -15291,6 +15640,28 @@ components:
|
|
|
15291
15640
|
- abbr
|
|
15292
15641
|
- name
|
|
15293
15642
|
x-typelizer: true
|
|
15643
|
+
StockLevel:
|
|
15644
|
+
type: object
|
|
15645
|
+
properties:
|
|
15646
|
+
id:
|
|
15647
|
+
type: string
|
|
15648
|
+
count_on_hand:
|
|
15649
|
+
type: number
|
|
15650
|
+
backorderable:
|
|
15651
|
+
type: boolean
|
|
15652
|
+
stock_location_id:
|
|
15653
|
+
type: string
|
|
15654
|
+
nullable: true
|
|
15655
|
+
variant_id:
|
|
15656
|
+
type: string
|
|
15657
|
+
nullable: true
|
|
15658
|
+
required:
|
|
15659
|
+
- id
|
|
15660
|
+
- count_on_hand
|
|
15661
|
+
- backorderable
|
|
15662
|
+
- stock_location_id
|
|
15663
|
+
- variant_id
|
|
15664
|
+
x-typelizer: true
|
|
15294
15665
|
StockLocation:
|
|
15295
15666
|
type: object
|
|
15296
15667
|
properties:
|
|
@@ -15338,6 +15709,76 @@ components:
|
|
|
15338
15709
|
- pickup_ready_in_minutes
|
|
15339
15710
|
- pickup_instructions
|
|
15340
15711
|
x-typelizer: true
|
|
15712
|
+
StockMovement:
|
|
15713
|
+
type: object
|
|
15714
|
+
properties:
|
|
15715
|
+
id:
|
|
15716
|
+
type: string
|
|
15717
|
+
quantity:
|
|
15718
|
+
type: number
|
|
15719
|
+
kind:
|
|
15720
|
+
type: string
|
|
15721
|
+
nullable: true
|
|
15722
|
+
enum:
|
|
15723
|
+
- received
|
|
15724
|
+
- allocated
|
|
15725
|
+
- shipped
|
|
15726
|
+
- released
|
|
15727
|
+
- adjusted
|
|
15728
|
+
reason:
|
|
15729
|
+
type: string
|
|
15730
|
+
nullable: true
|
|
15731
|
+
created_at:
|
|
15732
|
+
type: string
|
|
15733
|
+
updated_at:
|
|
15734
|
+
type: string
|
|
15735
|
+
stock_level_id:
|
|
15736
|
+
type: string
|
|
15737
|
+
nullable: true
|
|
15738
|
+
required:
|
|
15739
|
+
- id
|
|
15740
|
+
- quantity
|
|
15741
|
+
- kind
|
|
15742
|
+
- reason
|
|
15743
|
+
- created_at
|
|
15744
|
+
- updated_at
|
|
15745
|
+
- stock_level_id
|
|
15746
|
+
x-typelizer: true
|
|
15747
|
+
StockReceiptEvent:
|
|
15748
|
+
type: object
|
|
15749
|
+
properties:
|
|
15750
|
+
id:
|
|
15751
|
+
type: string
|
|
15752
|
+
number:
|
|
15753
|
+
type: string
|
|
15754
|
+
quantity_accepted_total:
|
|
15755
|
+
type: number
|
|
15756
|
+
quantity_rejected_total:
|
|
15757
|
+
type: number
|
|
15758
|
+
received_at:
|
|
15759
|
+
type: string
|
|
15760
|
+
created_at:
|
|
15761
|
+
type: string
|
|
15762
|
+
updated_at:
|
|
15763
|
+
type: string
|
|
15764
|
+
receivable_type:
|
|
15765
|
+
type: string
|
|
15766
|
+
enum:
|
|
15767
|
+
- purchase_order
|
|
15768
|
+
- stock_transfer
|
|
15769
|
+
receivable_id:
|
|
15770
|
+
type: string
|
|
15771
|
+
required:
|
|
15772
|
+
- id
|
|
15773
|
+
- number
|
|
15774
|
+
- quantity_accepted_total
|
|
15775
|
+
- quantity_rejected_total
|
|
15776
|
+
- received_at
|
|
15777
|
+
- created_at
|
|
15778
|
+
- updated_at
|
|
15779
|
+
- receivable_type
|
|
15780
|
+
- receivable_id
|
|
15781
|
+
x-typelizer: true
|
|
15341
15782
|
StockReservation:
|
|
15342
15783
|
type: object
|
|
15343
15784
|
properties:
|
|
@@ -15346,6 +15787,33 @@ components:
|
|
|
15346
15787
|
required:
|
|
15347
15788
|
- id
|
|
15348
15789
|
x-typelizer: true
|
|
15790
|
+
StockTransfer:
|
|
15791
|
+
type: object
|
|
15792
|
+
properties:
|
|
15793
|
+
id:
|
|
15794
|
+
type: string
|
|
15795
|
+
number:
|
|
15796
|
+
type: string
|
|
15797
|
+
reference:
|
|
15798
|
+
type: string
|
|
15799
|
+
nullable: true
|
|
15800
|
+
created_at:
|
|
15801
|
+
type: string
|
|
15802
|
+
updated_at:
|
|
15803
|
+
type: string
|
|
15804
|
+
source_location_id:
|
|
15805
|
+
type: string
|
|
15806
|
+
destination_location_id:
|
|
15807
|
+
type: string
|
|
15808
|
+
required:
|
|
15809
|
+
- id
|
|
15810
|
+
- number
|
|
15811
|
+
- reference
|
|
15812
|
+
- created_at
|
|
15813
|
+
- updated_at
|
|
15814
|
+
- source_location_id
|
|
15815
|
+
- destination_location_id
|
|
15816
|
+
x-typelizer: true
|
|
15349
15817
|
StoreCreditEvent:
|
|
15350
15818
|
type: object
|
|
15351
15819
|
properties:
|
|
@@ -15403,6 +15871,23 @@ components:
|
|
|
15403
15871
|
- display_amount_remaining
|
|
15404
15872
|
- currency
|
|
15405
15873
|
x-typelizer: true
|
|
15874
|
+
SupplierEvent:
|
|
15875
|
+
type: object
|
|
15876
|
+
properties:
|
|
15877
|
+
id:
|
|
15878
|
+
type: string
|
|
15879
|
+
name:
|
|
15880
|
+
type: string
|
|
15881
|
+
created_at:
|
|
15882
|
+
type: string
|
|
15883
|
+
updated_at:
|
|
15884
|
+
type: string
|
|
15885
|
+
required:
|
|
15886
|
+
- id
|
|
15887
|
+
- name
|
|
15888
|
+
- created_at
|
|
15889
|
+
- updated_at
|
|
15890
|
+
x-typelizer: true
|
|
15406
15891
|
TaxIdentifier:
|
|
15407
15892
|
type: object
|
|
15408
15893
|
properties:
|
|
@@ -23,9 +23,9 @@ Every webhook delivery sends a JSON envelope with the event metadata and a `data
|
|
|
23
23
|
| `name` | string | Event name (e.g., `order.placed`) |
|
|
24
24
|
| `created_at` | string | ISO 8601 timestamp |
|
|
25
25
|
| `data` | object | Serialized resource (see payloads below) |
|
|
26
|
-
| `metadata` | object | Additional context: always the Spree version, plus event-specific keys such as `notify_customer`
|
|
26
|
+
| `metadata` | object | Additional context: always the Spree version, plus event-specific keys such as `notify_customer` or `deprecated_alias_of` |
|
|
27
27
|
|
|
28
|
-
Event payloads use the same [Store API V3 serializers](introduction.md) as the REST API. All `id` fields use [prefixed IDs](introduction.md) (e.g., `or_m3Rp9wXz`, `prod_86Rf07xd4z`). All monetary values are strings. All timestamps are ISO 8601.
|
|
28
|
+
Event payloads use the same [Store API V3 serializers](introduction.md) as the REST API, so they never carry back-office fields such as costs, internal notes or staff names. When you need those, fetch the record from the [Admin API](admin-api/introduction.md) using the `id` in the payload. All `id` fields use [prefixed IDs](introduction.md) (e.g., `or_m3Rp9wXz`, `prod_86Rf07xd4z`). All monetary values are strings. All timestamps are ISO 8601.
|
|
29
29
|
|
|
30
30
|
For details on creating webhook endpoints and verifying signatures, see [Webhooks](../developer/core-concepts/webhooks.md). For the event system and the subscriber pattern, see [Events](../developer/core-concepts/events.md).
|
|
31
31
|
|
|
@@ -73,7 +73,7 @@ Events: `order.created`, `order.updated`, `order.deleted`, `order.placed`, `orde
|
|
|
73
73
|
| `order.resend_confirmation_email` | An admin asked to send the order confirmation again |
|
|
74
74
|
| `order.resend_digital_links_email` | An admin asked to send the download links again |
|
|
75
75
|
|
|
76
|
-
The `order.placed` and `order.canceled`
|
|
76
|
+
The `metadata` of `order.placed` and `order.canceled` contains a `notify_customer` boolean. It is `false` when whoever placed or canceled the order asked for the customer not to be emailed.
|
|
77
77
|
|
|
78
78
|
Order payloads include nested `items`, `fulfillments`, `payments`, `discounts`, `fees`, `billing_address`, `shipping_address`, `gift_card`, and `market`.
|
|
79
79
|
|
|
@@ -171,7 +171,7 @@ Carts publish their own events, separate from orders. Use them to follow carts t
|
|
|
171
171
|
|
|
172
172
|
Events: `order_group.created`, `order_group.updated`, `order_group.deleted`, `order_group.completed`
|
|
173
173
|
|
|
174
|
-
When one checkout creates several orders (for example, one per seller), they belong to an order group. `order_group.completed` fires once every order in the group is placed. The payload includes the group's `number`, `email`, `currency`, `total`, `item_total`, `fulfillment_status`, `payment_status`, `completed_at`, the addresses, and the nested `orders`.
|
|
174
|
+
When one checkout creates several orders (for example, one per seller), they belong to an order group. `order_group.completed` fires once every order in the group is placed. The payload includes the group's `number`, `email`, `currency`, `total`, `item_total`, `fulfillment_status`, `payment_status`, `completed_at`, the addresses, and the nested `orders`. Its `metadata` contains `notify_customer`, as on `order.placed`.
|
|
175
175
|
|
|
176
176
|
## Line Item Events
|
|
177
177
|
|
|
@@ -542,6 +542,21 @@ Events: `user.created`, `user.updated`, `user.deleted`, `customer.anonymized`, `
|
|
|
542
542
|
|
|
543
543
|
Customer lifecycle events use the `user` prefix. Customer payloads include nested `addresses`, `default_billing_address`, `default_shipping_address`, `newsletter_subscriber`, and `customer_groups`.
|
|
544
544
|
|
|
545
|
+
`customer.password_reset_requested` carries what you need to send the reset email yourself, rather than the customer record:
|
|
546
|
+
|
|
547
|
+
```json
|
|
548
|
+
{
|
|
549
|
+
"email": "customer@example.com",
|
|
550
|
+
"reset_token": "eyJfcmFpbHMiOnsi...",
|
|
551
|
+
"store_id": "store_UkLWZg9DAJ",
|
|
552
|
+
"redirect_url": "https://shop.example.com/account/reset-password"
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
`redirect_url` is present only when the request included one.
|
|
557
|
+
|
|
558
|
+
> **WARNING:** A reset token lets whoever holds it take over the account. `customer.password_reset_requested` is therefore sent only to endpoints that name it — never to an endpoint subscribed to `*` or `customer.*` — and subscribing to it needs the permission to manage customers. The staff and seller equivalents are never sent to webhooks at all: Spree sends those emails itself.
|
|
559
|
+
|
|
545
560
|
```json
|
|
546
561
|
{
|
|
547
562
|
"id": "cust_k5nR8xLq",
|
|
@@ -865,7 +880,7 @@ Events: `invitation.created`, `invitation.resent`, `invitation.accepted`
|
|
|
865
880
|
|
|
866
881
|
## Other Events
|
|
867
882
|
|
|
868
|
-
These resources publish events too.
|
|
883
|
+
These resources publish events too. Back-office records (purchase orders, stock receipts, suppliers and shipping labels) send a short payload with their status, related record IDs and timestamps; fetch the rest from the Admin API.
|
|
869
884
|
|
|
870
885
|
| Resource | Events |
|
|
871
886
|
|---|---|
|
|
@@ -134,7 +134,13 @@ subscribes_to 'order.placed', async: false
|
|
|
134
134
|
|
|
135
135
|
## Publishing your own events
|
|
136
136
|
|
|
137
|
-
Anything in your own code can announce something, and subscribers and webhooks treat it like any built-in event:
|
|
137
|
+
Anything in your own code can announce something, and subscribers and webhooks treat it like any built-in event. Declare the event on the model first, then publish it:
|
|
138
|
+
|
|
139
|
+
```ruby server/config/initializers/spree_events.rb
|
|
140
|
+
Rails.application.config.to_prepare do
|
|
141
|
+
Spree::Order.publishes_event :flagged_for_review
|
|
142
|
+
end
|
|
143
|
+
```
|
|
138
144
|
|
|
139
145
|
```ruby server/app/services/fraud_check.rb
|
|
140
146
|
order.publish_event('order.flagged_for_review')
|
|
@@ -142,6 +148,10 @@ order.publish_event('order.flagged_for_review')
|
|
|
142
148
|
|
|
143
149
|
Useful when your own domain has moments worth reacting to — a fraud check completing, an approval granted.
|
|
144
150
|
|
|
151
|
+
Every event Spree publishes is declared this way, which is what lets the admin dashboard's webhook picker, the [webhook events endpoint](webhooks.md#event-subscriptions) and the typed events in `@spree/sdk/webhooks` list it. Publishing an event nobody declared raises an error in development and test, so a typo is caught before it ships; in production it is logged and delivered anyway.
|
|
152
|
+
|
|
153
|
+
The payload is the model's Store API serializer, as for built-in events. To send something else, pass a serializer of your own: `publishes_event :flagged_for_review, serializer: 'MyApp::FraudFlagEventSerializer'`. Keep it to what a customer could see; back-office fields belong behind the Admin API. Facts about the event rather than the record, such as who triggered it, go in its metadata: `order.publish_event('order.flagged_for_review', nil, rule: 'velocity')`.
|
|
154
|
+
|
|
145
155
|
## Guidance
|
|
146
156
|
|
|
147
157
|
**Listen for the specific event.** `order.placed` rather than `order.updated` with a status check.
|
|
@@ -141,6 +141,28 @@ The `subscriptions` array accepts exact event names and wildcard patterns:
|
|
|
141
141
|
| `['order.*', 'payment.*', 'fulfillment.fulfilled']` | Multiple patterns |
|
|
142
142
|
| `[]` or `['*']` | All events |
|
|
143
143
|
|
|
144
|
+
An event that carries a credential — `customer.password_reset_requested`, which includes a reset token — is never matched by a pattern. An endpoint receives it only when it names it, and naming it needs the permission to manage customers. Password reset requests for staff and sellers are never sent to webhooks: Spree emails those itself.
|
|
145
|
+
|
|
146
|
+
To see every event you can subscribe to, including those your installed extensions add, list them:
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
```typescript Admin SDK
|
|
150
|
+
const { data: events } = await client.webhookEvents.list()
|
|
151
|
+
// [{ name: 'order.placed', group: 'order', credential: false, deprecated: false, ... }, ...]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```bash CLI
|
|
155
|
+
spree api get /webhook_events
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```bash cURL
|
|
159
|
+
curl 'https://api.mystore.com/api/v3/admin/webhook_events' \
|
|
160
|
+
-H 'X-Spree-API-Key: sk_xxx'
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
Each entry says whether the event carries a credential (and which permission subscribing to it needs), and whether it is a deprecated name along with the event that replaces it.
|
|
165
|
+
|
|
144
166
|
## Webhook Payload
|
|
145
167
|
|
|
146
168
|
Each webhook delivery sends a JSON payload with the following structure. The `data` object uses the same [Store API V3 serializers](../../api-reference/introduction.md) as the REST API, so webhook payloads and API responses share the same schema:
|
|
@@ -175,7 +197,9 @@ Each webhook delivery sends a JSON payload with the following structure. The `da
|
|
|
175
197
|
| `name` | Event name (e.g., `order.placed`) |
|
|
176
198
|
| `created_at` | ISO8601 timestamp when event occurred |
|
|
177
199
|
| `data` | Serialized resource data (V3 API format with [prefixed IDs](../../api-reference/introduction.md)) |
|
|
178
|
-
| `metadata` | Additional context
|
|
200
|
+
| `metadata` | Additional context: the Spree version, plus facts about the event itself, such as `notify_customer` |
|
|
201
|
+
|
|
202
|
+
Payloads carry what a customer could see, never back-office fields such as costs, internal notes or staff names. When an integration needs those, it fetches the record from the Admin API with the `id` in the payload, using a key scoped to what it may read.
|
|
179
203
|
|
|
180
204
|
For complete payload schemas for each event type, see [Webhook Events & Payloads](../../api-reference/webhooks-events.md).
|
|
181
205
|
|
|
@@ -203,29 +227,49 @@ The [Spree Storefront](https://github.com/spree/storefront) includes a ready-mad
|
|
|
203
227
|
|
|
204
228
|
#### Any JavaScript/TypeScript framework
|
|
205
229
|
|
|
206
|
-
Use `@spree/sdk/webhooks` for framework-agnostic verification:
|
|
230
|
+
Use `@spree/sdk/webhooks` for framework-agnostic verification. `constructWebhookEvent` checks the signature and returns a typed event: once you check `event.name`, `event.data` has the type of the record that event carries.
|
|
207
231
|
|
|
208
232
|
```typescript Store SDK
|
|
209
|
-
import {
|
|
210
|
-
import
|
|
211
|
-
import type { Order } from '@spree/sdk'
|
|
233
|
+
import { constructWebhookEvent, WebhookVerificationError } from '@spree/sdk/webhooks'
|
|
234
|
+
import { webhookEventSchemas } from '@spree/sdk/zod'
|
|
212
235
|
|
|
213
236
|
// Hono, Cloudflare Workers, or any Web Fetch API-based framework
|
|
214
|
-
app.post('/webhooks/spree', async (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
237
|
+
app.post('/webhooks/spree', async (c) => {
|
|
238
|
+
let event
|
|
239
|
+
try {
|
|
240
|
+
event = constructWebhookEvent(await c.req.text(), c.req.raw.headers, process.env.SPREE_WEBHOOK_SECRET!, {
|
|
241
|
+
schemas: webhookEventSchemas, // optional: validate `data` at runtime
|
|
242
|
+
})
|
|
243
|
+
} catch (error) {
|
|
244
|
+
if (error instanceof WebhookVerificationError) return c.json({ error: 'Invalid signature' }, 401)
|
|
245
|
+
throw error
|
|
246
|
+
}
|
|
218
247
|
|
|
219
|
-
|
|
220
|
-
|
|
248
|
+
switch (event.name) {
|
|
249
|
+
case 'order.placed':
|
|
250
|
+
await fulfil(event.data) // typed as Order
|
|
251
|
+
break
|
|
252
|
+
case 'customer.password_reset_requested':
|
|
253
|
+
await sendResetEmail(event.data.email, event.data.reset_token)
|
|
254
|
+
break
|
|
221
255
|
}
|
|
222
256
|
|
|
223
|
-
|
|
224
|
-
// handle event...
|
|
225
|
-
res.json({ received: true })
|
|
257
|
+
return c.json({ received: true })
|
|
226
258
|
})
|
|
227
259
|
```
|
|
228
260
|
|
|
261
|
+
Pass the body exactly as received: parsing and re-serializing it changes the bytes the signature covers. `verifyWebhookSignature` is still available when you only need the check.
|
|
262
|
+
|
|
263
|
+
Events your own code or an extension publishes can be typed too, by adding them to `WebhookEventMap`:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
declare module '@spree/sdk/webhooks' {
|
|
267
|
+
interface WebhookEventMap {
|
|
268
|
+
'loyalty.points_earned': { id: string; points: number }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
229
273
|
#### Ruby
|
|
230
274
|
|
|
231
275
|
```ruby server/app/controllers/webhooks_controller.rb
|
|
@@ -324,7 +368,7 @@ SSL certificates are verified in production, and not in development — so you c
|
|
|
324
368
|
|
|
325
369
|
## Available Events
|
|
326
370
|
|
|
327
|
-
Webhooks can subscribe to any event in Spree's event system. See [Webhook Events & Payloads](../../api-reference/webhooks-events.md) for the complete list.
|
|
371
|
+
Webhooks can subscribe to any event in Spree's event system. See [Webhook Events & Payloads](../../api-reference/webhooks-events.md) for the complete list, or [list them through the Admin API](#event-subscriptions) to include the events your extensions add.
|
|
328
372
|
|
|
329
373
|
Common webhook events include:
|
|
330
374
|
|
|
@@ -14,12 +14,14 @@ store.save
|
|
|
14
14
|
|
|
15
15
|
To define a model preference, you need to add them to your model class.
|
|
16
16
|
|
|
17
|
-
Make sure to generate a migration to add the `preferences` column to the table. This column
|
|
17
|
+
Make sure to generate a migration to add the `preferences` column to the table. This column stores the preferences as JSON.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
spree generate migration AddPreferencesToSpreeBrands preferences:
|
|
20
|
+
spree generate migration AddPreferencesToSpreeBrands preferences:jsonb
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
`jsonb` is for PostgreSQL, the default database. On MySQL or SQLite use `preferences:json`.
|
|
24
|
+
|
|
23
25
|
Run the migration.
|
|
24
26
|
|
|
25
27
|
```bash
|
|
@@ -90,7 +92,28 @@ You can get a hash of all stored preferences by accessing the `preferences` help
|
|
|
90
92
|
brand.preferences # => { 'featured' => false, 'display_name' => 'Wilson' }
|
|
91
93
|
```
|
|
92
94
|
|
|
93
|
-
This hash will contain the value for every preference that has been defined for the model instance, whether the value is the default or one that has been previously stored.
|
|
95
|
+
This hash will contain the value for every preference that has been defined for the model instance, whether the value is the default or one that has been previously stored. Its keys are strings, and it can be read with either strings or symbols (`brand.preferences[:featured]`). Values are stored as JSON, so read typed values through the `preferred_*` methods: a `:decimal` preference comes back as a `BigDecimal` there, while the raw hash holds its exact string (`"9.99"`).
|
|
96
|
+
|
|
97
|
+
`preferences` never holds secrets — see [Secret preferences](#secret-preferences).
|
|
98
|
+
|
|
99
|
+
## Secret preferences
|
|
100
|
+
|
|
101
|
+
Declare API keys, signing secrets and other credentials with the `:password` type:
|
|
102
|
+
|
|
103
|
+
```ruby server/app/models/my_app/gateway.rb
|
|
104
|
+
module MyApp
|
|
105
|
+
class Gateway < Spree::Gateway
|
|
106
|
+
preference :publishable_key, :string
|
|
107
|
+
preference :secret_key, :password
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
A `:password` preference works like any other — `preferred_secret_key`, `preferred_secret_key = ...`, `get_preference(:secret_key)` — but it is stored apart from the other preferences, in an encrypted `secret_preferences` column, whenever [Active Record encryption keys](../deployment/environment_variables.md#active-record-encryption) are configured. The Admin API returns it masked, showing only its last four characters.
|
|
113
|
+
|
|
114
|
+
Payment methods and integrations already have that column. To declare a secret on another model, include `Spree::SecretPreferences` and add a `secret_preferences` text column to its table; Spree refuses a `:password` preference on a model that cannot encrypt it.
|
|
115
|
+
|
|
116
|
+
Always declare a credential as `:password`. A secret declared as `:string`, or nested inside a `:hash` or `:array` preference, is stored in plain text.
|
|
94
117
|
|
|
95
118
|
## Models with preferences
|
|
96
119
|
|
|
@@ -18,7 +18,7 @@ You'll almost always want to set [`RAILS_HOST`](#urls-and-hosts) too — without
|
|
|
18
18
|
|
|
19
19
|
## Active Record encryption
|
|
20
20
|
|
|
21
|
-
Spree encrypts sensitive values at rest with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html): webhook endpoint signing secrets, payment gateway customer IDs, and the OAuth tokens stored on user identities. It does so only when encryption keys are configured — without them, these values are stored in plain text and a production app logs a warning at boot.
|
|
21
|
+
Spree encrypts sensitive values at rest with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html): payment gateway and integration secrets (API keys and webhook signing secrets), webhook endpoint signing secrets, payment gateway customer IDs, and the OAuth tokens stored on user identities. It does so only when encryption keys are configured — without them, these values are stored in plain text and a production app logs a warning at boot.
|
|
22
22
|
|
|
23
23
|
| Variable | Description |
|
|
24
24
|
| --- | --- |
|
|
@@ -45,10 +45,16 @@ After restarting your server, you can select "MyGateway" when creating a new pay
|
|
|
45
45
|
|
|
46
46
|
### Show a logo and setup guide (optional)
|
|
47
47
|
|
|
48
|
-
Payment
|
|
48
|
+
Payment methods backed by an external provider also appear in the admin dashboard under **Settings > Integrations**, next to other connected services. A method is listed there when it inherits from `Spree::Gateway`, or when its class defines `self.third_party?` to return `true`. Declare a logo and a link to your setup guide so merchants recognise the provider and know how to connect it:
|
|
49
49
|
|
|
50
50
|
```ruby app/models/my_gateway.rb
|
|
51
51
|
class MyGateway < Spree::PaymentMethod
|
|
52
|
+
# Lists MyGateway under Settings > Integrations. Not needed when the class
|
|
53
|
+
# inherits from Spree::Gateway.
|
|
54
|
+
def self.third_party?
|
|
55
|
+
true
|
|
56
|
+
end
|
|
57
|
+
|
|
52
58
|
def self.logo_url
|
|
53
59
|
'https://my-gateway.example.com/logo.svg'
|
|
54
60
|
end
|
|
@@ -49,6 +49,24 @@ Re-running is safe — `bundle exec rake spree:upgrade` figures out what still n
|
|
|
49
49
|
|
|
50
50
|
Reference material — the data backfills `bundle exec rake spree:upgrade` executes. Every task is idempotent.
|
|
51
51
|
|
|
52
|
+
### Store preferences as JSON
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
```bash Spree CLI (Docker)
|
|
56
|
+
spree rake spree:upgrade:preferences_json
|
|
57
|
+
spree rake spree:upgrade:encrypt_secret_preferences
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```bash Without Spree CLI
|
|
61
|
+
bundle exec rake spree:upgrade:preferences_json
|
|
62
|
+
bundle exec rake spree:upgrade:encrypt_secret_preferences
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
Preferences were stored as YAML; in 6.0 they are JSON. The migration converts every `preferences` column itself, and moves gateway and integration secrets (preferences declared as `:password`) into a new `secret_preferences` column. The first task is a safety net for anything the migration could not reach — a schema changed by hand, or an extension gem installed after the migration ran. The second encrypts the moved secrets; until it runs they stay readable and are encrypted the next time their payment method or integration is saved. It does nothing until [encryption keys](#enable-active-record-encryption) are configured.
|
|
67
|
+
|
|
68
|
+
See [Preferences are stored as JSON](#preferences-are-stored-as-json) for what changes in your code.
|
|
69
|
+
|
|
52
70
|
### Convert incomplete orders into carts
|
|
53
71
|
|
|
54
72
|
```bash
|
|
@@ -181,7 +199,7 @@ Countries and states are no longer database records in 6.0. Addresses, delivery
|
|
|
181
199
|
|
|
182
200
|
## Enable Active Record encryption
|
|
183
201
|
|
|
184
|
-
Spree encrypts webhook endpoint signing secrets, payment gateway customer IDs and the OAuth tokens on user identities with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html) — but only when encryption keys are configured. Without keys these values are stored in plain text. New 6.0 projects get keys at setup; upgraded applications need to add them.
|
|
202
|
+
Spree encrypts payment gateway and integration secrets, webhook endpoint signing secrets, payment gateway customer IDs and the OAuth tokens on user identities with [Active Record encryption](https://guides.rubyonrails.org/active_record_encryption.html) — but only when encryption keys are configured. Without keys these values are stored in plain text. New 6.0 projects get keys at setup; upgraded applications need to add them.
|
|
185
203
|
|
|
186
204
|
**1. Make the app read the keys.** Projects created from `spree-starter` read them from the `ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY`, `ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY` and `ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT` env vars, falling back to the `active_record_encryption` entry in Rails credentials. If your `config/application.rb` predates this, add inside the `Application` class:
|
|
187
205
|
|
|
@@ -212,7 +230,31 @@ Recreate the containers so they pick up the new `.env` (`spree update`, or `spre
|
|
|
212
230
|
|
|
213
231
|
> **WARNING:** Never change or lose the keys once data is encrypted — the encrypted records become unreadable.
|
|
214
232
|
|
|
215
|
-
**3. Encrypt existing rows.** Rows written before the keys were set are plain text. OAuth tokens on user identities stay readable and are encrypted on their next write. Webhook endpoint secrets and gateway customer IDs can't be read in plain text once encryption is on — follow [Enabling encryption on an existing installation](../deployment/environment_variables.md#enabling-encryption-on-an-existing-installation): turn on `support_unencrypted_data` and `extend_queries`, deploy with the keys, run `find_each(&:encrypt)` over `Spree::WebhookEndpoint`, `Spree::GatewayCustomer` and `Spree::UserIdentity`, then turn the two settings off again.
|
|
233
|
+
**3. Encrypt existing rows.** Rows written before the keys were set are plain text. Gateway and integration secrets and the OAuth tokens on user identities stay readable and are encrypted on their next write; run `spree rake spree:upgrade:encrypt_secret_preferences` (`bundle exec rake spree:upgrade:encrypt_secret_preferences` without the Spree CLI) to encrypt every gateway and integration secret at once. Webhook endpoint secrets and gateway customer IDs can't be read in plain text once encryption is on — follow [Enabling encryption on an existing installation](../deployment/environment_variables.md#enabling-encryption-on-an-existing-installation): turn on `support_unencrypted_data` and `extend_queries`, deploy with the keys, run `find_each(&:encrypt)` over `Spree::WebhookEndpoint`, `Spree::GatewayCustomer` and `Spree::UserIdentity`, then turn the two settings off again.
|
|
234
|
+
|
|
235
|
+
## Preferences are stored as JSON
|
|
236
|
+
|
|
237
|
+
Model preferences moved from YAML to JSON, and secrets moved out of them. Declarations do not change, and the `preferred_*` methods return the same values as before. What can affect your code:
|
|
238
|
+
|
|
239
|
+
- **The raw `preferences` hash has string keys.** It still answers to symbols (`calculator.preferences[:amount]`), but `preferences.keys` returns strings. Decimals sit in it as exact strings (`"9.99"`); read them through `preferred_*`, which returns a `BigDecimal`.
|
|
240
|
+
- **Secrets are not in `preferences`.** Preferences declared `:password` live in the encrypted `secret_preferences` column. Read them with `preferred_*` or `get_preference`. A secret you assign as part of a whole hash (`update(preferences: { secret_key: ... })`) is moved there when the record is saved. To declare a secret on a model other than a payment method or an integration, see [Secret preferences](../customization/model-preferences.md#secret-preferences).
|
|
241
|
+
- **Your own preference tables need a JSON column.** The migration converts every table a model storing Spree preferences reads, including your application's own; a table another library owns is left alone. A new table should use `t.jsonb :preferences` on PostgreSQL, the default database (`t.json` on MySQL or SQLite).
|
|
242
|
+
- **Tiered calculators take a list of tiers.** `Spree::Calculator::TieredPercent` and `TieredFlatRate` store `tiers` as a list instead of a hash keyed by threshold, in Ruby and in the Admin API. The migration converts existing calculators.
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
// Before
|
|
246
|
+
{ "tiers": { "100": 10, "250": 15 } }
|
|
247
|
+
// After
|
|
248
|
+
{ "tiers": [{ "threshold": "100", "value": "10" }, { "threshold": "250", "value": "15" }] }
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`value` is a percentage for `TieredPercent` and an amount for `TieredFlatRate`.
|
|
252
|
+
- **Spree no longer allows extra classes in YAML columns.** It used to add `Symbol`, `BigDecimal` and a few time classes to `config.active_record.yaml_column_permitted_classes`. If your application serializes its own columns as YAML with those classes, add them in `config/application.rb` yourself.
|
|
253
|
+
- **Preference change methods follow Rails' naming.** Each preference is a Rails store accessor, so `preferred_<name>_changed?`, `preferred_<name>_change` and `preferred_<name>_was` work as before, while the after-save forms are Rails' own: `saved_change_to_preferred_<name>?` replaces `preferred_<name>_previously_changed?`, `saved_change_to_preferred_<name>` replaces `preferred_<name>_previous_change`, and `preferred_<name>_before_last_save` replaces `preferred_<name>_previously_was`.
|
|
254
|
+
- **Per-preference helper methods are gone.** Use `preference_type(:name)`, `preference_default(:name)` and `preference_deprecated(:name)` instead of `preferred_<name>_type`, `preferred_<name>_default` and `preferred_<name>_deprecated`. `clear_preferences`, `restore_preferences_for`, `preferences_of_type`, the class methods `preference_getter_method`, `preference_setter_method` and `prefers_query_method`, `Spree::Preferences::ScopedStore`, `Spree::Preferences::Store` and the `Spree::Preference` model are removed.
|
|
255
|
+
- **The `spree_preferences` table is dropped.** The installation id it held is not carried over: the default store generates a new one the next time it is saved. Rows an application wrote there itself are dropped with it: copy any you need before upgrading.
|
|
256
|
+
- **Preferences live only on models.** `Spree::Preferences::Preferable` is included by `Spree::Base` and needs a `preferences` JSON column; including it in a plain Ruby class is no longer supported. A hash stored inside a preference comes back with string keys.
|
|
257
|
+
- **A record whose preferences still hold YAML cannot be read.** The migration converts every row, so this only happens to rows written by older code after it ran. Run `spree rake spree:upgrade:preferences_json` (`bundle exec rake spree:upgrade:preferences_json` without the Spree CLI) to convert it.
|
|
216
258
|
|
|
217
259
|
## The Cart/Order split
|
|
218
260
|
|
|
@@ -453,6 +495,18 @@ now returns `nil` for an ID with another model's prefix, the same as
|
|
|
453
495
|
`find_by_prefix_id`. Call `Spree::PrefixedId.decode_prefixed_id` if you
|
|
454
496
|
really need to decode any prefix.
|
|
455
497
|
|
|
498
|
+
## Every event is declared
|
|
499
|
+
|
|
500
|
+
Events are now declared on the model that publishes them (`publishes_event`, `publishes_events`), and `publish_event` raises in development and test for a name nobody declared. Extensions that publish their own events need one line each — see [Publishing your own events](../core-concepts/events.md#publishing-your-own-events). In production an undeclared event is logged and still delivered.
|
|
501
|
+
|
|
502
|
+
Some payloads changed so that every webhook carries the Store API shape and nothing more:
|
|
503
|
+
|
|
504
|
+
- **`notify_customer` moved to `metadata`** on `order.placed`, `order.completed`, `order.canceled` and `order_group.completed`. Read `event.metadata['notify_customer']` in subscribers and `metadata.notify_customer` in webhook receivers.
|
|
505
|
+
- **`customer.anonymized`** carries the customer record; the store and the requester moved to `metadata` (`store_id`, `requested_by_id`).
|
|
506
|
+
- **Purchase order, stock receipt, supplier and shipping label events** carry a short payload — status, related record IDs and timestamps. Costs, notes, contact details and label files are read from the Admin API.
|
|
507
|
+
- **`saved_report.*`** no longer includes the author's name.
|
|
508
|
+
- **Subscribing an endpoint to `customer.password_reset_requested`** needs the permission to manage customers. The staff and seller reset events are still never sent to webhooks.
|
|
509
|
+
|
|
456
510
|
## Removed in 6.0
|
|
457
511
|
|
|
458
512
|
These were deprecated in 5.x and are **gone now** — there is no bridge, so calls raise `NoMethodError`. Most were one-line delegations to a replacement that already exists.
|