spree_core 5.1.8 → 5.2.0.rc1

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.
Files changed (389) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/payment_icons/ach.svg +1 -0
  3. data/app/assets/images/payment_icons/achdirectdebit.svg +1 -0
  4. data/app/assets/images/payment_icons/ada.svg +1 -0
  5. data/app/assets/images/payment_icons/adyen.svg +1 -0
  6. data/app/assets/images/payment_icons/affinbank.svg +1 -0
  7. data/app/assets/images/payment_icons/affirm.svg +1 -0
  8. data/app/assets/images/payment_icons/afterpay.svg +1 -0
  9. data/app/assets/images/payment_icons/airtel_money.svg +1 -0
  10. data/app/assets/images/payment_icons/airteltigo_mobile_money.svg +1 -0
  11. data/app/assets/images/payment_icons/alandsbanken.svg +1 -0
  12. data/app/assets/images/payment_icons/alipay.svg +1 -0
  13. data/app/assets/images/payment_icons/alipay_hk.svg +1 -0
  14. data/app/assets/images/payment_icons/alliancebank.svg +1 -0
  15. data/app/assets/images/payment_icons/alma.svg +1 -0
  16. data/app/assets/images/payment_icons/amazon.svg +1 -0
  17. data/app/assets/images/payment_icons/ambank.svg +1 -0
  18. data/app/assets/images/payment_icons/american_express.svg +1 -0
  19. data/app/assets/images/payment_icons/apecoin.svg +1 -0
  20. data/app/assets/images/payment_icons/apple_pay.svg +1 -0
  21. data/app/assets/images/payment_icons/arbitrum.svg +1 -0
  22. data/app/assets/images/payment_icons/atome.svg +1 -0
  23. data/app/assets/images/payment_icons/authorizenet.svg +1 -0
  24. data/app/assets/images/payment_icons/avalanche.svg +1 -0
  25. data/app/assets/images/payment_icons/bacs.svg +1 -0
  26. data/app/assets/images/payment_icons/bancontact.svg +1 -0
  27. data/app/assets/images/payment_icons/bangkokbank.svg +1 -0
  28. data/app/assets/images/payment_icons/bankislam.svg +1 -0
  29. data/app/assets/images/payment_icons/bankmuamalat.svg +1 -0
  30. data/app/assets/images/payment_icons/bankofamerica.svg +1 -0
  31. data/app/assets/images/payment_icons/bankrakyat.svg +1 -0
  32. data/app/assets/images/payment_icons/base.svg +1 -0
  33. data/app/assets/images/payment_icons/becs.svg +1 -0
  34. data/app/assets/images/payment_icons/benefit.svg +1 -0
  35. data/app/assets/images/payment_icons/billie.svg +1 -0
  36. data/app/assets/images/payment_icons/bitcoin.svg +1 -0
  37. data/app/assets/images/payment_icons/bitcoin_cash.svg +1 -0
  38. data/app/assets/images/payment_icons/bizum.svg +1 -0
  39. data/app/assets/images/payment_icons/blik.svg +1 -0
  40. data/app/assets/images/payment_icons/bnbchain.svg +1 -0
  41. data/app/assets/images/payment_icons/bogus.svg +1 -0
  42. data/app/assets/images/payment_icons/bogus_app_coin.svg +1 -0
  43. data/app/assets/images/payment_icons/boleto.svg +1 -0
  44. data/app/assets/images/payment_icons/boost.svg +1 -0
  45. data/app/assets/images/payment_icons/braintree.svg +1 -0
  46. data/app/assets/images/payment_icons/buckaroopaybybank.svg +1 -0
  47. data/app/assets/images/payment_icons/busd.svg +1 -0
  48. data/app/assets/images/payment_icons/cartes_bancaires.svg +1 -0
  49. data/app/assets/images/payment_icons/cash.svg +1 -0
  50. data/app/assets/images/payment_icons/cashappafterpay.svg +1 -0
  51. data/app/assets/images/payment_icons/cashapppay.svg +1 -0
  52. data/app/assets/images/payment_icons/checkout_finance.svg +1 -0
  53. data/app/assets/images/payment_icons/chinabank.svg +1 -0
  54. data/app/assets/images/payment_icons/clearpay.svg +1 -0
  55. data/app/assets/images/payment_icons/collector_bank.svg +1 -0
  56. data/app/assets/images/payment_icons/dai.svg +1 -0
  57. data/app/assets/images/payment_icons/dana.svg +1 -0
  58. data/app/assets/images/payment_icons/dankort.svg +1 -0
  59. data/app/assets/images/payment_icons/danske_bank.svg +1 -0
  60. data/app/assets/images/payment_icons/deutschebank.svg +1 -0
  61. data/app/assets/images/payment_icons/diners_club.svg +1 -0
  62. data/app/assets/images/payment_icons/directbanktransferlatinamerica.svg +1 -0
  63. data/app/assets/images/payment_icons/discover.svg +1 -0
  64. data/app/assets/images/payment_icons/dogecoin.svg +1 -0
  65. data/app/assets/images/payment_icons/duitnow.svg +1 -0
  66. data/app/assets/images/payment_icons/eft_secure.svg +1 -0
  67. data/app/assets/images/payment_icons/eftpos_au.svg +1 -0
  68. data/app/assets/images/payment_icons/eftposau.svg +1 -0
  69. data/app/assets/images/payment_icons/elo.svg +1 -0
  70. data/app/assets/images/payment_icons/eos.svg +1 -0
  71. data/app/assets/images/payment_icons/eps.svg +1 -0
  72. data/app/assets/images/payment_icons/ethereum.svg +1 -0
  73. data/app/assets/images/payment_icons/eurobonuscheckout.svg +1 -0
  74. data/app/assets/images/payment_icons/ezcash.svg +1 -0
  75. data/app/assets/images/payment_icons/fantom.svg +1 -0
  76. data/app/assets/images/payment_icons/fpx.svg +1 -0
  77. data/app/assets/images/payment_icons/gcash.svg +1 -0
  78. data/app/assets/images/payment_icons/generic.svg +1 -0
  79. data/app/assets/images/payment_icons/genericbank.svg +1 -0
  80. data/app/assets/images/payment_icons/gift-card.svg +1 -0
  81. data/app/assets/images/payment_icons/giropay.svg +1 -0
  82. data/app/assets/images/payment_icons/glbepaypal.svg +1 -0
  83. data/app/assets/images/payment_icons/gmobanktransfer.svg +1 -0
  84. data/app/assets/images/payment_icons/gnosis.svg +1 -0
  85. data/app/assets/images/payment_icons/google_pay.svg +1 -0
  86. data/app/assets/images/payment_icons/google_wallet.svg +1 -0
  87. data/app/assets/images/payment_icons/gopay.svg +1 -0
  88. data/app/assets/images/payment_icons/grabpay.svg +1 -0
  89. data/app/assets/images/payment_icons/gusd.svg +1 -0
  90. data/app/assets/images/payment_icons/handelsbanken.svg +1 -0
  91. data/app/assets/images/payment_icons/hongleongbank.svg +1 -0
  92. data/app/assets/images/payment_icons/hypercard.svg +1 -0
  93. data/app/assets/images/payment_icons/hypercash.svg +1 -0
  94. data/app/assets/images/payment_icons/ideal.svg +1 -0
  95. data/app/assets/images/payment_icons/in3viaideal.svg +1 -0
  96. data/app/assets/images/payment_icons/inbank.svg +1 -0
  97. data/app/assets/images/payment_icons/jcb.svg +1 -0
  98. data/app/assets/images/payment_icons/kakao_pay.svg +1 -0
  99. data/app/assets/images/payment_icons/kasikornbank.svg +1 -0
  100. data/app/assets/images/payment_icons/klarna-pay-later.svg +1 -0
  101. data/app/assets/images/payment_icons/klarna-pay-now.svg +1 -0
  102. data/app/assets/images/payment_icons/klarna-slice-it.svg +1 -0
  103. data/app/assets/images/payment_icons/klarna.svg +1 -0
  104. data/app/assets/images/payment_icons/knet.svg +1 -0
  105. data/app/assets/images/payment_icons/krungthaibank.svg +1 -0
  106. data/app/assets/images/payment_icons/landbank.svg +1 -0
  107. data/app/assets/images/payment_icons/laybuybyklarna.svg +1 -0
  108. data/app/assets/images/payment_icons/litecoin.svg +1 -0
  109. data/app/assets/images/payment_icons/lunchcheck.svg +1 -0
  110. data/app/assets/images/payment_icons/mach.svg +1 -0
  111. data/app/assets/images/payment_icons/mada.svg +1 -0
  112. data/app/assets/images/payment_icons/maestro.svg +1 -0
  113. data/app/assets/images/payment_icons/master.svg +1 -0
  114. data/app/assets/images/payment_icons/mayabank.svg +1 -0
  115. data/app/assets/images/payment_icons/maybank.svg +1 -0
  116. data/app/assets/images/payment_icons/maybankm2u.svg +1 -0
  117. data/app/assets/images/payment_icons/maybankqrpay.svg +1 -0
  118. data/app/assets/images/payment_icons/mbway.svg +1 -0
  119. data/app/assets/images/payment_icons/mcash.svg +1 -0
  120. data/app/assets/images/payment_icons/medicinosbankas.svg +1 -0
  121. data/app/assets/images/payment_icons/mercadopago.svg +1 -0
  122. data/app/assets/images/payment_icons/metrobank.svg +1 -0
  123. data/app/assets/images/payment_icons/mobilepay.svg +1 -0
  124. data/app/assets/images/payment_icons/momopay.svg +1 -0
  125. data/app/assets/images/payment_icons/monero.svg +1 -0
  126. data/app/assets/images/payment_icons/mtn_mobile_money.svg +1 -0
  127. data/app/assets/images/payment_icons/mybank.svg +1 -0
  128. data/app/assets/images/payment_icons/naver_pay.svg +1 -0
  129. data/app/assets/images/payment_icons/nelo.svg +1 -0
  130. data/app/assets/images/payment_icons/netbanking.svg +1 -0
  131. data/app/assets/images/payment_icons/novalnetdirectdebitach.svg +1 -0
  132. data/app/assets/images/payment_icons/nubank.svg +1 -0
  133. data/app/assets/images/payment_icons/ocbcbank.svg +1 -0
  134. data/app/assets/images/payment_icons/offlinebanktransferlatinamerica.svg +1 -0
  135. data/app/assets/images/payment_icons/ola_money.svg +1 -0
  136. data/app/assets/images/payment_icons/oney.svg +1 -0
  137. data/app/assets/images/payment_icons/onlinebanking.svg +1 -0
  138. data/app/assets/images/payment_icons/onlinebanktransfer.svg +1 -0
  139. data/app/assets/images/payment_icons/orangemobilemoney.svg +1 -0
  140. data/app/assets/images/payment_icons/otpbank.svg +1 -0
  141. data/app/assets/images/payment_icons/oxxo.svg +1 -0
  142. data/app/assets/images/payment_icons/paybybank.svg +1 -0
  143. data/app/assets/images/payment_icons/paybybankmollie.svg +1 -0
  144. data/app/assets/images/payment_icons/paybybankus.svg +1 -0
  145. data/app/assets/images/payment_icons/paycash.svg +1 -0
  146. data/app/assets/images/payment_icons/payco.svg +1 -0
  147. data/app/assets/images/payment_icons/payeverpaybybank.svg +1 -0
  148. data/app/assets/images/payment_icons/payme.svg +1 -0
  149. data/app/assets/images/payment_icons/paynow.svg +1 -0
  150. data/app/assets/images/payment_icons/paynowmbank.svg +1 -0
  151. data/app/assets/images/payment_icons/paypal.svg +1 -0
  152. data/app/assets/images/payment_icons/paypo.svg +1 -0
  153. data/app/assets/images/payment_icons/payrexxbanktransfer.svg +1 -0
  154. data/app/assets/images/payment_icons/payrexxpaybybank.svg +1 -0
  155. data/app/assets/images/payment_icons/paysafecash.svg +1 -0
  156. data/app/assets/images/payment_icons/pix.svg +1 -0
  157. data/app/assets/images/payment_icons/polygon.svg +1 -0
  158. data/app/assets/images/payment_icons/przelewy24.svg +1 -0
  159. data/app/assets/images/payment_icons/publicbank.svg +1 -0
  160. data/app/assets/images/payment_icons/publicbank_pbe.svg +1 -0
  161. data/app/assets/images/payment_icons/qr_promptpay.svg +1 -0
  162. data/app/assets/images/payment_icons/rabobank.svg +1 -0
  163. data/app/assets/images/payment_icons/revolut.svg +1 -0
  164. data/app/assets/images/payment_icons/rhbbank.svg +1 -0
  165. data/app/assets/images/payment_icons/riverty.svg +1 -0
  166. data/app/assets/images/payment_icons/safetypaybanktransfer.svg +1 -0
  167. data/app/assets/images/payment_icons/samsung_pay.svg +1 -0
  168. data/app/assets/images/payment_icons/satispay.svg +1 -0
  169. data/app/assets/images/payment_icons/scalapay.svg +1 -0
  170. data/app/assets/images/payment_icons/scotiabank.svg +1 -0
  171. data/app/assets/images/payment_icons/seabankid.svg +1 -0
  172. data/app/assets/images/payment_icons/seabankph.svg +1 -0
  173. data/app/assets/images/payment_icons/sepa_bank_transfer.svg +1 -0
  174. data/app/assets/images/payment_icons/sepadirectdebit.svg +1 -0
  175. data/app/assets/images/payment_icons/seveneleven.svg +1 -0
  176. data/app/assets/images/payment_icons/shib.svg +1 -0
  177. data/app/assets/images/payment_icons/shopcash.svg +1 -0
  178. data/app/assets/images/payment_icons/siauliubankas.svg +1 -0
  179. data/app/assets/images/payment_icons/skeps.svg +1 -0
  180. data/app/assets/images/payment_icons/snap_checkout.svg +1 -0
  181. data/app/assets/images/payment_icons/sofort.svg +1 -0
  182. data/app/assets/images/payment_icons/softbank.svg +1 -0
  183. data/app/assets/images/payment_icons/spei.svg +1 -0
  184. data/app/assets/images/payment_icons/storecredit.svg +1 -0
  185. data/app/assets/images/payment_icons/stripe.svg +1 -0
  186. data/app/assets/images/payment_icons/sveacheckout.svg +1 -0
  187. data/app/assets/images/payment_icons/swedbank.svg +1 -0
  188. data/app/assets/images/payment_icons/swish.svg +1 -0
  189. data/app/assets/images/payment_icons/tbibank.svg +1 -0
  190. data/app/assets/images/payment_icons/thanachartbank.svg +1 -0
  191. data/app/assets/images/payment_icons/tnmmoney.svg +1 -0
  192. data/app/assets/images/payment_icons/touchngo.svg +1 -0
  193. data/app/assets/images/payment_icons/trustly.svg +1 -0
  194. data/app/assets/images/payment_icons/twint.svg +1 -0
  195. data/app/assets/images/payment_icons/uaevisa.svg +1 -0
  196. data/app/assets/images/payment_icons/unionpay.svg +1 -0
  197. data/app/assets/images/payment_icons/unzerbanktransfer.svg +1 -0
  198. data/app/assets/images/payment_icons/upi.svg +1 -0
  199. data/app/assets/images/payment_icons/usbank.svg +1 -0
  200. data/app/assets/images/payment_icons/usdc.svg +1 -0
  201. data/app/assets/images/payment_icons/usdt.svg +1 -0
  202. data/app/assets/images/payment_icons/venmo.svg +1 -0
  203. data/app/assets/images/payment_icons/vipps.svg +1 -0
  204. data/app/assets/images/payment_icons/visa.svg +1 -0
  205. data/app/assets/images/payment_icons/volksbank.svg +1 -0
  206. data/app/assets/images/payment_icons/waavepaybybank.svg +1 -0
  207. data/app/assets/images/payment_icons/walley.svg +1 -0
  208. data/app/assets/images/payment_icons/wbtc.svg +1 -0
  209. data/app/assets/images/payment_icons/wechatpay.svg +1 -0
  210. data/app/assets/images/payment_icons/whishcheckout.svg +1 -0
  211. data/app/assets/images/payment_icons/wingbank.svg +1 -0
  212. data/app/assets/images/payment_icons/xrp.svg +1 -0
  213. data/app/assets/images/payment_icons/zip.svg +1 -0
  214. data/app/finders/spree/posts/find.rb +137 -0
  215. data/app/helpers/spree/addresses_helper.rb +9 -3
  216. data/app/helpers/spree/base_helper.rb +8 -4
  217. data/app/jobs/spree/images/save_from_url_job.rb +70 -0
  218. data/app/jobs/spree/imports/create_rows_job.rb +72 -0
  219. data/app/jobs/spree/imports/process_rows_job.rb +19 -0
  220. data/app/models/concerns/spree/adjustment_source.rb +3 -3
  221. data/app/models/concerns/spree/admin_user_methods.rb +52 -0
  222. data/app/models/concerns/spree/display_on.rb +7 -1
  223. data/app/models/concerns/spree/has_image_alt_text.rb +18 -0
  224. data/app/models/concerns/spree/has_one_link.rb +1 -1
  225. data/app/models/concerns/spree/has_page_links.rb +1 -1
  226. data/app/models/concerns/spree/linkable.rb +9 -0
  227. data/app/models/concerns/spree/metadata.rb +2 -0
  228. data/app/models/concerns/spree/metafields.rb +94 -0
  229. data/app/models/concerns/spree/named_type.rb +1 -1
  230. data/app/models/concerns/spree/user_methods.rb +20 -7
  231. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  232. data/app/models/concerns/spree/user_roles.rb +3 -2
  233. data/app/models/spree/ability.rb +4 -0
  234. data/app/models/spree/address.rb +3 -1
  235. data/app/models/spree/adjustable/adjuster/tax.rb +2 -2
  236. data/app/models/spree/adjustable/adjustments_updater.rb +26 -3
  237. data/app/models/spree/adjustment.rb +4 -1
  238. data/app/models/spree/asset.rb +16 -0
  239. data/app/models/spree/base.rb +1 -1
  240. data/app/models/spree/credit_card.rb +1 -0
  241. data/app/models/spree/current.rb +5 -1
  242. data/app/models/spree/custom_domain.rb +5 -0
  243. data/app/models/spree/customer_return.rb +1 -0
  244. data/app/models/spree/export.rb +39 -2
  245. data/app/models/spree/exports/customers.rb +17 -0
  246. data/app/models/spree/exports/gift_cards.rb +13 -0
  247. data/app/models/spree/exports/newsletter_subscribers.rb +13 -0
  248. data/app/models/spree/exports/orders.rb +6 -4
  249. data/app/models/spree/exports/products.rb +9 -3
  250. data/app/models/spree/gift_card.rb +7 -1
  251. data/app/models/spree/gift_card_batch.rb +0 -1
  252. data/app/models/spree/import.rb +279 -0
  253. data/app/models/spree/import_mapping.rb +46 -0
  254. data/app/models/spree/import_row.rb +108 -0
  255. data/app/models/spree/import_schema.rb +25 -0
  256. data/app/models/spree/import_schemas/products.rb +45 -0
  257. data/app/models/spree/imports/products.rb +9 -0
  258. data/app/models/spree/invitation.rb +1 -1
  259. data/app/models/spree/legacy_user.rb +0 -1
  260. data/app/models/spree/line_item.rb +2 -7
  261. data/app/models/spree/metafield.rb +53 -0
  262. data/app/models/spree/metafield_definition.rb +91 -0
  263. data/app/models/spree/metafields/boolean.rb +15 -0
  264. data/app/models/spree/metafields/json.rb +27 -0
  265. data/app/models/spree/metafields/long_text.rb +7 -0
  266. data/app/models/spree/metafields/number.rb +15 -0
  267. data/app/models/spree/metafields/rich_text.rb +18 -0
  268. data/app/models/spree/metafields/short_text.rb +7 -0
  269. data/app/models/spree/newsletter_subscriber/emails.rb +12 -0
  270. data/app/models/spree/newsletter_subscriber.rb +64 -0
  271. data/app/models/spree/option_type.rb +2 -0
  272. data/app/models/spree/option_value.rb +1 -0
  273. data/app/models/spree/order/checkout.rb +7 -0
  274. data/app/models/spree/order.rb +8 -3
  275. data/app/models/spree/order_merger.rb +2 -4
  276. data/app/models/spree/order_promotion.rb +3 -0
  277. data/app/models/spree/order_updater.rb +2 -2
  278. data/app/models/spree/page.rb +5 -1
  279. data/app/models/spree/page_block.rb +4 -0
  280. data/app/models/spree/page_blocks/image.rb +3 -0
  281. data/app/models/spree/page_blocks/metafields.rb +18 -0
  282. data/app/models/spree/page_blocks/products/brand.rb +15 -0
  283. data/app/models/spree/page_blocks/products/buy_buttons.rb +5 -1
  284. data/app/models/spree/page_blocks/products/description.rb +18 -0
  285. data/app/models/spree/page_blocks/products/price.rb +1 -1
  286. data/app/models/spree/page_blocks/products/quantity_selector.rb +6 -2
  287. data/app/models/spree/page_blocks/products/title.rb +5 -1
  288. data/app/models/spree/page_blocks/products/variant_picker.rb +1 -1
  289. data/app/models/spree/page_section.rb +2 -2
  290. data/app/models/spree/page_sections/breadcrumbs.rb +12 -0
  291. data/app/models/spree/page_sections/footer.rb +20 -13
  292. data/app/models/spree/page_sections/image_banner.rb +6 -1
  293. data/app/models/spree/page_sections/image_with_text.rb +5 -0
  294. data/app/models/spree/page_sections/newsletter.rb +7 -0
  295. data/app/models/spree/page_sections/product_details.rb +38 -1
  296. data/app/models/spree/pages/account.rb +4 -0
  297. data/app/models/spree/pages/cart.rb +10 -0
  298. data/app/models/spree/pages/checkout.rb +6 -0
  299. data/app/models/spree/pages/custom.rb +4 -0
  300. data/app/models/spree/pages/homepage.rb +4 -0
  301. data/app/models/spree/pages/login.rb +4 -0
  302. data/app/models/spree/pages/password.rb +2 -0
  303. data/app/models/spree/pages/post_list.rb +4 -0
  304. data/app/models/spree/pages/product_details.rb +1 -0
  305. data/app/models/spree/pages/shop_all.rb +4 -0
  306. data/app/models/spree/pages/wishlist.rb +4 -0
  307. data/app/models/spree/payment.rb +1 -0
  308. data/app/models/spree/payment_method.rb +4 -5
  309. data/app/models/spree/payment_source.rb +1 -0
  310. data/app/models/spree/policy.rb +70 -0
  311. data/app/models/spree/post.rb +4 -2
  312. data/app/models/spree/post_category.rb +1 -0
  313. data/app/models/spree/product.rb +16 -9
  314. data/app/models/spree/promotion/actions/free_shipping.rb +3 -3
  315. data/app/models/spree/promotion.rb +24 -8
  316. data/app/models/spree/promotion_action.rb +1 -1
  317. data/app/models/spree/promotion_handler/cart.rb +1 -1
  318. data/app/models/spree/promotion_handler/coupon.rb +1 -1
  319. data/app/models/spree/promotion_rule.rb +1 -1
  320. data/app/models/spree/property.rb +18 -0
  321. data/app/models/spree/refund.rb +2 -1
  322. data/app/models/spree/role_user.rb +1 -1
  323. data/app/models/spree/shipment.rb +1 -0
  324. data/app/models/spree/shipping_method.rb +1 -0
  325. data/app/models/spree/stock_item.rb +1 -0
  326. data/app/models/spree/stock_transfer.rb +1 -0
  327. data/app/models/spree/store.rb +45 -3
  328. data/app/models/spree/store_credit.rb +2 -1
  329. data/app/models/spree/tax_category.rb +1 -1
  330. data/app/models/spree/tax_rate.rb +18 -3
  331. data/app/models/spree/taxon.rb +12 -2
  332. data/app/models/spree/taxonomy.rb +11 -0
  333. data/app/models/spree/theme.rb +1 -1
  334. data/app/models/spree/variant.rb +17 -0
  335. data/app/presenters/spree/csv/customer_presenter.rb +59 -0
  336. data/app/presenters/spree/csv/gift_card_presenter.rb +49 -0
  337. data/app/presenters/spree/csv/metafields_helper.rb +17 -0
  338. data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +39 -0
  339. data/app/presenters/spree/csv/order_line_item_presenter.rb +12 -5
  340. data/app/presenters/spree/csv/product_variant_presenter.rb +9 -5
  341. data/app/services/spree/cart/recalculate.rb +6 -4
  342. data/app/services/spree/cart/remove_line_item.rb +1 -2
  343. data/app/services/spree/imports/row_processors/base.rb +19 -0
  344. data/app/services/spree/imports/row_processors/product_variant.rb +228 -0
  345. data/app/services/spree/line_items/destroy.rb +1 -1
  346. data/app/services/spree/newsletter/subscribe.rb +43 -0
  347. data/app/services/spree/newsletter/verify.rb +30 -0
  348. data/app/sorters/spree/posts/sort.rb +40 -0
  349. data/app/views/spree/shared/_payment.html.erb +3 -3
  350. data/config/locales/en.yml +56 -2
  351. data/db/migrate/20250605131334_add_missing_fields_to_users.rb +23 -13
  352. data/db/migrate/20250728095629_create_spree_metafields.rb +27 -0
  353. data/db/migrate/20250730102644_add_missing_unique_indexes_to_spree_option_types_and_values.rb +40 -0
  354. data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +24 -0
  355. data/db/migrate/20250811112056_create_spree_policies.rb +22 -0
  356. data/db/migrate/20250821211705_fix_unique_index_on_spree_order_promotions.rb +20 -0
  357. data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +7 -0
  358. data/db/migrate/20250826093602_create_spree_newsletter_subscribers.rb +12 -0
  359. data/db/migrate/20250902143122_fix_policies_store_association.rb +18 -0
  360. data/db/migrate/20250911205659_add_missing_index_on_spree_products_promotionable.rb +5 -0
  361. data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +10 -0
  362. data/db/migrate/20250914101955_add_missing_indexes_on_spree_adjustments.rb +6 -0
  363. data/db/migrate/20250915093930_add_metadata_to_spree_newsletter_subscribers.rb +20 -0
  364. data/db/migrate/20250923141845_create_spree_imports.rb +47 -0
  365. data/lib/generators/spree/cursor_rules/cursor_rules_generator.rb +19 -0
  366. data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +387 -0
  367. data/lib/generators/spree/dummy/dummy_generator.rb +0 -1
  368. data/lib/generators/spree/install/templates/config/initializers/spree.rb +5 -0
  369. data/lib/spree/core/configuration.rb +1 -0
  370. data/lib/spree/core/dependencies.rb +3 -0
  371. data/lib/spree/core/engine.rb +57 -2
  372. data/lib/spree/core/version.rb +1 -1
  373. data/lib/spree/core.rb +3 -1
  374. data/lib/spree/permitted_attributes.rb +18 -3
  375. data/lib/spree/testing_support/capybara_config.rb +9 -3
  376. data/lib/spree/testing_support/factories/export_factory.rb +5 -17
  377. data/lib/spree/testing_support/factories/import_factory.rb +20 -0
  378. data/lib/spree/testing_support/factories/import_mapping_factory.rb +7 -0
  379. data/lib/spree/testing_support/factories/import_row_factory.rb +7 -0
  380. data/lib/spree/testing_support/factories/metafield_definition_factory.rb +72 -0
  381. data/lib/spree/testing_support/factories/metafield_factory.rb +68 -0
  382. data/lib/spree/testing_support/factories/newsletter_subscriber_factory.rb +18 -0
  383. data/lib/spree/testing_support/factories/policy_factory.rb +8 -0
  384. data/lib/spree/testing_support/factories/post_factory.rb +8 -0
  385. data/lib/spree/testing_support/store.rb +11 -0
  386. data/lib/tasks/core.rake +128 -0
  387. metadata +279 -6
  388. data/app/models/action_text/rich_text_decorator.rb +0 -11
  389. data/app/presenters/spree/csv/product_presenter.rb +0 -63
@@ -1,12 +1,15 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class ImageBanner < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
4
6
  TOP_PADDING_DEFAULT = 0
5
7
  BOTTOM_PADDING_DEFAULT = 0
6
8
 
7
9
  preference :overlay_transparency, :integer, default: 40
8
10
  preference :height, :integer, default: 384
9
11
  preference :vertical_alignment, :string, default: :middle
12
+ preference :image_alt, :string
10
13
 
11
14
  def default_blocks
12
15
  [
@@ -45,6 +48,8 @@ module Spree
45
48
  def icon_name
46
49
  'slideshow'
47
50
  end
51
+
52
+
48
53
  end
49
54
  end
50
- end
55
+ end
@@ -1,11 +1,14 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class ImageWithText < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
4
6
  TOP_PADDING_DEFAULT = 16
5
7
  BOTTOM_PADDING_DEFAULT = 16
6
8
 
7
9
  preference :desktop_image_alignment, :string, default: 'right'
8
10
  preference :vertical_alignment, :string, default: :middle
11
+ preference :image_alt, :string
9
12
 
10
13
  has_one :link, ->(ps) { ps.links }, class_name: 'Spree::PageLink', as: :parent, dependent: :destroy, inverse_of: :parent
11
14
  accepts_nested_attributes_for :link
@@ -55,6 +58,8 @@ module Spree
55
58
  def icon_name
56
59
  'photo'
57
60
  end
61
+
62
+
58
63
  end
59
64
  end
60
65
  end
@@ -1,7 +1,10 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class Newsletter < Spree::PageSection
4
+ include Spree::HasImageAltText
5
+
4
6
  preference :overlay_transparency, :integer, default: 40
7
+ preference :image_alt, :string
5
8
 
6
9
  def default_blocks
7
10
  @default_blocks.presence || [
@@ -27,6 +30,10 @@ module Spree
27
30
  'footer'
28
31
  end
29
32
 
33
+ def lazy?
34
+ !Rails.env.test?
35
+ end
36
+
30
37
  def blocks_available?
31
38
  true
32
39
  end
@@ -1,7 +1,8 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class ProductDetails < Spree::PageSection
4
- TOP_PADDING_DEFAULT = 20
4
+ TOP_BORDER_WIDTH_DEFAULT = 0
5
+ TOP_PADDING_DEFAULT = 0
5
6
  BOTTOM_PADDING_DEFAULT = 40
6
7
 
7
8
  def icon_name
@@ -11,6 +12,42 @@ module Spree
11
12
  def self.role
12
13
  'system'
13
14
  end
15
+
16
+ def default_blocks
17
+ product_metafield_definition_ids = Spree::MetafieldDefinition.where(resource_type: 'Spree::Product').ids
18
+
19
+ [
20
+ Spree::PageBlocks::Products::Brand.new,
21
+ Spree::PageBlocks::Products::Title.new,
22
+ Spree::PageBlocks::Products::Price.new(text: Spree.t(:price), preferred_text_alignment: 'left'),
23
+ Spree::PageBlocks::Products::VariantPicker.new,
24
+ Spree::PageBlocks::Products::QuantitySelector.new,
25
+ Spree::PageBlocks::Products::BuyButtons.new,
26
+ Spree::PageBlocks::Products::Description.new,
27
+ Spree::PageBlocks::Metafields.new(preferred_metafield_definition_ids: product_metafield_definition_ids),
28
+ ]
29
+ end
30
+
31
+ def blocks_available?
32
+ true
33
+ end
34
+
35
+ def can_sort_blocks?
36
+ true
37
+ end
38
+
39
+ def available_blocks_to_add
40
+ [
41
+ Spree::PageBlocks::Products::Brand,
42
+ Spree::PageBlocks::Products::Title,
43
+ Spree::PageBlocks::Products::Price,
44
+ Spree::PageBlocks::Products::VariantPicker,
45
+ Spree::PageBlocks::Products::QuantitySelector,
46
+ Spree::PageBlocks::Products::BuyButtons,
47
+ Spree::PageBlocks::Products::Description,
48
+ Spree::PageBlocks::Metafields,
49
+ ]
50
+ end
14
51
  end
15
52
  end
16
53
  end
@@ -10,6 +10,10 @@ module Spree
10
10
  def icon_name
11
11
  'user'
12
12
  end
13
+
14
+ def linkable?
15
+ true
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,9 +1,19 @@
1
1
  module Spree
2
2
  module Pages
3
3
  class Cart < Spree::Page
4
+ def page_builder_url
5
+ return unless page_builder_url_exists?(:cart_path)
6
+
7
+ Spree::Core::Engine.routes.url_helpers.cart_path
8
+ end
9
+
4
10
  def icon_name
5
11
  'shopping-cart'
6
12
  end
13
+
14
+ def linkable?
15
+ true
16
+ end
7
17
  end
8
18
  end
9
19
  end
@@ -1,6 +1,12 @@
1
1
  module Spree
2
2
  module Pages
3
3
  class Checkout < Spree::Page
4
+ def page_builder_url
5
+ return unless page_builder_url_exists?(:checkout_path)
6
+
7
+ Spree::Core::Engine.routes.url_helpers.checkout_path
8
+ end
9
+
4
10
  def icon_name
5
11
  'credit-card'
6
12
  end
@@ -5,6 +5,10 @@ module Spree
5
5
  true
6
6
  end
7
7
 
8
+ def linkable?
9
+ true
10
+ end
11
+
8
12
  def page_builder_url
9
13
  return unless page_builder_url_exists?(:page_path)
10
14
 
@@ -11,6 +11,10 @@ module Spree
11
11
  'home'
12
12
  end
13
13
 
14
+ def linkable?
15
+ true
16
+ end
17
+
14
18
  def default_sections
15
19
  sections = [
16
20
  Spree::PageSections::ImageWithText.new(
@@ -10,6 +10,10 @@ module Spree
10
10
 
11
11
  Spree::Core::Engine.routes.url_helpers.login_path
12
12
  end
13
+
14
+ def linkable?
15
+ true
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -2,6 +2,8 @@ module Spree
2
2
  module Pages
3
3
  class Password < Spree::Page
4
4
  def page_builder_url
5
+ return unless page_builder_url_exists?(:password_path)
6
+
5
7
  Spree::Core::Engine.routes.url_helpers.password_path
6
8
  end
7
9
 
@@ -27,6 +27,10 @@ module Spree
27
27
  def customizable?
28
28
  true
29
29
  end
30
+
31
+ def linkable?
32
+ true
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -16,6 +16,7 @@ module Spree
16
16
 
17
17
  def default_sections
18
18
  [
19
+ Spree::PageSections::Breadcrumbs.new,
19
20
  Spree::PageSections::ProductDetails.new,
20
21
  Spree::PageSections::RelatedProducts.new
21
22
  ]
@@ -31,6 +31,10 @@ module Spree
31
31
  def customizable?
32
32
  true
33
33
  end
34
+
35
+ def linkable?
36
+ true
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -6,6 +6,10 @@ module Spree
6
6
 
7
7
  Spree::Core::Engine.routes.url_helpers.account_wishlist_path
8
8
  end
9
+
10
+ def linkable?
11
+ true
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -5,6 +5,7 @@ module Spree
5
5
  include Spree::Core::NumberGenerator.new(prefix: 'P', letters: true, length: 7)
6
6
  include Spree::NumberIdentifier
7
7
  include Spree::NumberAsParam
8
+ include Spree::Metafields
8
9
  include Spree::Metadata
9
10
  if defined?(Spree::Security::Payments)
10
11
  include Spree::Security::Payments
@@ -4,6 +4,7 @@ module Spree
4
4
  acts_as_list
5
5
 
6
6
  include Spree::MultiStoreResource
7
+ include Spree::Metafields
7
8
  include Spree::Metadata
8
9
  include Spree::DisplayOn
9
10
  if defined?(Spree::Security::PaymentMethods)
@@ -22,12 +23,10 @@ module Spree
22
23
  has_many :store_payment_methods, class_name: 'Spree::StorePaymentMethod'
23
24
  has_many :stores, class_name: 'Spree::Store', through: :store_payment_methods
24
25
 
25
- with_options dependent: :restrict_with_error do
26
- has_many :payments, class_name: 'Spree::Payment', inverse_of: :payment_method
27
- has_many :credit_cards, class_name: 'Spree::CreditCard'
28
- end
26
+ has_many :payments, class_name: 'Spree::Payment', inverse_of: :payment_method, dependent: :nullify
27
+ has_many :credit_cards, class_name: 'Spree::CreditCard', dependent: :destroy # CCs are soft deleted
29
28
 
30
- has_many :gateway_customers, class_name: 'Spree::GatewayCustomer'
29
+ has_many :gateway_customers, class_name: 'Spree::GatewayCustomer', dependent: :destroy
31
30
 
32
31
  def self.providers
33
32
  Rails.application.config.spree.payment_methods
@@ -1,6 +1,7 @@
1
1
  # This model is used to store payment sources for non-credit card payments, eg wallet, account, etc.
2
2
  module Spree
3
3
  class PaymentSource < Spree.base_class
4
+ include Spree::Metafields
4
5
  include Spree::Metadata
5
6
  include Spree::PaymentSourceConcern
6
7
 
@@ -0,0 +1,70 @@
1
+ module Spree
2
+ class Policy < Spree.base_class
3
+ extend FriendlyId
4
+ include Spree::TranslatableResource
5
+ include Spree::Linkable
6
+
7
+ UNIQUENESS_SCOPE = %i[owner_id owner_type].freeze
8
+
9
+ #
10
+ # FriendlyId
11
+ #
12
+ friendly_id :slug_candidates, use: %i[slugged scoped history], scope: UNIQUENESS_SCOPE
13
+
14
+ #
15
+ # Associations
16
+ #
17
+ belongs_to :owner, polymorphic: true, touch: true # can be a store or a vendor or organization
18
+
19
+ #
20
+ # Translations
21
+ #
22
+ TRANSLATABLE_FIELDS = %i[name body].freeze
23
+ translates(*TRANSLATABLE_FIELDS, column_fallback: !Spree.always_use_translations?)
24
+
25
+ #
26
+ # ActionText
27
+ #
28
+ translates :body, backend: :action_text
29
+
30
+ #
31
+ # Validations
32
+ #
33
+ validates :slug, presence: true, uniqueness: { scope: UNIQUENESS_SCOPE }
34
+ validates :name, presence: true
35
+ validates :owner, presence: true
36
+
37
+ #
38
+ # Scopes
39
+ #
40
+ scope :with_body, -> { joins(:rich_text_body).distinct }
41
+ scope :without_body, -> { where.missing(:rich_text_body) }
42
+
43
+ #
44
+ # Ransack
45
+ #
46
+ self.whitelisted_ransackable_attributes = %w[name owner_type owner_id]
47
+
48
+ before_destroy :really_destroy_slugs!
49
+
50
+ # For policies, store.policies returns all policies owned by the store
51
+ # We don't want to filter out other policies in requests that use `for_store` when they have a different owner type
52
+ def self.for_store(store)
53
+ store.policies.or(where.not(owner_type: 'Spree::Store'))
54
+ end
55
+
56
+ def page_builder_url
57
+ return unless Spree::Core::Engine.routes.url_helpers.respond_to?(:policy_path)
58
+
59
+ Spree::Core::Engine.routes.url_helpers.policy_path(self)
60
+ end
61
+
62
+ def with_body?
63
+ body.present?
64
+ end
65
+
66
+ def really_destroy_slugs!
67
+ slugs.with_deleted.each(&:really_destroy!)
68
+ end
69
+ end
70
+ end
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  class Post < Spree.base_class
3
3
  include Spree::SingleStoreResource
4
+ include Spree::Linkable
5
+ include Spree::Metafields
4
6
  extend FriendlyId
5
7
 
6
8
  friendly_id :slug_candidates, use: %i[slugged scoped history], scope: %i[store_id deleted?]
@@ -36,7 +38,7 @@ module Spree
36
38
  #
37
39
  # Associations
38
40
  #
39
- belongs_to :author, class_name: Spree.admin_user_class.to_s
41
+ belongs_to :author, class_name: Spree.admin_user_class.to_s, optional: true
40
42
  belongs_to :store, class_name: 'Spree::Store'
41
43
  belongs_to :post_category, class_name: 'Spree::PostCategory', optional: true
42
44
  alias category post_category
@@ -44,7 +46,7 @@ module Spree
44
46
  #
45
47
  # Validations
46
48
  #
47
- validates :title, :store, :author, presence: true
49
+ validates :title, :store, presence: true
48
50
  validates :slug, presence: true, uniqueness: { scope: :store_id, conditions: -> { where(deleted_at: nil) } }
49
51
  validates :meta_title, length: { maximum: 160 }, allow_blank: true
50
52
  validates :meta_description, length: { maximum: 320 }, allow_blank: true
@@ -1,6 +1,7 @@
1
1
  module Spree
2
2
  class PostCategory < Spree.base_class
3
3
  include Spree::SingleStoreResource
4
+ include Spree::Metafields
4
5
  extend FriendlyId
5
6
 
6
7
  friendly_id :slug_candidates, use: %i[slugged scoped history], scope: %i[store_id]
@@ -28,7 +28,9 @@ module Spree
28
28
  include Spree::MultiStoreResource
29
29
  include Spree::TranslatableResource
30
30
  include Spree::MemoizedData
31
+ include Spree::Metafields
31
32
  include Spree::Metadata
33
+ include Spree::Linkable
32
34
  include Spree::Product::Webhooks
33
35
  include Spree::Product::Slugs
34
36
  if defined?(Spree::VendorConcern)
@@ -118,8 +120,6 @@ module Spree
118
120
  has_many :stores, through: :store_products, class_name: 'Spree::Store'
119
121
  has_many :digitals, through: :variants_including_master
120
122
 
121
- has_many :page_links, as: :linkable, class_name: 'Spree::PageLink', dependent: :destroy
122
-
123
123
  after_initialize :ensure_master
124
124
  after_initialize :assign_default_tax_category
125
125
 
@@ -618,11 +618,18 @@ module Spree
618
618
 
619
619
  def to_csv(store = nil)
620
620
  store ||= stores.default || stores.first
621
- properties_for_csv ||= Spree::Property.order(:position).flat_map do |property|
622
- [
623
- property.name,
624
- product_properties.find { |pp| pp.property_id == property.id }&.value
625
- ]
621
+ properties_for_csv = if Spree::Config[:product_properties_enabled]
622
+ Spree::Property.order(:position).flat_map do |property|
623
+ [
624
+ property.name,
625
+ product_properties.find { |pp| pp.property_id == property.id }&.value
626
+ ]
627
+ end
628
+ else
629
+ []
630
+ end
631
+ metafields_for_csv ||= Spree::MetafieldDefinition.for_resource_type('Spree::Product').order(:namespace, :key).map do |mf_def|
632
+ metafields.find { |mf| mf.metafield_definition_id == mf_def.id }&.csv_value
626
633
  end
627
634
  taxons_for_csv ||= taxons.manual.reorder(depth: :desc).first(3).pluck(:pretty_name)
628
635
  taxons_for_csv.fill(nil, taxons_for_csv.size...3)
@@ -631,10 +638,10 @@ module Spree
631
638
 
632
639
  if has_variants?
633
640
  variants_including_master.each_with_index do |variant, index|
634
- csv_lines << Spree::CSV::ProductVariantPresenter.new(self, variant, index, properties_for_csv, taxons_for_csv, store).call
641
+ csv_lines << Spree::CSV::ProductVariantPresenter.new(self, variant, index, properties_for_csv, taxons_for_csv, store, metafields_for_csv).call
635
642
  end
636
643
  else
637
- csv_lines << Spree::CSV::ProductVariantPresenter.new(self, master, 0, properties_for_csv, taxons_for_csv, store).call
644
+ csv_lines << Spree::CSV::ProductVariantPresenter.new(self, master, 0, properties_for_csv, taxons_for_csv, store, metafields_for_csv).call
638
645
  end
639
646
 
640
647
  csv_lines
@@ -18,12 +18,12 @@ module Spree
18
18
  def create_adjustment(order, adjustable, included = false)
19
19
  amount = compute_amount(adjustable)
20
20
 
21
- adjustments.new(
22
- adjustable: adjustable,
21
+ adjustable.adjustments.new(
23
22
  amount: amount,
24
23
  included: included,
25
24
  label: label,
26
- order: order
25
+ order: order,
26
+ source: self
27
27
  ).save
28
28
  end
29
29
  end
@@ -1,6 +1,7 @@
1
1
  module Spree
2
2
  class Promotion < Spree.base_class
3
3
  include Spree::MultiStoreResource
4
+ include Spree::Metafields
4
5
  include Spree::Metadata
5
6
  if defined?(Spree::Webhooks::HasWebhooks)
6
7
  include Spree::Webhooks::HasWebhooks
@@ -49,7 +50,7 @@ module Spree
49
50
  before_validation :downcase_code, if: -> { code.present? }
50
51
  before_validation :set_starts_at_to_current_time, if: -> { starts_at.blank? }
51
52
  after_commit :generate_coupon_codes, if: -> { multi_codes? }, on: [:create, :update]
52
- after_commit :remove_coupons, unless: -> { multi_codes? }, on: :update
53
+ after_commit :remove_coupons, on: :update
53
54
  before_destroy :not_used?
54
55
 
55
56
  #
@@ -147,8 +148,8 @@ module Spree
147
148
  if action_taken
148
149
  # connect to the order
149
150
  # create the join_table entry.
150
- orders << order
151
- save
151
+ order.promotions << self unless order.promotions.include?(self)
152
+ order.save
152
153
  end
153
154
 
154
155
  action_taken
@@ -174,8 +175,8 @@ module Spree
174
175
  if action_taken
175
176
  # connect to the order
176
177
  # create the join_table entry.
177
- orders << order
178
- save
178
+ order.promotions << self unless order.promotions.include?(self)
179
+ order.save
179
180
  end
180
181
 
181
182
  action_taken
@@ -188,14 +189,26 @@ module Spree
188
189
  !!eligible_rules(promotable, options)
189
190
  end
190
191
 
192
+ # We cache the rules to avoid multiple database queries
193
+ # this is useful for orders with many line items
194
+ #
195
+ # @return [Array<Spree::PromotionRule>]
196
+ def cached_rules
197
+ Rails.cache.fetch("#{cache_key_with_version}/rules") do
198
+ rules.to_a
199
+ end
200
+ rescue TypeError # when using null_store in test environment
201
+ rules.to_a
202
+ end
203
+
191
204
  # eligible_rules returns an array of promotion rules where eligible? is true for the promotable
192
205
  # if there are no such rules, an empty array is returned
193
206
  # if the rules make this promotable ineligible, then nil is returned (i.e. this promotable is not eligible)
194
207
  def eligible_rules(promotable, options = {})
195
208
  # Promotions without rules are eligible by default.
196
- return [] if rules.none?
209
+ return [] if cached_rules.none?
197
210
 
198
- specific_rules = rules.select { |rule| rule.applicable?(promotable) }
211
+ specific_rules = cached_rules.select { |rule| rule.applicable?(promotable) }
199
212
  return [] if specific_rules.none?
200
213
 
201
214
  rule_eligibility = Hash[specific_rules.map do |rule|
@@ -329,6 +342,9 @@ module Spree
329
342
  end
330
343
 
331
344
  def remove_coupons
345
+ return unless (previous_changes.key?('kind') && previous_changes['kind'][0] == 'coupon_code' && kind == 'automatic') ||
346
+ (previous_changes.key?('multi_codes') && previous_changes['multi_codes'][0] == true && multi_codes == false)
347
+
332
348
  coupon_codes.where(deleted_at: nil).update_all(deleted_at: Time.current)
333
349
  end
334
350
 
@@ -337,7 +353,7 @@ module Spree
337
353
  when Spree::LineItem
338
354
  !promotable.product.promotionable?
339
355
  when Spree::Order
340
- promotable.line_items.any? &&
356
+ (promotable.item_count.positive? || promotable.line_items.any?) &&
341
357
  promotable.line_items.joins(:product).where(spree_products: { promotionable: true }).none?
342
358
  end
343
359
  end
@@ -4,7 +4,7 @@ module Spree
4
4
  class PromotionAction < Spree.base_class
5
5
  acts_as_paranoid
6
6
 
7
- belongs_to :promotion, class_name: 'Spree::Promotion'
7
+ belongs_to :promotion, class_name: 'Spree::Promotion', touch: true
8
8
 
9
9
  validates :promotion, :type, presence: true
10
10
 
@@ -39,7 +39,7 @@ module Spree
39
39
  end
40
40
 
41
41
  def promotion_scope
42
- ::Spree::Promotion.for_store(store)
42
+ store.promotions
43
43
  end
44
44
  end
45
45
  end
@@ -62,7 +62,7 @@ module Spree
62
62
  promotion = order.promotions.with_coupon_code(coupon_code)
63
63
  if promotion.present?
64
64
  # Order promotion has to be destroyed before line item removing
65
- order.order_promotions.where(promotion_id: promotion.id).destroy_all
65
+ order.promotions.delete(promotion)
66
66
 
67
67
  if promotion.multi_codes?
68
68
  coupon_code = promotion.coupon_codes.find_by(order: order)
@@ -1,7 +1,7 @@
1
1
  # Base class for all promotion rules
2
2
  module Spree
3
3
  class PromotionRule < Spree.base_class
4
- belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules
4
+ belongs_to :promotion, class_name: 'Spree::Promotion', inverse_of: :promotion_rules, touch: true
5
5
 
6
6
  delegate :stores, to: :promotion
7
7
 
@@ -3,6 +3,7 @@ module Spree
3
3
  include Spree::FilterParam
4
4
  include Spree::Metadata
5
5
  include Spree::ParameterizableName
6
+ include Spree::UniqueName
6
7
  include Spree::DisplayOn
7
8
  include Spree::TranslatableResource
8
9
  if defined?(Spree::Webhooks::HasWebhooks)
@@ -49,6 +50,23 @@ module Spree
49
50
  end
50
51
  end
51
52
 
53
+ # Returns the metafield type for the property kind
54
+ # @return [String] eg. 'Spree::Metafields::ShortText'
55
+ def kind_to_metafield_type
56
+ case kind
57
+ when 'short_text'
58
+ 'Spree::Metafields::ShortText'
59
+ when 'long_text'
60
+ 'Spree::Metafields::LongText'
61
+ when 'number'
62
+ 'Spree::Metafields::Number'
63
+ when 'rich_text'
64
+ 'Spree::Metafields::RichText'
65
+ else
66
+ 'Spree::Metafields::ShortText'
67
+ end
68
+ end
69
+
52
70
  private
53
71
 
54
72
  def touch_all_products
@@ -1,5 +1,6 @@
1
1
  module Spree
2
2
  class Refund < Spree.base_class
3
+ include Spree::Metafields
3
4
  include Spree::Metadata
4
5
  if defined?(Spree::Webhooks::HasWebhooks)
5
6
  include Spree::Webhooks::HasWebhooks
@@ -13,7 +14,7 @@ module Spree
13
14
  belongs_to :reimbursement, optional: true
14
15
  end
15
16
  belongs_to :reason, class_name: 'Spree::RefundReason', foreign_key: :refund_reason_id
16
- belongs_to :refunder, class_name: "::#{Spree.admin_user_class}", optional: true
17
+ belongs_to :refunder, class_name: Spree.admin_user_class.to_s, optional: true
17
18
 
18
19
  has_many :log_entries, as: :source
19
20
 
@@ -6,7 +6,7 @@ module Spree
6
6
  belongs_to :role, class_name: 'Spree::Role', foreign_key: :role_id
7
7
  belongs_to :user, polymorphic: true
8
8
  belongs_to :resource, polymorphic: true
9
- belongs_to :invitation, class_name: 'Spree::Invitation', optional: true
9
+ belongs_to :invitation, class_name: 'Spree::Invitation', optional: true, inverse_of: :role_user
10
10
 
11
11
  #
12
12
  # Validations