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.
- checksums.yaml +4 -4
- data/app/assets/images/payment_icons/ach.svg +1 -0
- data/app/assets/images/payment_icons/achdirectdebit.svg +1 -0
- data/app/assets/images/payment_icons/ada.svg +1 -0
- data/app/assets/images/payment_icons/adyen.svg +1 -0
- data/app/assets/images/payment_icons/affinbank.svg +1 -0
- data/app/assets/images/payment_icons/affirm.svg +1 -0
- data/app/assets/images/payment_icons/afterpay.svg +1 -0
- data/app/assets/images/payment_icons/airtel_money.svg +1 -0
- data/app/assets/images/payment_icons/airteltigo_mobile_money.svg +1 -0
- data/app/assets/images/payment_icons/alandsbanken.svg +1 -0
- data/app/assets/images/payment_icons/alipay.svg +1 -0
- data/app/assets/images/payment_icons/alipay_hk.svg +1 -0
- data/app/assets/images/payment_icons/alliancebank.svg +1 -0
- data/app/assets/images/payment_icons/alma.svg +1 -0
- data/app/assets/images/payment_icons/amazon.svg +1 -0
- data/app/assets/images/payment_icons/ambank.svg +1 -0
- data/app/assets/images/payment_icons/american_express.svg +1 -0
- data/app/assets/images/payment_icons/apecoin.svg +1 -0
- data/app/assets/images/payment_icons/apple_pay.svg +1 -0
- data/app/assets/images/payment_icons/arbitrum.svg +1 -0
- data/app/assets/images/payment_icons/atome.svg +1 -0
- data/app/assets/images/payment_icons/authorizenet.svg +1 -0
- data/app/assets/images/payment_icons/avalanche.svg +1 -0
- data/app/assets/images/payment_icons/bacs.svg +1 -0
- data/app/assets/images/payment_icons/bancontact.svg +1 -0
- data/app/assets/images/payment_icons/bangkokbank.svg +1 -0
- data/app/assets/images/payment_icons/bankislam.svg +1 -0
- data/app/assets/images/payment_icons/bankmuamalat.svg +1 -0
- data/app/assets/images/payment_icons/bankofamerica.svg +1 -0
- data/app/assets/images/payment_icons/bankrakyat.svg +1 -0
- data/app/assets/images/payment_icons/base.svg +1 -0
- data/app/assets/images/payment_icons/becs.svg +1 -0
- data/app/assets/images/payment_icons/benefit.svg +1 -0
- data/app/assets/images/payment_icons/billie.svg +1 -0
- data/app/assets/images/payment_icons/bitcoin.svg +1 -0
- data/app/assets/images/payment_icons/bitcoin_cash.svg +1 -0
- data/app/assets/images/payment_icons/bizum.svg +1 -0
- data/app/assets/images/payment_icons/blik.svg +1 -0
- data/app/assets/images/payment_icons/bnbchain.svg +1 -0
- data/app/assets/images/payment_icons/bogus.svg +1 -0
- data/app/assets/images/payment_icons/bogus_app_coin.svg +1 -0
- data/app/assets/images/payment_icons/boleto.svg +1 -0
- data/app/assets/images/payment_icons/boost.svg +1 -0
- data/app/assets/images/payment_icons/braintree.svg +1 -0
- data/app/assets/images/payment_icons/buckaroopaybybank.svg +1 -0
- data/app/assets/images/payment_icons/busd.svg +1 -0
- data/app/assets/images/payment_icons/cartes_bancaires.svg +1 -0
- data/app/assets/images/payment_icons/cash.svg +1 -0
- data/app/assets/images/payment_icons/cashappafterpay.svg +1 -0
- data/app/assets/images/payment_icons/cashapppay.svg +1 -0
- data/app/assets/images/payment_icons/checkout_finance.svg +1 -0
- data/app/assets/images/payment_icons/chinabank.svg +1 -0
- data/app/assets/images/payment_icons/clearpay.svg +1 -0
- data/app/assets/images/payment_icons/collector_bank.svg +1 -0
- data/app/assets/images/payment_icons/dai.svg +1 -0
- data/app/assets/images/payment_icons/dana.svg +1 -0
- data/app/assets/images/payment_icons/dankort.svg +1 -0
- data/app/assets/images/payment_icons/danske_bank.svg +1 -0
- data/app/assets/images/payment_icons/deutschebank.svg +1 -0
- data/app/assets/images/payment_icons/diners_club.svg +1 -0
- data/app/assets/images/payment_icons/directbanktransferlatinamerica.svg +1 -0
- data/app/assets/images/payment_icons/discover.svg +1 -0
- data/app/assets/images/payment_icons/dogecoin.svg +1 -0
- data/app/assets/images/payment_icons/duitnow.svg +1 -0
- data/app/assets/images/payment_icons/eft_secure.svg +1 -0
- data/app/assets/images/payment_icons/eftpos_au.svg +1 -0
- data/app/assets/images/payment_icons/eftposau.svg +1 -0
- data/app/assets/images/payment_icons/elo.svg +1 -0
- data/app/assets/images/payment_icons/eos.svg +1 -0
- data/app/assets/images/payment_icons/eps.svg +1 -0
- data/app/assets/images/payment_icons/ethereum.svg +1 -0
- data/app/assets/images/payment_icons/eurobonuscheckout.svg +1 -0
- data/app/assets/images/payment_icons/ezcash.svg +1 -0
- data/app/assets/images/payment_icons/fantom.svg +1 -0
- data/app/assets/images/payment_icons/fpx.svg +1 -0
- data/app/assets/images/payment_icons/gcash.svg +1 -0
- data/app/assets/images/payment_icons/generic.svg +1 -0
- data/app/assets/images/payment_icons/genericbank.svg +1 -0
- data/app/assets/images/payment_icons/gift-card.svg +1 -0
- data/app/assets/images/payment_icons/giropay.svg +1 -0
- data/app/assets/images/payment_icons/glbepaypal.svg +1 -0
- data/app/assets/images/payment_icons/gmobanktransfer.svg +1 -0
- data/app/assets/images/payment_icons/gnosis.svg +1 -0
- data/app/assets/images/payment_icons/google_pay.svg +1 -0
- data/app/assets/images/payment_icons/google_wallet.svg +1 -0
- data/app/assets/images/payment_icons/gopay.svg +1 -0
- data/app/assets/images/payment_icons/grabpay.svg +1 -0
- data/app/assets/images/payment_icons/gusd.svg +1 -0
- data/app/assets/images/payment_icons/handelsbanken.svg +1 -0
- data/app/assets/images/payment_icons/hongleongbank.svg +1 -0
- data/app/assets/images/payment_icons/hypercard.svg +1 -0
- data/app/assets/images/payment_icons/hypercash.svg +1 -0
- data/app/assets/images/payment_icons/ideal.svg +1 -0
- data/app/assets/images/payment_icons/in3viaideal.svg +1 -0
- data/app/assets/images/payment_icons/inbank.svg +1 -0
- data/app/assets/images/payment_icons/jcb.svg +1 -0
- data/app/assets/images/payment_icons/kakao_pay.svg +1 -0
- data/app/assets/images/payment_icons/kasikornbank.svg +1 -0
- data/app/assets/images/payment_icons/klarna-pay-later.svg +1 -0
- data/app/assets/images/payment_icons/klarna-pay-now.svg +1 -0
- data/app/assets/images/payment_icons/klarna-slice-it.svg +1 -0
- data/app/assets/images/payment_icons/klarna.svg +1 -0
- data/app/assets/images/payment_icons/knet.svg +1 -0
- data/app/assets/images/payment_icons/krungthaibank.svg +1 -0
- data/app/assets/images/payment_icons/landbank.svg +1 -0
- data/app/assets/images/payment_icons/laybuybyklarna.svg +1 -0
- data/app/assets/images/payment_icons/litecoin.svg +1 -0
- data/app/assets/images/payment_icons/lunchcheck.svg +1 -0
- data/app/assets/images/payment_icons/mach.svg +1 -0
- data/app/assets/images/payment_icons/mada.svg +1 -0
- data/app/assets/images/payment_icons/maestro.svg +1 -0
- data/app/assets/images/payment_icons/master.svg +1 -0
- data/app/assets/images/payment_icons/mayabank.svg +1 -0
- data/app/assets/images/payment_icons/maybank.svg +1 -0
- data/app/assets/images/payment_icons/maybankm2u.svg +1 -0
- data/app/assets/images/payment_icons/maybankqrpay.svg +1 -0
- data/app/assets/images/payment_icons/mbway.svg +1 -0
- data/app/assets/images/payment_icons/mcash.svg +1 -0
- data/app/assets/images/payment_icons/medicinosbankas.svg +1 -0
- data/app/assets/images/payment_icons/mercadopago.svg +1 -0
- data/app/assets/images/payment_icons/metrobank.svg +1 -0
- data/app/assets/images/payment_icons/mobilepay.svg +1 -0
- data/app/assets/images/payment_icons/momopay.svg +1 -0
- data/app/assets/images/payment_icons/monero.svg +1 -0
- data/app/assets/images/payment_icons/mtn_mobile_money.svg +1 -0
- data/app/assets/images/payment_icons/mybank.svg +1 -0
- data/app/assets/images/payment_icons/naver_pay.svg +1 -0
- data/app/assets/images/payment_icons/nelo.svg +1 -0
- data/app/assets/images/payment_icons/netbanking.svg +1 -0
- data/app/assets/images/payment_icons/novalnetdirectdebitach.svg +1 -0
- data/app/assets/images/payment_icons/nubank.svg +1 -0
- data/app/assets/images/payment_icons/ocbcbank.svg +1 -0
- data/app/assets/images/payment_icons/offlinebanktransferlatinamerica.svg +1 -0
- data/app/assets/images/payment_icons/ola_money.svg +1 -0
- data/app/assets/images/payment_icons/oney.svg +1 -0
- data/app/assets/images/payment_icons/onlinebanking.svg +1 -0
- data/app/assets/images/payment_icons/onlinebanktransfer.svg +1 -0
- data/app/assets/images/payment_icons/orangemobilemoney.svg +1 -0
- data/app/assets/images/payment_icons/otpbank.svg +1 -0
- data/app/assets/images/payment_icons/oxxo.svg +1 -0
- data/app/assets/images/payment_icons/paybybank.svg +1 -0
- data/app/assets/images/payment_icons/paybybankmollie.svg +1 -0
- data/app/assets/images/payment_icons/paybybankus.svg +1 -0
- data/app/assets/images/payment_icons/paycash.svg +1 -0
- data/app/assets/images/payment_icons/payco.svg +1 -0
- data/app/assets/images/payment_icons/payeverpaybybank.svg +1 -0
- data/app/assets/images/payment_icons/payme.svg +1 -0
- data/app/assets/images/payment_icons/paynow.svg +1 -0
- data/app/assets/images/payment_icons/paynowmbank.svg +1 -0
- data/app/assets/images/payment_icons/paypal.svg +1 -0
- data/app/assets/images/payment_icons/paypo.svg +1 -0
- data/app/assets/images/payment_icons/payrexxbanktransfer.svg +1 -0
- data/app/assets/images/payment_icons/payrexxpaybybank.svg +1 -0
- data/app/assets/images/payment_icons/paysafecash.svg +1 -0
- data/app/assets/images/payment_icons/pix.svg +1 -0
- data/app/assets/images/payment_icons/polygon.svg +1 -0
- data/app/assets/images/payment_icons/przelewy24.svg +1 -0
- data/app/assets/images/payment_icons/publicbank.svg +1 -0
- data/app/assets/images/payment_icons/publicbank_pbe.svg +1 -0
- data/app/assets/images/payment_icons/qr_promptpay.svg +1 -0
- data/app/assets/images/payment_icons/rabobank.svg +1 -0
- data/app/assets/images/payment_icons/revolut.svg +1 -0
- data/app/assets/images/payment_icons/rhbbank.svg +1 -0
- data/app/assets/images/payment_icons/riverty.svg +1 -0
- data/app/assets/images/payment_icons/safetypaybanktransfer.svg +1 -0
- data/app/assets/images/payment_icons/samsung_pay.svg +1 -0
- data/app/assets/images/payment_icons/satispay.svg +1 -0
- data/app/assets/images/payment_icons/scalapay.svg +1 -0
- data/app/assets/images/payment_icons/scotiabank.svg +1 -0
- data/app/assets/images/payment_icons/seabankid.svg +1 -0
- data/app/assets/images/payment_icons/seabankph.svg +1 -0
- data/app/assets/images/payment_icons/sepa_bank_transfer.svg +1 -0
- data/app/assets/images/payment_icons/sepadirectdebit.svg +1 -0
- data/app/assets/images/payment_icons/seveneleven.svg +1 -0
- data/app/assets/images/payment_icons/shib.svg +1 -0
- data/app/assets/images/payment_icons/shopcash.svg +1 -0
- data/app/assets/images/payment_icons/siauliubankas.svg +1 -0
- data/app/assets/images/payment_icons/skeps.svg +1 -0
- data/app/assets/images/payment_icons/snap_checkout.svg +1 -0
- data/app/assets/images/payment_icons/sofort.svg +1 -0
- data/app/assets/images/payment_icons/softbank.svg +1 -0
- data/app/assets/images/payment_icons/spei.svg +1 -0
- data/app/assets/images/payment_icons/storecredit.svg +1 -0
- data/app/assets/images/payment_icons/stripe.svg +1 -0
- data/app/assets/images/payment_icons/sveacheckout.svg +1 -0
- data/app/assets/images/payment_icons/swedbank.svg +1 -0
- data/app/assets/images/payment_icons/swish.svg +1 -0
- data/app/assets/images/payment_icons/tbibank.svg +1 -0
- data/app/assets/images/payment_icons/thanachartbank.svg +1 -0
- data/app/assets/images/payment_icons/tnmmoney.svg +1 -0
- data/app/assets/images/payment_icons/touchngo.svg +1 -0
- data/app/assets/images/payment_icons/trustly.svg +1 -0
- data/app/assets/images/payment_icons/twint.svg +1 -0
- data/app/assets/images/payment_icons/uaevisa.svg +1 -0
- data/app/assets/images/payment_icons/unionpay.svg +1 -0
- data/app/assets/images/payment_icons/unzerbanktransfer.svg +1 -0
- data/app/assets/images/payment_icons/upi.svg +1 -0
- data/app/assets/images/payment_icons/usbank.svg +1 -0
- data/app/assets/images/payment_icons/usdc.svg +1 -0
- data/app/assets/images/payment_icons/usdt.svg +1 -0
- data/app/assets/images/payment_icons/venmo.svg +1 -0
- data/app/assets/images/payment_icons/vipps.svg +1 -0
- data/app/assets/images/payment_icons/visa.svg +1 -0
- data/app/assets/images/payment_icons/volksbank.svg +1 -0
- data/app/assets/images/payment_icons/waavepaybybank.svg +1 -0
- data/app/assets/images/payment_icons/walley.svg +1 -0
- data/app/assets/images/payment_icons/wbtc.svg +1 -0
- data/app/assets/images/payment_icons/wechatpay.svg +1 -0
- data/app/assets/images/payment_icons/whishcheckout.svg +1 -0
- data/app/assets/images/payment_icons/wingbank.svg +1 -0
- data/app/assets/images/payment_icons/xrp.svg +1 -0
- data/app/assets/images/payment_icons/zip.svg +1 -0
- data/app/finders/spree/posts/find.rb +137 -0
- data/app/helpers/spree/addresses_helper.rb +9 -3
- data/app/helpers/spree/base_helper.rb +8 -4
- data/app/jobs/spree/images/save_from_url_job.rb +70 -0
- data/app/jobs/spree/imports/create_rows_job.rb +72 -0
- data/app/jobs/spree/imports/process_rows_job.rb +19 -0
- data/app/models/concerns/spree/adjustment_source.rb +3 -3
- data/app/models/concerns/spree/admin_user_methods.rb +52 -0
- data/app/models/concerns/spree/display_on.rb +7 -1
- data/app/models/concerns/spree/has_image_alt_text.rb +18 -0
- data/app/models/concerns/spree/has_one_link.rb +1 -1
- data/app/models/concerns/spree/has_page_links.rb +1 -1
- data/app/models/concerns/spree/linkable.rb +9 -0
- data/app/models/concerns/spree/metadata.rb +2 -0
- data/app/models/concerns/spree/metafields.rb +94 -0
- data/app/models/concerns/spree/named_type.rb +1 -1
- data/app/models/concerns/spree/user_methods.rb +20 -7
- data/app/models/concerns/spree/user_payment_source.rb +1 -1
- data/app/models/concerns/spree/user_roles.rb +3 -2
- data/app/models/spree/ability.rb +4 -0
- data/app/models/spree/address.rb +3 -1
- data/app/models/spree/adjustable/adjuster/tax.rb +2 -2
- data/app/models/spree/adjustable/adjustments_updater.rb +26 -3
- data/app/models/spree/adjustment.rb +4 -1
- data/app/models/spree/asset.rb +16 -0
- data/app/models/spree/base.rb +1 -1
- data/app/models/spree/credit_card.rb +1 -0
- data/app/models/spree/current.rb +5 -1
- data/app/models/spree/custom_domain.rb +5 -0
- data/app/models/spree/customer_return.rb +1 -0
- data/app/models/spree/export.rb +39 -2
- data/app/models/spree/exports/customers.rb +17 -0
- data/app/models/spree/exports/gift_cards.rb +13 -0
- data/app/models/spree/exports/newsletter_subscribers.rb +13 -0
- data/app/models/spree/exports/orders.rb +6 -4
- data/app/models/spree/exports/products.rb +9 -3
- data/app/models/spree/gift_card.rb +7 -1
- data/app/models/spree/gift_card_batch.rb +0 -1
- data/app/models/spree/import.rb +279 -0
- data/app/models/spree/import_mapping.rb +46 -0
- data/app/models/spree/import_row.rb +108 -0
- data/app/models/spree/import_schema.rb +25 -0
- data/app/models/spree/import_schemas/products.rb +45 -0
- data/app/models/spree/imports/products.rb +9 -0
- data/app/models/spree/invitation.rb +1 -1
- data/app/models/spree/legacy_user.rb +0 -1
- data/app/models/spree/line_item.rb +2 -7
- data/app/models/spree/metafield.rb +53 -0
- data/app/models/spree/metafield_definition.rb +91 -0
- data/app/models/spree/metafields/boolean.rb +15 -0
- data/app/models/spree/metafields/json.rb +27 -0
- data/app/models/spree/metafields/long_text.rb +7 -0
- data/app/models/spree/metafields/number.rb +15 -0
- data/app/models/spree/metafields/rich_text.rb +18 -0
- data/app/models/spree/metafields/short_text.rb +7 -0
- data/app/models/spree/newsletter_subscriber/emails.rb +12 -0
- data/app/models/spree/newsletter_subscriber.rb +64 -0
- data/app/models/spree/option_type.rb +2 -0
- data/app/models/spree/option_value.rb +1 -0
- data/app/models/spree/order/checkout.rb +7 -0
- data/app/models/spree/order.rb +8 -3
- data/app/models/spree/order_merger.rb +2 -4
- data/app/models/spree/order_promotion.rb +3 -0
- data/app/models/spree/order_updater.rb +2 -2
- data/app/models/spree/page.rb +5 -1
- data/app/models/spree/page_block.rb +4 -0
- data/app/models/spree/page_blocks/image.rb +3 -0
- data/app/models/spree/page_blocks/metafields.rb +18 -0
- data/app/models/spree/page_blocks/products/brand.rb +15 -0
- data/app/models/spree/page_blocks/products/buy_buttons.rb +5 -1
- data/app/models/spree/page_blocks/products/description.rb +18 -0
- data/app/models/spree/page_blocks/products/price.rb +1 -1
- data/app/models/spree/page_blocks/products/quantity_selector.rb +6 -2
- data/app/models/spree/page_blocks/products/title.rb +5 -1
- data/app/models/spree/page_blocks/products/variant_picker.rb +1 -1
- data/app/models/spree/page_section.rb +2 -2
- data/app/models/spree/page_sections/breadcrumbs.rb +12 -0
- data/app/models/spree/page_sections/footer.rb +20 -13
- data/app/models/spree/page_sections/image_banner.rb +6 -1
- data/app/models/spree/page_sections/image_with_text.rb +5 -0
- data/app/models/spree/page_sections/newsletter.rb +7 -0
- data/app/models/spree/page_sections/product_details.rb +38 -1
- data/app/models/spree/pages/account.rb +4 -0
- data/app/models/spree/pages/cart.rb +10 -0
- data/app/models/spree/pages/checkout.rb +6 -0
- data/app/models/spree/pages/custom.rb +4 -0
- data/app/models/spree/pages/homepage.rb +4 -0
- data/app/models/spree/pages/login.rb +4 -0
- data/app/models/spree/pages/password.rb +2 -0
- data/app/models/spree/pages/post_list.rb +4 -0
- data/app/models/spree/pages/product_details.rb +1 -0
- data/app/models/spree/pages/shop_all.rb +4 -0
- data/app/models/spree/pages/wishlist.rb +4 -0
- data/app/models/spree/payment.rb +1 -0
- data/app/models/spree/payment_method.rb +4 -5
- data/app/models/spree/payment_source.rb +1 -0
- data/app/models/spree/policy.rb +70 -0
- data/app/models/spree/post.rb +4 -2
- data/app/models/spree/post_category.rb +1 -0
- data/app/models/spree/product.rb +16 -9
- data/app/models/spree/promotion/actions/free_shipping.rb +3 -3
- data/app/models/spree/promotion.rb +24 -8
- data/app/models/spree/promotion_action.rb +1 -1
- data/app/models/spree/promotion_handler/cart.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +1 -1
- data/app/models/spree/promotion_rule.rb +1 -1
- data/app/models/spree/property.rb +18 -0
- data/app/models/spree/refund.rb +2 -1
- data/app/models/spree/role_user.rb +1 -1
- data/app/models/spree/shipment.rb +1 -0
- data/app/models/spree/shipping_method.rb +1 -0
- data/app/models/spree/stock_item.rb +1 -0
- data/app/models/spree/stock_transfer.rb +1 -0
- data/app/models/spree/store.rb +45 -3
- data/app/models/spree/store_credit.rb +2 -1
- data/app/models/spree/tax_category.rb +1 -1
- data/app/models/spree/tax_rate.rb +18 -3
- data/app/models/spree/taxon.rb +12 -2
- data/app/models/spree/taxonomy.rb +11 -0
- data/app/models/spree/theme.rb +1 -1
- data/app/models/spree/variant.rb +17 -0
- data/app/presenters/spree/csv/customer_presenter.rb +59 -0
- data/app/presenters/spree/csv/gift_card_presenter.rb +49 -0
- data/app/presenters/spree/csv/metafields_helper.rb +17 -0
- data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +39 -0
- data/app/presenters/spree/csv/order_line_item_presenter.rb +12 -5
- data/app/presenters/spree/csv/product_variant_presenter.rb +9 -5
- data/app/services/spree/cart/recalculate.rb +6 -4
- data/app/services/spree/cart/remove_line_item.rb +1 -2
- data/app/services/spree/imports/row_processors/base.rb +19 -0
- data/app/services/spree/imports/row_processors/product_variant.rb +228 -0
- data/app/services/spree/line_items/destroy.rb +1 -1
- data/app/services/spree/newsletter/subscribe.rb +43 -0
- data/app/services/spree/newsletter/verify.rb +30 -0
- data/app/sorters/spree/posts/sort.rb +40 -0
- data/app/views/spree/shared/_payment.html.erb +3 -3
- data/config/locales/en.yml +56 -2
- data/db/migrate/20250605131334_add_missing_fields_to_users.rb +23 -13
- data/db/migrate/20250728095629_create_spree_metafields.rb +27 -0
- data/db/migrate/20250730102644_add_missing_unique_indexes_to_spree_option_types_and_values.rb +40 -0
- data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +24 -0
- data/db/migrate/20250811112056_create_spree_policies.rb +22 -0
- data/db/migrate/20250821211705_fix_unique_index_on_spree_order_promotions.rb +20 -0
- data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +7 -0
- data/db/migrate/20250826093602_create_spree_newsletter_subscribers.rb +12 -0
- data/db/migrate/20250902143122_fix_policies_store_association.rb +18 -0
- data/db/migrate/20250911205659_add_missing_index_on_spree_products_promotionable.rb +5 -0
- data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +10 -0
- data/db/migrate/20250914101955_add_missing_indexes_on_spree_adjustments.rb +6 -0
- data/db/migrate/20250915093930_add_metadata_to_spree_newsletter_subscribers.rb +20 -0
- data/db/migrate/20250923141845_create_spree_imports.rb +47 -0
- data/lib/generators/spree/cursor_rules/cursor_rules_generator.rb +19 -0
- data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +387 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +0 -1
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +5 -0
- data/lib/spree/core/configuration.rb +1 -0
- data/lib/spree/core/dependencies.rb +3 -0
- data/lib/spree/core/engine.rb +57 -2
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +3 -1
- data/lib/spree/permitted_attributes.rb +18 -3
- data/lib/spree/testing_support/capybara_config.rb +9 -3
- data/lib/spree/testing_support/factories/export_factory.rb +5 -17
- data/lib/spree/testing_support/factories/import_factory.rb +20 -0
- data/lib/spree/testing_support/factories/import_mapping_factory.rb +7 -0
- data/lib/spree/testing_support/factories/import_row_factory.rb +7 -0
- data/lib/spree/testing_support/factories/metafield_definition_factory.rb +72 -0
- data/lib/spree/testing_support/factories/metafield_factory.rb +68 -0
- data/lib/spree/testing_support/factories/newsletter_subscriber_factory.rb +18 -0
- data/lib/spree/testing_support/factories/policy_factory.rb +8 -0
- data/lib/spree/testing_support/factories/post_factory.rb +8 -0
- data/lib/spree/testing_support/store.rb +11 -0
- data/lib/tasks/core.rake +128 -0
- metadata +279 -6
- data/app/models/action_text/rich_text_decorator.rb +0 -11
- data/app/presenters/spree/csv/product_presenter.rb +0 -63
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Imports
|
|
3
|
+
module RowProcessors
|
|
4
|
+
class ProductVariant < Base
|
|
5
|
+
OPTION_TYPES_COUNT = 3
|
|
6
|
+
|
|
7
|
+
def initialize(row)
|
|
8
|
+
super
|
|
9
|
+
@store = row.store
|
|
10
|
+
@product = ensure_product_exists
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :product, :store
|
|
14
|
+
|
|
15
|
+
def process!
|
|
16
|
+
variant_scope = options.empty? ? product.variants_including_master : product.variants
|
|
17
|
+
|
|
18
|
+
variant = if attributes['sku'].present?
|
|
19
|
+
variant_scope.where(
|
|
20
|
+
Spree::Variant.arel_table[:sku].lower.eq(attributes['sku'].strip.downcase)
|
|
21
|
+
).first || product.variants.new
|
|
22
|
+
elsif options.empty?
|
|
23
|
+
product.master
|
|
24
|
+
else
|
|
25
|
+
product.variants.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
variant.sku = attributes['sku'] if attributes['sku'].present?
|
|
29
|
+
variant.cost_price = attributes['cost_price'] if attributes['cost_price'].present?
|
|
30
|
+
variant.weight = attributes['weight'] if attributes['weight'].present?
|
|
31
|
+
variant.height = attributes['height'] if attributes['height'].present?
|
|
32
|
+
variant.width = attributes['width'] if attributes['width'].present?
|
|
33
|
+
variant.depth = attributes['depth'] if attributes['depth'].present?
|
|
34
|
+
variant.track_inventory = attributes['track_inventory'] if attributes['track_inventory'].present?
|
|
35
|
+
variant.option_value_variants = prepare_option_value_variants
|
|
36
|
+
variant.save!
|
|
37
|
+
|
|
38
|
+
if attributes['price'].present?
|
|
39
|
+
currency = (attributes['currency'].presence || store.default_currency).to_s.strip.upcase
|
|
40
|
+
variant.set_price(currency, attributes['price'], attributes['compare_at_price'])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if attributes['inventory_count'].present?
|
|
44
|
+
variant.set_stock(attributes['inventory_count'].to_i, attributes['inventory_backorderable']&.to_b, store.default_stock_location)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
handle_images(variant)
|
|
48
|
+
|
|
49
|
+
variant
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def ensure_product_exists
|
|
55
|
+
product = Spree::Product.new
|
|
56
|
+
if attributes['slug'].present?
|
|
57
|
+
existing_product = product_scope.find_by(slug: attributes['slug'].strip.downcase)
|
|
58
|
+
product = existing_product if existing_product.present?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
product = assign_attributes_to_product(product)
|
|
62
|
+
product.save!
|
|
63
|
+
handle_metafields(product)
|
|
64
|
+
product
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def product_scope
|
|
68
|
+
Spree::Product.accessible_by(import.current_ability, :manage)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def assign_attributes_to_product(product)
|
|
72
|
+
# setting SKU for master variant so it will be picked up in process! and won't try to create a non-master variant
|
|
73
|
+
if product.new_record?
|
|
74
|
+
product.slug = attributes['slug']
|
|
75
|
+
product.sku = attributes['sku'] if attributes['sku'].present? && options.empty?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
product.stores << store if product.stores.exclude?(store)
|
|
79
|
+
product.name = attributes['name'] if attributes['name'].present?
|
|
80
|
+
product.description = attributes['description'] if attributes['description'].present?
|
|
81
|
+
product.meta_title = attributes['meta_title'] if attributes['meta_title'].present?
|
|
82
|
+
product.meta_description = attributes['meta_description'] if attributes['meta_description'].present?
|
|
83
|
+
product.meta_keywords = attributes['meta_keywords'] if attributes['meta_keywords'].present?
|
|
84
|
+
product.status = to_spree_status(attributes['status']) if attributes['status'].present?
|
|
85
|
+
product.tag_list = attributes['tags'] if attributes['tags'].present?
|
|
86
|
+
|
|
87
|
+
product.taxons = prepare_taxons if options.empty?
|
|
88
|
+
product
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def prepare_taxons
|
|
92
|
+
taxon_pretty_names = [
|
|
93
|
+
attributes['category1'],
|
|
94
|
+
attributes['category2'],
|
|
95
|
+
attributes['category3']
|
|
96
|
+
].compact_blank.map(&:strip).uniq
|
|
97
|
+
|
|
98
|
+
return [] if taxon_pretty_names.empty?
|
|
99
|
+
|
|
100
|
+
taxons = taxon_pretty_names.map { |taxon_pretty_name| handle_taxon_line(taxon_pretty_name) }
|
|
101
|
+
taxons.compact
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def handle_taxon_line(taxon_pretty_name)
|
|
105
|
+
taxon_names = taxon_pretty_name.strip.split('->').map(&:strip).map(&:presence).compact
|
|
106
|
+
return if taxon_names.empty?
|
|
107
|
+
|
|
108
|
+
taxonomy_name = taxon_names.shift
|
|
109
|
+
taxonomy = store.taxonomies.with_matching_name(taxonomy_name).first || store.taxonomies.create!(name: taxonomy_name)
|
|
110
|
+
|
|
111
|
+
last_taxon = taxonomy.root
|
|
112
|
+
|
|
113
|
+
taxon_names.each do |taxon_name|
|
|
114
|
+
last_taxon = taxonomy.taxons.with_matching_name(taxon_name).where(parent: last_taxon).first || taxonomy.taxons.create!(name: taxon_name, parent: last_taxon)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
last_taxon
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def prepare_option_value_variants
|
|
121
|
+
return [] if options.empty?
|
|
122
|
+
|
|
123
|
+
options.map do |option|
|
|
124
|
+
option_type = Spree::OptionType.search_by_name(option[:option_name]).first || Spree::OptionType.create!(presentation: option[:option_name])
|
|
125
|
+
option_value = option_type.option_values.search_by_name(option[:option_value]).first || option_type.option_values.create!(presentation: option[:option_value])
|
|
126
|
+
|
|
127
|
+
# ensure product option types include new option type
|
|
128
|
+
Spree::ProductOptionType.find_or_create_by!(product: product, option_type: option_type)
|
|
129
|
+
|
|
130
|
+
Spree::OptionValueVariant.new(option_value: option_value)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def handle_images(variant)
|
|
135
|
+
image_urls = [
|
|
136
|
+
attributes['image1_src'],
|
|
137
|
+
attributes['image2_src'],
|
|
138
|
+
attributes['image3_src'],
|
|
139
|
+
].compact.map(&:strip).compact_blank.uniq
|
|
140
|
+
|
|
141
|
+
return if image_urls.empty?
|
|
142
|
+
|
|
143
|
+
image_urls.each do |image_url|
|
|
144
|
+
Spree::Images::SaveFromUrlJob.perform_later(variant.id, 'Spree::Variant', image_url)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def options
|
|
149
|
+
@options ||= begin
|
|
150
|
+
options = []
|
|
151
|
+
|
|
152
|
+
OPTION_TYPES_COUNT.times.map do |index|
|
|
153
|
+
next if attributes["option#{index + 1}_name"].blank?
|
|
154
|
+
next if attributes["option#{index + 1}_value"].blank?
|
|
155
|
+
|
|
156
|
+
options << {
|
|
157
|
+
index: index + 1,
|
|
158
|
+
option_name: attributes["option#{index + 1}_name"],
|
|
159
|
+
option_value: attributes["option#{index + 1}_value"]
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
options
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def handle_metafields(product)
|
|
168
|
+
return unless product.class.included_modules.include?(Spree::Metafields)
|
|
169
|
+
|
|
170
|
+
metafield_attributes = attributes.select { |key, _value| key.to_s.start_with?('metafield.') }
|
|
171
|
+
return if metafield_attributes.empty?
|
|
172
|
+
|
|
173
|
+
# Build nested attributes for metafields
|
|
174
|
+
nested_attrs = []
|
|
175
|
+
|
|
176
|
+
metafield_attributes.each do |attribute_key, value|
|
|
177
|
+
# Extract namespace.key from "metafield.namespace.key"
|
|
178
|
+
full_key = attribute_key.to_s.sub(/^metafield\./, '')
|
|
179
|
+
namespace, key = product.extract_namespace_and_key(full_key)
|
|
180
|
+
|
|
181
|
+
# Find or initialize metafield definition
|
|
182
|
+
metafield_definition = Spree::MetafieldDefinition.find_by(
|
|
183
|
+
namespace: namespace,
|
|
184
|
+
key: key,
|
|
185
|
+
resource_type: product.class.name
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
next unless metafield_definition
|
|
189
|
+
|
|
190
|
+
# Find existing metafield if product is persisted
|
|
191
|
+
existing_metafield = product.persisted? ? product.metafields.find_by(metafield_definition: metafield_definition) : nil
|
|
192
|
+
|
|
193
|
+
# Skip blank values for new metafields
|
|
194
|
+
next if value.blank? && existing_metafield.nil?
|
|
195
|
+
|
|
196
|
+
# For existing metafields with blank values, we'll mark them for destruction
|
|
197
|
+
# For new metafields, we skip them (handled above)
|
|
198
|
+
# For existing or new metafields with values, we create/update them
|
|
199
|
+
metafield_attrs = {
|
|
200
|
+
metafield_definition_id: metafield_definition.id,
|
|
201
|
+
value: value.to_s.strip,
|
|
202
|
+
type: metafield_definition.metafield_type
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
metafield_attrs[:id] = existing_metafield.id if existing_metafield
|
|
206
|
+
|
|
207
|
+
nested_attrs << metafield_attrs
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
product.update(metafields_attributes: nested_attrs) unless nested_attrs.empty?
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def to_spree_status(status)
|
|
214
|
+
case status.strip.downcase
|
|
215
|
+
when 'active'
|
|
216
|
+
'active'
|
|
217
|
+
when 'draft'
|
|
218
|
+
'draft'
|
|
219
|
+
when 'archived'
|
|
220
|
+
'archived'
|
|
221
|
+
else
|
|
222
|
+
'draft'
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Newsletter
|
|
3
|
+
class Subscribe
|
|
4
|
+
def initialize(email:, current_user: nil)
|
|
5
|
+
@email = email
|
|
6
|
+
@current_user = current_user
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call
|
|
10
|
+
return existed_subscription if existed_subscription.present?
|
|
11
|
+
|
|
12
|
+
ActiveRecord::Base.transaction do
|
|
13
|
+
upsert_subscriber
|
|
14
|
+
return subscriber if subscriber.errors.any?
|
|
15
|
+
|
|
16
|
+
if subscriber.email == current_user&.email
|
|
17
|
+
# no need to verified since user email is already verified
|
|
18
|
+
Spree::Newsletter::Verify.new(subscriber: subscriber).call
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# deliver confirmation email after the transaction is completed
|
|
23
|
+
subscriber.deliver_newsletter_email_verification unless subscriber.verified?
|
|
24
|
+
subscriber
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
attr_reader :email, :current_user
|
|
30
|
+
|
|
31
|
+
def upsert_subscriber
|
|
32
|
+
@upsert_subscriber ||= Spree::NewsletterSubscriber.find_or_create_by(email: email) do |new_record|
|
|
33
|
+
new_record.user = Spree.user_class.find_by(email: new_record.email) || current_user
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
alias_method :subscriber, :upsert_subscriber
|
|
37
|
+
|
|
38
|
+
def existed_subscription
|
|
39
|
+
@existed_subscription ||= Spree::NewsletterSubscriber.verified.find_by(email: email)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Newsletter
|
|
3
|
+
class Verify
|
|
4
|
+
def initialize(subscriber:)
|
|
5
|
+
@subscriber = subscriber
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
verify_subscriber
|
|
10
|
+
set_user_email_marketing_to_true
|
|
11
|
+
|
|
12
|
+
subscriber
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
attr_reader :subscriber
|
|
18
|
+
|
|
19
|
+
def verify_subscriber
|
|
20
|
+
subscriber.update!(verified_at: Time.current, verification_token: nil)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def set_user_email_marketing_to_true
|
|
24
|
+
return if subscriber.user.blank?
|
|
25
|
+
|
|
26
|
+
subscriber.user.update!(accepts_email_marketing: true)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Posts
|
|
3
|
+
class Sort < ::Spree::BaseSorter
|
|
4
|
+
def initialize(scope, params = {}, allowed_sort_attributes = [])
|
|
5
|
+
super(scope, params, allowed_sort_attributes)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
posts = by_param_attributes(scope)
|
|
10
|
+
posts = select_translatable_fields(posts) if Spree.use_translations?
|
|
11
|
+
|
|
12
|
+
posts.distinct
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
attr_reader :sort, :scope, :allowed_sort_attributes
|
|
18
|
+
|
|
19
|
+
# Add translatable fields to SELECT statement to avoid InvalidColumnReference error (workaround for Mobility issue #596)
|
|
20
|
+
def select_translatable_fields(scope)
|
|
21
|
+
translatable_fields = translatable_sortable_fields
|
|
22
|
+
return scope if translatable_fields.empty?
|
|
23
|
+
|
|
24
|
+
scope.i18n.select("#{Post.table_name}.*").select(*translatable_fields)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def translatable_sortable_fields
|
|
28
|
+
fields = []
|
|
29
|
+
Post.translatable_fields.each do |field|
|
|
30
|
+
fields << field if sort_by?(field.to_s)
|
|
31
|
+
end
|
|
32
|
+
fields
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def sort_by?(field)
|
|
36
|
+
sort.detect { |s| s[0] == field }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<p class="mb-1"><%= Spree.t(:gift_card) %>: <strong><%= source.originator.code.upcase %></strong></p>
|
|
23
23
|
<%= @order.display_gift_card_total %>
|
|
24
24
|
</div>
|
|
25
|
-
<% elsif payment_method_icon_tag(payment.payment_method.payment_icon_name).present? %>
|
|
25
|
+
<% elsif payment.payment_method.present? && payment_method_icon_tag(payment.payment_method.payment_icon_name).present? %>
|
|
26
26
|
<div class="d-flex flex align-items-center items-center">
|
|
27
27
|
<div><%= payment_method_icon_tag(payment.payment_method.payment_icon_name) %></div>
|
|
28
28
|
<div class="ml-3"><%= Spree.t(:store_credit_name) %></div>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
<%= payment_method_icon_tag source.class.to_s.demodulize.downcase, height: 30 %>
|
|
34
34
|
</div>
|
|
35
35
|
<div>
|
|
36
|
-
<% if payment.payment_method.respond_to?(:source_partial_name) %>
|
|
36
|
+
<% if payment.payment_method.present? && payment.payment_method.respond_to?(:source_partial_name) %>
|
|
37
37
|
<%= render partial: "spree/payment_sources/#{payment.payment_method.source_partial_name}", locals: { payment: payment, source: source } %>
|
|
38
38
|
<% elsif source.respond_to?(:name) %>
|
|
39
39
|
<%= source.name %>
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
<%= source.class.to_s.demodulize.downcase %>
|
|
42
42
|
<% end %>
|
|
43
43
|
</div>
|
|
44
|
-
<%
|
|
44
|
+
<% elsif payment.payment_method.present? %>
|
|
45
45
|
<div class="flex-shrink-0">
|
|
46
46
|
<%= payment_method_icon_tag payment.payment_method.payment_icon_name %>
|
|
47
47
|
</div>
|
data/config/locales/en.yml
CHANGED
|
@@ -53,6 +53,13 @@ en:
|
|
|
53
53
|
spree/gift_card:
|
|
54
54
|
amount_used: Amount used
|
|
55
55
|
expires_at: Expires at
|
|
56
|
+
spree/import:
|
|
57
|
+
preferred_delimiter: Delimiter
|
|
58
|
+
spree/import_mapping:
|
|
59
|
+
file_column: File Column
|
|
60
|
+
schema_field: Schema Field
|
|
61
|
+
spree/import_row:
|
|
62
|
+
row_number: Number
|
|
56
63
|
spree/inventory_unit:
|
|
57
64
|
state: State
|
|
58
65
|
spree/invitation:
|
|
@@ -60,6 +67,8 @@ en:
|
|
|
60
67
|
spree/line_item:
|
|
61
68
|
price: Price
|
|
62
69
|
quantity: Quantity
|
|
70
|
+
spree/metafield_definition:
|
|
71
|
+
namespace: Namespace
|
|
63
72
|
spree/option_type:
|
|
64
73
|
filterable: Filterable
|
|
65
74
|
name: Name
|
|
@@ -101,6 +110,9 @@ en:
|
|
|
101
110
|
number: Number
|
|
102
111
|
spree/payment_method:
|
|
103
112
|
name: Name
|
|
113
|
+
spree/policy:
|
|
114
|
+
body: Body
|
|
115
|
+
owner: Policy for
|
|
104
116
|
spree/product:
|
|
105
117
|
available_on: Available On
|
|
106
118
|
cost_currency: Cost Currency
|
|
@@ -165,6 +177,9 @@ en:
|
|
|
165
177
|
preferred_limit_digital_download_days: Limit digital links download days
|
|
166
178
|
seo_robots: SEO Robots
|
|
167
179
|
seo_title: SEO Title
|
|
180
|
+
storefront_custom_code_body_end: Custom Code before closing body tag
|
|
181
|
+
storefront_custom_code_body_start: Custom Code after opening body tag
|
|
182
|
+
storefront_custom_code_head: Custom Code in page head
|
|
168
183
|
url: Site URL
|
|
169
184
|
spree/store_credit:
|
|
170
185
|
amount_used: Amount used
|
|
@@ -241,6 +256,12 @@ en:
|
|
|
241
256
|
attachment:
|
|
242
257
|
attachment_must_be_present: must be present
|
|
243
258
|
not_allowed_content_type: has not allowed content type
|
|
259
|
+
spree/import:
|
|
260
|
+
attributes:
|
|
261
|
+
attachment:
|
|
262
|
+
content_type: has not allowed content type
|
|
263
|
+
type:
|
|
264
|
+
inclusion: is not included in the list of allowed types
|
|
244
265
|
spree/legacy_user:
|
|
245
266
|
attributes:
|
|
246
267
|
bill_address_id:
|
|
@@ -677,6 +698,9 @@ en:
|
|
|
677
698
|
analytics: Analytics
|
|
678
699
|
and: and
|
|
679
700
|
api_keys: API keys
|
|
701
|
+
apis:
|
|
702
|
+
platform: Platform API
|
|
703
|
+
storefront: Storefront API
|
|
680
704
|
apply: Apply
|
|
681
705
|
apply_only_on_full_priced_items: Apply only on full priced items
|
|
682
706
|
apply_store_credit: Apply Store Credit
|
|
@@ -728,6 +752,7 @@ en:
|
|
|
728
752
|
body_tag_end: Body tag end
|
|
729
753
|
body_tag_start: Body tag start
|
|
730
754
|
both: Both
|
|
755
|
+
brand: Brand
|
|
731
756
|
breadcrumbs: Breadcrumbs
|
|
732
757
|
calculated_reimbursements: Calculated Reimbursements
|
|
733
758
|
calculator: Calculator
|
|
@@ -821,6 +846,7 @@ en:
|
|
|
821
846
|
continue_selling_when_out_of_stock: Continue selling when out of stock
|
|
822
847
|
continue_shopping: Continue shopping
|
|
823
848
|
continue_without_logging_in: Continue without logging in
|
|
849
|
+
copied: Copied!
|
|
824
850
|
copy: Copy
|
|
825
851
|
copy_id: Copy ID
|
|
826
852
|
copy_link: Copy link
|
|
@@ -871,7 +897,6 @@ en:
|
|
|
871
897
|
credits: Credits
|
|
872
898
|
currencies: Currencies
|
|
873
899
|
currency: Currency
|
|
874
|
-
currency_and_country_help: This determines which vendors you can connect with and what customers see on your store.
|
|
875
900
|
currency_settings: Currency Settings
|
|
876
901
|
current: Current
|
|
877
902
|
current_password: Current password
|
|
@@ -900,6 +925,7 @@ en:
|
|
|
900
925
|
default_billing_address: Default billing address
|
|
901
926
|
default_country: Default Country
|
|
902
927
|
default_country_cannot_be_deleted: Default country cannot be deleted
|
|
928
|
+
default_country_help: Country that will be used for the default shipping and billing addresses on Checkout
|
|
903
929
|
default_currency: Default currency
|
|
904
930
|
default_locale: Default locale
|
|
905
931
|
default_post_categories:
|
|
@@ -1061,6 +1087,7 @@ en:
|
|
|
1061
1087
|
field: Field
|
|
1062
1088
|
filename: Filename
|
|
1063
1089
|
fill_in_customer_info: Please fill in customer info
|
|
1090
|
+
filled: Filled
|
|
1064
1091
|
filter: Filter
|
|
1065
1092
|
filter_results: Filter Results
|
|
1066
1093
|
filterable: Filterable
|
|
@@ -1143,6 +1170,7 @@ en:
|
|
|
1143
1170
|
images: Images
|
|
1144
1171
|
implement_eligible_for_return: 'Must implement #eligible_for_return? for your EligibilityValidator.'
|
|
1145
1172
|
implement_requires_manual_intervention: 'Must implement #requires_manual_intervention? for your EligibilityValidator.'
|
|
1173
|
+
import: Import
|
|
1146
1174
|
import_payment_methods_from: Import payment methods from
|
|
1147
1175
|
import_products_from: Import products from
|
|
1148
1176
|
in_stock: In Stock
|
|
@@ -1165,6 +1193,8 @@ en:
|
|
|
1165
1193
|
intercept_email_address: Intercept Email Address
|
|
1166
1194
|
intercept_email_instructions: Override email recipient and replace with this address.
|
|
1167
1195
|
internal_name: Internal Name
|
|
1196
|
+
internal_server_error: Internal Server Error
|
|
1197
|
+
internal_server_error_message: The server encountered an internal error and was unable to complete your request.
|
|
1168
1198
|
internationalization: Internationalization
|
|
1169
1199
|
invalid_credit_card: Invalid credit card.
|
|
1170
1200
|
invalid_exchange_variant: Invalid exchange variant.
|
|
@@ -1209,6 +1239,7 @@ en:
|
|
|
1209
1239
|
items_reimbursed: Items reimbursed
|
|
1210
1240
|
items_to_be_reimbursed: Items to be reimbursed
|
|
1211
1241
|
join_slack: Join Slack
|
|
1242
|
+
key: Key
|
|
1212
1243
|
kind: Kind
|
|
1213
1244
|
language: Language
|
|
1214
1245
|
last_name: Last Name
|
|
@@ -1264,6 +1295,8 @@ en:
|
|
|
1264
1295
|
meta_keywords: Meta Keywords
|
|
1265
1296
|
meta_title: Meta Title
|
|
1266
1297
|
metadata: Metadata
|
|
1298
|
+
metafield_definitions: Metafield Definitions
|
|
1299
|
+
metafields: Metafields
|
|
1267
1300
|
min: Min
|
|
1268
1301
|
minimal_amount: Minimal Amount
|
|
1269
1302
|
minimum_password_length:
|
|
@@ -1301,7 +1334,7 @@ en:
|
|
|
1301
1334
|
new_gift_card: New Gift Card
|
|
1302
1335
|
new_image: New Image
|
|
1303
1336
|
new_line_item: Add line item
|
|
1304
|
-
|
|
1337
|
+
new_metafield_definition: New Metafield Definition
|
|
1305
1338
|
new_nested_taxon: New nested taxon
|
|
1306
1339
|
new_option_type: New Option Type
|
|
1307
1340
|
new_order: New Order
|
|
@@ -1311,6 +1344,7 @@ en:
|
|
|
1311
1344
|
new_password: New password
|
|
1312
1345
|
new_payment: New Payment
|
|
1313
1346
|
new_payment_method: New Payment Method
|
|
1347
|
+
new_policy: New Policy
|
|
1314
1348
|
new_post: New Post
|
|
1315
1349
|
new_post_category: New Post Category
|
|
1316
1350
|
new_product: New Product
|
|
@@ -1343,6 +1377,17 @@ en:
|
|
|
1343
1377
|
new_user: New User
|
|
1344
1378
|
new_variant: New Variant
|
|
1345
1379
|
new_zone: New Zone
|
|
1380
|
+
newsletter_mailer:
|
|
1381
|
+
email_confirmation:
|
|
1382
|
+
dear_customer: Hey,
|
|
1383
|
+
ignore_disclaimer: If you didn't request this, please ignore this email.
|
|
1384
|
+
instructions: Please click the button below to verify your email address.
|
|
1385
|
+
message_copy_link: 'If the button doesn''t work please copy and paste the following link to your browser:'
|
|
1386
|
+
store_team: "%{store_name} Team"
|
|
1387
|
+
subject: Verify your email address
|
|
1388
|
+
thanks: Thank you
|
|
1389
|
+
verify_email_address_link: Verify email address
|
|
1390
|
+
newsletter_subscribers: Newsletter Subscribers
|
|
1346
1391
|
newsletters: Newsletters
|
|
1347
1392
|
next: Next
|
|
1348
1393
|
no_actions_added: No actions added
|
|
@@ -1495,6 +1540,7 @@ en:
|
|
|
1495
1540
|
buy_buttons:
|
|
1496
1541
|
display_name: Add To Cart
|
|
1497
1542
|
page_not_found: Sorry! Page you are looking can’t be found.
|
|
1543
|
+
page_not_found_message: This page just doesn't exist.
|
|
1498
1544
|
page_sections:
|
|
1499
1545
|
announcement_bar:
|
|
1500
1546
|
default_text: Welcome to my Store!
|
|
@@ -1779,6 +1825,7 @@ en:
|
|
|
1779
1825
|
resellable: Resellable
|
|
1780
1826
|
resend: Resend
|
|
1781
1827
|
reset_password: Reset my password
|
|
1828
|
+
resource: Resource
|
|
1782
1829
|
response_code: Response Code
|
|
1783
1830
|
restore_defaults: Restore defaults
|
|
1784
1831
|
resume: resume
|
|
@@ -1813,6 +1860,7 @@ en:
|
|
|
1813
1860
|
rma_value: RMA Value
|
|
1814
1861
|
role_id: Role ID
|
|
1815
1862
|
roles: Roles
|
|
1863
|
+
row: Row
|
|
1816
1864
|
rules: Rules
|
|
1817
1865
|
safe: Safe
|
|
1818
1866
|
sale: Sale
|
|
@@ -1869,6 +1917,8 @@ en:
|
|
|
1869
1917
|
seo_title: SEO Title
|
|
1870
1918
|
server: Server
|
|
1871
1919
|
server_error: The server returned an error
|
|
1920
|
+
service_unavailable: Service Unavailable
|
|
1921
|
+
service_unavailable_message: The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.
|
|
1872
1922
|
settings: Settings
|
|
1873
1923
|
ship: Ship
|
|
1874
1924
|
ship_address: Ship Address
|
|
@@ -2205,6 +2255,8 @@ en:
|
|
|
2205
2255
|
metric: metric
|
|
2206
2256
|
metric_system: Metric system
|
|
2207
2257
|
unlock: Unlock
|
|
2258
|
+
unprocessable_entity: Unprocessable Entity
|
|
2259
|
+
unprocessable_entity_message: Your request could not be processed. Please check the form for errors and try again.
|
|
2208
2260
|
unrecognized_card_type: Unrecognized card type
|
|
2209
2261
|
unshippable_items: Unshippable Items
|
|
2210
2262
|
update: Update
|
|
@@ -2246,6 +2298,8 @@ en:
|
|
|
2246
2298
|
variants_count: Variants count
|
|
2247
2299
|
vendor: Vendor
|
|
2248
2300
|
vendors: Vendors
|
|
2301
|
+
verified: Verified
|
|
2302
|
+
verified_at: Verified at
|
|
2249
2303
|
version: Version
|
|
2250
2304
|
view: View
|
|
2251
2305
|
view_all: View all
|
|
@@ -1,25 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# these fields were not present when someone used a custom user class
|
|
2
2
|
# so we need to ensure this is setup properly
|
|
3
3
|
class AddMissingFieldsToUsers < ActiveRecord::Migration[7.2]
|
|
4
4
|
def change
|
|
5
5
|
users_table = Spree.user_class.table_name
|
|
6
|
-
|
|
6
|
+
admin_users_table = Spree.admin_user_class.table_name
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
:
|
|
10
|
-
else
|
|
11
|
-
:json
|
|
12
|
-
end
|
|
8
|
+
change_table users_table do |t|
|
|
9
|
+
t.string :login unless column_exists?(users_table, :login)
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
if t.respond_to? :jsonb
|
|
12
|
+
t.jsonb :public_metadata unless column_exists?(users_table, :public_metadata)
|
|
13
|
+
t.jsonb :private_metadata unless column_exists?(users_table, :private_metadata)
|
|
14
|
+
else
|
|
15
|
+
t.json :public_metadata unless column_exists?(users_table, :public_metadata)
|
|
16
|
+
t.json :private_metadata unless column_exists?(users_table, :private_metadata)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
16
19
|
|
|
17
20
|
add_reference users_table, :bill_address, if_not_exists: true
|
|
18
21
|
add_reference users_table, :ship_address, if_not_exists: true
|
|
19
22
|
|
|
20
|
-
admin_users_table
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
change_table admin_users_table do |t|
|
|
24
|
+
t.string :login unless column_exists?(admin_users_table, :login)
|
|
25
|
+
|
|
26
|
+
if t.respond_to? :jsonb
|
|
27
|
+
t.jsonb :public_metadata unless column_exists?(admin_users_table, :public_metadata)
|
|
28
|
+
t.jsonb :private_metadata unless column_exists?(admin_users_table, :private_metadata)
|
|
29
|
+
else
|
|
30
|
+
t.json :public_metadata unless column_exists?(admin_users_table, :public_metadata)
|
|
31
|
+
t.json :private_metadata unless column_exists?(admin_users_table, :private_metadata)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
24
34
|
end
|
|
25
35
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class CreateSpreeMetafields < ActiveRecord::Migration[7.2]
|
|
2
|
+
def change
|
|
3
|
+
create_table :spree_metafield_definitions do |t|
|
|
4
|
+
t.string :namespace, null: false
|
|
5
|
+
t.string :key, null: false
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :metafield_type, null: false
|
|
8
|
+
t.string :resource_type, null: false, index: true
|
|
9
|
+
t.string :display_on, null: false, default: 'both', index: true
|
|
10
|
+
t.timestamps
|
|
11
|
+
|
|
12
|
+
t.index [:namespace, :key]
|
|
13
|
+
t.index [:resource_type, :namespace, :key], unique: true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
create_table :spree_metafields do |t|
|
|
17
|
+
t.string :type, null: false, index: true
|
|
18
|
+
t.references :resource, polymorphic: true, null: false, index: true
|
|
19
|
+
t.references :metafield_definition, null: false, index: true
|
|
20
|
+
t.text :value
|
|
21
|
+
|
|
22
|
+
t.timestamps
|
|
23
|
+
|
|
24
|
+
t.index [:resource_type, :resource_id, :metafield_definition_id], name: 'index_metafields_on_resource_and_definition', unique: true
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|