spree_core 5.1.9 → 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 +5 -2
- 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/checkout/update.rb +0 -24
- 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 -3
- 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
|
@@ -5,10 +5,6 @@ module Spree
|
|
|
5
5
|
include Spree::Addresses::Helper
|
|
6
6
|
|
|
7
7
|
def call(order:, params:, permitted_attributes:, request_env:)
|
|
8
|
-
# Validate address ownership to prevent IDOR attacks
|
|
9
|
-
address_ownership_error = validate_address_ownership(order, params)
|
|
10
|
-
return failure(order, address_ownership_error) if address_ownership_error
|
|
11
|
-
|
|
12
8
|
ship_changed = address_with_country_iso_present?(params, 'ship')
|
|
13
9
|
bill_changed = address_with_country_iso_present?(params, 'bill')
|
|
14
10
|
params[:order][:ship_address_attributes] = replace_country_iso_with_id(params[:order][:ship_address_attributes]) if ship_changed
|
|
@@ -30,26 +26,6 @@ module Spree
|
|
|
30
26
|
|
|
31
27
|
private
|
|
32
28
|
|
|
33
|
-
def validate_address_ownership(order, params)
|
|
34
|
-
return nil unless params[:order]
|
|
35
|
-
|
|
36
|
-
%w[bill ship].each do |address_kind|
|
|
37
|
-
address_id = params[:order].dig("#{address_kind}_address_attributes".to_sym, :id)
|
|
38
|
-
next unless address_id
|
|
39
|
-
|
|
40
|
-
address = Spree::Address.find_by(id: address_id)
|
|
41
|
-
next unless address
|
|
42
|
-
|
|
43
|
-
# Allow if address has no user (guest address) or belongs to the order's user
|
|
44
|
-
next if address.user_id.nil?
|
|
45
|
-
next if order.user_id.present? && address.user_id == order.user_id
|
|
46
|
-
|
|
47
|
-
return Spree.t(:address_not_owned_by_user)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
nil
|
|
51
|
-
end
|
|
52
|
-
|
|
53
29
|
def address_with_country_iso_present?(params, address_kind = 'ship')
|
|
54
30
|
return false unless params.dig(:order, "#{address_kind}_address_attributes".to_sym, :country_iso)
|
|
55
31
|
return false if params.dig(:order, "#{address_kind}_address_attributes".to_sym, :country_id)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Imports
|
|
3
|
+
module RowProcessors
|
|
4
|
+
class Base
|
|
5
|
+
def initialize(row)
|
|
6
|
+
@row = row
|
|
7
|
+
@import = row.import
|
|
8
|
+
@attributes = row.to_schema_hash
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_reader :row, :import, :attributes
|
|
12
|
+
|
|
13
|
+
def process!
|
|
14
|
+
raise NotImplementedError, 'Subclasses must implement the process! method'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -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:
|
|
@@ -642,7 +663,6 @@ en:
|
|
|
642
663
|
successfully_updated: Updated successfully
|
|
643
664
|
unsuccessfully_saved: There was an error while trying to save your address.
|
|
644
665
|
unsuccessfully_updated: There was an update while trying to update your address.
|
|
645
|
-
address_not_owned_by_user: The specified address does not belong to this user.
|
|
646
666
|
address_settings: Address settings
|
|
647
667
|
addresses: Addresses
|
|
648
668
|
adjustable: Adjustable
|
|
@@ -678,6 +698,9 @@ en:
|
|
|
678
698
|
analytics: Analytics
|
|
679
699
|
and: and
|
|
680
700
|
api_keys: API keys
|
|
701
|
+
apis:
|
|
702
|
+
platform: Platform API
|
|
703
|
+
storefront: Storefront API
|
|
681
704
|
apply: Apply
|
|
682
705
|
apply_only_on_full_priced_items: Apply only on full priced items
|
|
683
706
|
apply_store_credit: Apply Store Credit
|
|
@@ -729,6 +752,7 @@ en:
|
|
|
729
752
|
body_tag_end: Body tag end
|
|
730
753
|
body_tag_start: Body tag start
|
|
731
754
|
both: Both
|
|
755
|
+
brand: Brand
|
|
732
756
|
breadcrumbs: Breadcrumbs
|
|
733
757
|
calculated_reimbursements: Calculated Reimbursements
|
|
734
758
|
calculator: Calculator
|
|
@@ -822,6 +846,7 @@ en:
|
|
|
822
846
|
continue_selling_when_out_of_stock: Continue selling when out of stock
|
|
823
847
|
continue_shopping: Continue shopping
|
|
824
848
|
continue_without_logging_in: Continue without logging in
|
|
849
|
+
copied: Copied!
|
|
825
850
|
copy: Copy
|
|
826
851
|
copy_id: Copy ID
|
|
827
852
|
copy_link: Copy link
|
|
@@ -872,7 +897,6 @@ en:
|
|
|
872
897
|
credits: Credits
|
|
873
898
|
currencies: Currencies
|
|
874
899
|
currency: Currency
|
|
875
|
-
currency_and_country_help: This determines which vendors you can connect with and what customers see on your store.
|
|
876
900
|
currency_settings: Currency Settings
|
|
877
901
|
current: Current
|
|
878
902
|
current_password: Current password
|
|
@@ -901,6 +925,7 @@ en:
|
|
|
901
925
|
default_billing_address: Default billing address
|
|
902
926
|
default_country: Default Country
|
|
903
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
|
|
904
929
|
default_currency: Default currency
|
|
905
930
|
default_locale: Default locale
|
|
906
931
|
default_post_categories:
|
|
@@ -1062,6 +1087,7 @@ en:
|
|
|
1062
1087
|
field: Field
|
|
1063
1088
|
filename: Filename
|
|
1064
1089
|
fill_in_customer_info: Please fill in customer info
|
|
1090
|
+
filled: Filled
|
|
1065
1091
|
filter: Filter
|
|
1066
1092
|
filter_results: Filter Results
|
|
1067
1093
|
filterable: Filterable
|
|
@@ -1144,6 +1170,7 @@ en:
|
|
|
1144
1170
|
images: Images
|
|
1145
1171
|
implement_eligible_for_return: 'Must implement #eligible_for_return? for your EligibilityValidator.'
|
|
1146
1172
|
implement_requires_manual_intervention: 'Must implement #requires_manual_intervention? for your EligibilityValidator.'
|
|
1173
|
+
import: Import
|
|
1147
1174
|
import_payment_methods_from: Import payment methods from
|
|
1148
1175
|
import_products_from: Import products from
|
|
1149
1176
|
in_stock: In Stock
|
|
@@ -1166,6 +1193,8 @@ en:
|
|
|
1166
1193
|
intercept_email_address: Intercept Email Address
|
|
1167
1194
|
intercept_email_instructions: Override email recipient and replace with this address.
|
|
1168
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.
|
|
1169
1198
|
internationalization: Internationalization
|
|
1170
1199
|
invalid_credit_card: Invalid credit card.
|
|
1171
1200
|
invalid_exchange_variant: Invalid exchange variant.
|
|
@@ -1210,6 +1239,7 @@ en:
|
|
|
1210
1239
|
items_reimbursed: Items reimbursed
|
|
1211
1240
|
items_to_be_reimbursed: Items to be reimbursed
|
|
1212
1241
|
join_slack: Join Slack
|
|
1242
|
+
key: Key
|
|
1213
1243
|
kind: Kind
|
|
1214
1244
|
language: Language
|
|
1215
1245
|
last_name: Last Name
|
|
@@ -1265,6 +1295,8 @@ en:
|
|
|
1265
1295
|
meta_keywords: Meta Keywords
|
|
1266
1296
|
meta_title: Meta Title
|
|
1267
1297
|
metadata: Metadata
|
|
1298
|
+
metafield_definitions: Metafield Definitions
|
|
1299
|
+
metafields: Metafields
|
|
1268
1300
|
min: Min
|
|
1269
1301
|
minimal_amount: Minimal Amount
|
|
1270
1302
|
minimum_password_length:
|
|
@@ -1302,7 +1334,7 @@ en:
|
|
|
1302
1334
|
new_gift_card: New Gift Card
|
|
1303
1335
|
new_image: New Image
|
|
1304
1336
|
new_line_item: Add line item
|
|
1305
|
-
|
|
1337
|
+
new_metafield_definition: New Metafield Definition
|
|
1306
1338
|
new_nested_taxon: New nested taxon
|
|
1307
1339
|
new_option_type: New Option Type
|
|
1308
1340
|
new_order: New Order
|
|
@@ -1312,6 +1344,7 @@ en:
|
|
|
1312
1344
|
new_password: New password
|
|
1313
1345
|
new_payment: New Payment
|
|
1314
1346
|
new_payment_method: New Payment Method
|
|
1347
|
+
new_policy: New Policy
|
|
1315
1348
|
new_post: New Post
|
|
1316
1349
|
new_post_category: New Post Category
|
|
1317
1350
|
new_product: New Product
|
|
@@ -1344,6 +1377,17 @@ en:
|
|
|
1344
1377
|
new_user: New User
|
|
1345
1378
|
new_variant: New Variant
|
|
1346
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
|
|
1347
1391
|
newsletters: Newsletters
|
|
1348
1392
|
next: Next
|
|
1349
1393
|
no_actions_added: No actions added
|
|
@@ -1496,6 +1540,7 @@ en:
|
|
|
1496
1540
|
buy_buttons:
|
|
1497
1541
|
display_name: Add To Cart
|
|
1498
1542
|
page_not_found: Sorry! Page you are looking can’t be found.
|
|
1543
|
+
page_not_found_message: This page just doesn't exist.
|
|
1499
1544
|
page_sections:
|
|
1500
1545
|
announcement_bar:
|
|
1501
1546
|
default_text: Welcome to my Store!
|
|
@@ -1780,6 +1825,7 @@ en:
|
|
|
1780
1825
|
resellable: Resellable
|
|
1781
1826
|
resend: Resend
|
|
1782
1827
|
reset_password: Reset my password
|
|
1828
|
+
resource: Resource
|
|
1783
1829
|
response_code: Response Code
|
|
1784
1830
|
restore_defaults: Restore defaults
|
|
1785
1831
|
resume: resume
|
|
@@ -1814,6 +1860,7 @@ en:
|
|
|
1814
1860
|
rma_value: RMA Value
|
|
1815
1861
|
role_id: Role ID
|
|
1816
1862
|
roles: Roles
|
|
1863
|
+
row: Row
|
|
1817
1864
|
rules: Rules
|
|
1818
1865
|
safe: Safe
|
|
1819
1866
|
sale: Sale
|
|
@@ -1870,6 +1917,8 @@ en:
|
|
|
1870
1917
|
seo_title: SEO Title
|
|
1871
1918
|
server: Server
|
|
1872
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.
|
|
1873
1922
|
settings: Settings
|
|
1874
1923
|
ship: Ship
|
|
1875
1924
|
ship_address: Ship Address
|
|
@@ -2206,6 +2255,8 @@ en:
|
|
|
2206
2255
|
metric: metric
|
|
2207
2256
|
metric_system: Metric system
|
|
2208
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.
|
|
2209
2260
|
unrecognized_card_type: Unrecognized card type
|
|
2210
2261
|
unshippable_items: Unshippable Items
|
|
2211
2262
|
update: Update
|
|
@@ -2247,6 +2298,8 @@ en:
|
|
|
2247
2298
|
variants_count: Variants count
|
|
2248
2299
|
vendor: Vendor
|
|
2249
2300
|
vendors: Vendors
|
|
2301
|
+
verified: Verified
|
|
2302
|
+
verified_at: Verified at
|
|
2250
2303
|
version: Version
|
|
2251
2304
|
view: View
|
|
2252
2305
|
view_all: View all
|