solidus_core 1.0.0.pre
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 +7 -0
- data/LICENSE +26 -0
- data/app/assets/images/logo/solidus.png +0 -0
- data/app/assets/images/logo/solidus_logo.png +0 -0
- data/app/assets/images/noimage/large.png +0 -0
- data/app/assets/images/noimage/mini.png +0 -0
- data/app/assets/images/noimage/product.png +0 -0
- data/app/assets/images/noimage/small.png +0 -0
- data/app/assets/javascripts/spree.js.coffee.erb +61 -0
- data/app/controllers/spree/base_controller.rb +15 -0
- data/app/helpers/spree/base_helper.rb +210 -0
- data/app/helpers/spree/checkout_helper.rb +31 -0
- data/app/helpers/spree/orders_helper.rb +17 -0
- data/app/helpers/spree/products_helper.rb +82 -0
- data/app/helpers/spree/store_helper.rb +16 -0
- data/app/helpers/spree/taxons_helper.rb +19 -0
- data/app/mailers/spree/base_mailer.rb +23 -0
- data/app/mailers/spree/carton_mailer.rb +12 -0
- data/app/mailers/spree/order_mailer.rb +35 -0
- data/app/mailers/spree/reimbursement_mailer.rb +10 -0
- data/app/mailers/spree/test_mailer.rb +8 -0
- data/app/models/concerns/spree/adjustment_source.rb +24 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +33 -0
- data/app/models/concerns/spree/default_price.rb +34 -0
- data/app/models/concerns/spree/display_money.rb +32 -0
- data/app/models/concerns/spree/named_type.rb +12 -0
- data/app/models/concerns/spree/user_address.rb +30 -0
- data/app/models/concerns/spree/user_api_authentication.rb +13 -0
- data/app/models/concerns/spree/user_payment_source.rb +19 -0
- data/app/models/concerns/spree/user_reporting.rb +22 -0
- data/app/models/spree/ability.rb +74 -0
- data/app/models/spree/address.rb +157 -0
- data/app/models/spree/adjustment.rb +143 -0
- data/app/models/spree/app_configuration.rb +253 -0
- data/app/models/spree/asset.rb +6 -0
- data/app/models/spree/base.rb +15 -0
- data/app/models/spree/billing_integration.rb +21 -0
- data/app/models/spree/calculator.rb +47 -0
- data/app/models/spree/calculator/default_tax.rb +67 -0
- data/app/models/spree/calculator/flat_percent_item_total.rb +22 -0
- data/app/models/spree/calculator/flat_rate.rb +20 -0
- data/app/models/spree/calculator/flexi_rate.rb +33 -0
- data/app/models/spree/calculator/free_shipping.rb +21 -0
- data/app/models/spree/calculator/percent_on_line_item.rb +15 -0
- data/app/models/spree/calculator/percent_per_item.rb +50 -0
- data/app/models/spree/calculator/price_sack.rb +29 -0
- data/app/models/spree/calculator/returns/default_refund_amount.rb +36 -0
- data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +22 -0
- data/app/models/spree/calculator/shipping/flat_rate.rb +18 -0
- data/app/models/spree/calculator/shipping/flexi_rate.rb +35 -0
- data/app/models/spree/calculator/shipping/per_item.rb +22 -0
- data/app/models/spree/calculator/shipping/price_sack.rb +28 -0
- data/app/models/spree/calculator/tiered_flat_rate.rb +37 -0
- data/app/models/spree/calculator/tiered_percent.rb +44 -0
- data/app/models/spree/carton.rb +57 -0
- data/app/models/spree/classification.rb +11 -0
- data/app/models/spree/country.rb +23 -0
- data/app/models/spree/credit_card.rb +197 -0
- data/app/models/spree/customer_return.rb +73 -0
- data/app/models/spree/exchange.rb +46 -0
- data/app/models/spree/gateway.rb +79 -0
- data/app/models/spree/gateway/bogus.rb +91 -0
- data/app/models/spree/gateway/bogus_simple.rb +26 -0
- data/app/models/spree/image.rb +44 -0
- data/app/models/spree/inventory_unit.rb +154 -0
- data/app/models/spree/item_adjustments.rb +85 -0
- data/app/models/spree/item_adjustments.rb.orig +93 -0
- data/app/models/spree/legacy_user.rb +38 -0
- data/app/models/spree/line_item.rb +183 -0
- data/app/models/spree/line_item_action.rb +6 -0
- data/app/models/spree/log_entry.rb +20 -0
- data/app/models/spree/option_type.rb +30 -0
- data/app/models/spree/option_value.rb +26 -0
- data/app/models/spree/option_values_variant.rb +6 -0
- data/app/models/spree/order.rb +811 -0
- data/app/models/spree/order/checkout.rb +351 -0
- data/app/models/spree/order/currency_updater.rb +40 -0
- data/app/models/spree/order/payments.rb +66 -0
- data/app/models/spree/order_cancellations.rb +72 -0
- data/app/models/spree/order_capturing.rb +49 -0
- data/app/models/spree/order_contents.rb +125 -0
- data/app/models/spree/order_inventory.rb +108 -0
- data/app/models/spree/order_mutex.rb +35 -0
- data/app/models/spree/order_promotion.rb +23 -0
- data/app/models/spree/order_shipping.rb +99 -0
- data/app/models/spree/order_stock_location.rb +15 -0
- data/app/models/spree/order_updater.rb +178 -0
- data/app/models/spree/payment.rb +292 -0
- data/app/models/spree/payment/processing.rb +210 -0
- data/app/models/spree/payment_capture_event.rb +9 -0
- data/app/models/spree/payment_method.rb +79 -0
- data/app/models/spree/payment_method/check.rb +31 -0
- data/app/models/spree/payment_method/store_credit.rb +127 -0
- data/app/models/spree/preference.rb +5 -0
- data/app/models/spree/preferences/configuration.rb +78 -0
- data/app/models/spree/preferences/preferable.rb +128 -0
- data/app/models/spree/preferences/preferable_class_methods.rb +64 -0
- data/app/models/spree/preferences/scoped_store.rb +33 -0
- data/app/models/spree/preferences/store.rb +93 -0
- data/app/models/spree/price.rb +62 -0
- data/app/models/spree/product.rb +347 -0
- data/app/models/spree/product/scopes.rb +262 -0
- data/app/models/spree/product_option_type.rb +7 -0
- data/app/models/spree/product_property.rb +25 -0
- data/app/models/spree/product_scope/scopes.rb +47 -0
- data/app/models/spree/promotion.rb +229 -0
- data/app/models/spree/promotion/actions/create_adjustment.rb +63 -0
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +80 -0
- data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +129 -0
- data/app/models/spree/promotion/actions/free_shipping.rb +41 -0
- data/app/models/spree/promotion/rules/first_order.rb +37 -0
- data/app/models/spree/promotion/rules/item_total.rb +61 -0
- data/app/models/spree/promotion/rules/one_use_per_user.rb +24 -0
- data/app/models/spree/promotion/rules/option_value.rb +50 -0
- data/app/models/spree/promotion/rules/product.rb +64 -0
- data/app/models/spree/promotion/rules/taxon.rb +69 -0
- data/app/models/spree/promotion/rules/user.rb +30 -0
- data/app/models/spree/promotion/rules/user_logged_in.rb +18 -0
- data/app/models/spree/promotion_action.rb +23 -0
- data/app/models/spree/promotion_builder.rb +55 -0
- data/app/models/spree/promotion_category.rb +6 -0
- data/app/models/spree/promotion_chooser.rb +30 -0
- data/app/models/spree/promotion_code.rb +39 -0
- data/app/models/spree/promotion_code/code_builder.rb +62 -0
- data/app/models/spree/promotion_handler/cart.rb +65 -0
- data/app/models/spree/promotion_handler/coupon.rb +119 -0
- data/app/models/spree/promotion_handler/free_shipping.rb +43 -0
- data/app/models/spree/promotion_handler/page.rb +24 -0
- data/app/models/spree/promotion_rule.rb +44 -0
- data/app/models/spree/property.rb +20 -0
- data/app/models/spree/prototype.rb +9 -0
- data/app/models/spree/refund.rb +96 -0
- data/app/models/spree/refund_reason.rb +13 -0
- data/app/models/spree/reimbursement.rb +188 -0
- data/app/models/spree/reimbursement/credit.rb +25 -0
- data/app/models/spree/reimbursement/reimbursement_type_engine.rb +56 -0
- data/app/models/spree/reimbursement/reimbursement_type_validator.rb +15 -0
- data/app/models/spree/reimbursement_performer.rb +43 -0
- data/app/models/spree/reimbursement_tax_calculator.rb +38 -0
- data/app/models/spree/reimbursement_type.rb +16 -0
- data/app/models/spree/reimbursement_type/credit.rb +13 -0
- data/app/models/spree/reimbursement_type/exchange.rb +9 -0
- data/app/models/spree/reimbursement_type/original_payment.rb +13 -0
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +70 -0
- data/app/models/spree/reimbursement_type/store_credit.rb +27 -0
- data/app/models/spree/return_authorization.rb +108 -0
- data/app/models/spree/return_authorization_reason.rb +7 -0
- data/app/models/spree/return_item.rb +311 -0
- data/app/models/spree/return_item/eligibility_validator/base_validator.rb +24 -0
- data/app/models/spree/return_item/eligibility_validator/default.rb +30 -0
- data/app/models/spree/return_item/eligibility_validator/inventory_shipped.rb +16 -0
- data/app/models/spree/return_item/eligibility_validator/no_reimbursements.rb +17 -0
- data/app/models/spree/return_item/eligibility_validator/order_completed.rb +16 -0
- data/app/models/spree/return_item/eligibility_validator/rma_required.rb +17 -0
- data/app/models/spree/return_item/eligibility_validator/time_since_purchase.rb +16 -0
- data/app/models/spree/return_item/exchange_variant_eligibility/same_option_value.rb +34 -0
- data/app/models/spree/return_item/exchange_variant_eligibility/same_product.rb +9 -0
- data/app/models/spree/returns_calculator.rb +8 -0
- data/app/models/spree/role.rb +10 -0
- data/app/models/spree/role_user.rb +17 -0
- data/app/models/spree/shipment.rb +427 -0
- data/app/models/spree/shipping_calculator.rb +22 -0
- data/app/models/spree/shipping_category.rb +8 -0
- data/app/models/spree/shipping_manifest.rb +23 -0
- data/app/models/spree/shipping_method.rb +69 -0
- data/app/models/spree/shipping_method_category.rb +6 -0
- data/app/models/spree/shipping_rate.rb +57 -0
- data/app/models/spree/state.rb +30 -0
- data/app/models/spree/state_change.rb +15 -0
- data/app/models/spree/static_model_preferences.rb +32 -0
- data/app/models/spree/stock/adjuster.rb +28 -0
- data/app/models/spree/stock/availability_validator.rb +35 -0
- data/app/models/spree/stock/content_item.rb +48 -0
- data/app/models/spree/stock/coordinator.rb +96 -0
- data/app/models/spree/stock/differentiator.rb +44 -0
- data/app/models/spree/stock/estimator.rb +70 -0
- data/app/models/spree/stock/inventory_unit_builder.rb +22 -0
- data/app/models/spree/stock/inventory_validator.rb +14 -0
- data/app/models/spree/stock/package.rb +131 -0
- data/app/models/spree/stock/packer.rb +49 -0
- data/app/models/spree/stock/prioritizer.rb +47 -0
- data/app/models/spree/stock/quantifier.rb +47 -0
- data/app/models/spree/stock/splitter/backordered.rb +23 -0
- data/app/models/spree/stock/splitter/base.rb +28 -0
- data/app/models/spree/stock/splitter/shipping_category.rb +32 -0
- data/app/models/spree/stock/splitter/weight.rb +32 -0
- data/app/models/spree/stock_item.rb +107 -0
- data/app/models/spree/stock_location.rb +128 -0
- data/app/models/spree/stock_movement.rb +26 -0
- data/app/models/spree/stock_transfer.rb +108 -0
- data/app/models/spree/store.rb +38 -0
- data/app/models/spree/store_credit.rb +267 -0
- data/app/models/spree/store_credit_category.rb +17 -0
- data/app/models/spree/store_credit_event.rb +52 -0
- data/app/models/spree/store_credit_type.rb +6 -0
- data/app/models/spree/tax_category.rb +19 -0
- data/app/models/spree/tax_rate.rb +199 -0
- data/app/models/spree/taxon.rb +103 -0
- data/app/models/spree/taxonomy.rb +27 -0
- data/app/models/spree/tracker.rb +8 -0
- data/app/models/spree/transfer_item.rb +58 -0
- data/app/models/spree/unit_cancel.rb +32 -0
- data/app/models/spree/user_stock_location.rb +6 -0
- data/app/models/spree/validations/db_maximum_length_validator.rb +22 -0
- data/app/models/spree/variant.rb +356 -0
- data/app/models/spree/variant/scopes.rb +40 -0
- data/app/models/spree/zone.rb +138 -0
- data/app/models/spree/zone_member.rb +11 -0
- data/app/views/layouts/spree/base_mailer.html.erb +784 -0
- data/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb +19 -0
- data/app/views/spree/carton_mailer/shipped_email.text.erb +16 -0
- data/app/views/spree/order_mailer/cancel_email.html.erb +45 -0
- data/app/views/spree/order_mailer/cancel_email.text.erb +16 -0
- data/app/views/spree/order_mailer/confirm_email.html.erb +84 -0
- data/app/views/spree/order_mailer/confirm_email.text.erb +38 -0
- data/app/views/spree/order_mailer/inventory_cancellation_email.text.erb +10 -0
- data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +22 -0
- data/app/views/spree/shared/_base_mailer_footer.html.erb +20 -0
- data/app/views/spree/shared/_base_mailer_header.html.erb +31 -0
- data/app/views/spree/shared/_error_messages.html.erb +11 -0
- data/app/views/spree/shipment_mailer/shipped_email.html.erb +34 -0
- data/app/views/spree/test_mailer/test_email.html.erb +40 -0
- data/app/views/spree/test_mailer/test_email.text.erb +4 -0
- data/config/initializers/friendly_id.rb +88 -0
- data/config/initializers/premailer_assets.rb +1 -0
- data/config/initializers/user_class_extensions.rb +42 -0
- data/config/locales/en.yml +1534 -0
- data/config/routes.rb +1 -0
- data/db/default/spree/countries.rb +19 -0
- data/db/default/spree/roles.rb +2 -0
- data/db/default/spree/states.rb +16 -0
- data/db/default/spree/store_credit.rb +16 -0
- data/db/default/spree/stores.rb +9 -0
- data/db/default/spree/zones.rb +17 -0
- data/db/migrate/20120831092320_spree_one_two.rb +481 -0
- data/db/migrate/20120831092359_spree_promo_one_two.rb +45 -0
- data/db/migrate/20120905145253_add_tax_rate_label.rb +5 -0
- data/db/migrate/20120905151823_add_toggle_tax_rate_display.rb +5 -0
- data/db/migrate/20120929093553_remove_unused_preference_columns.rb +8 -0
- data/db/migrate/20121009142519_add_lock_version_to_variant.rb +5 -0
- data/db/migrate/20121010142909_add_states_required_to_countries.rb +5 -0
- data/db/migrate/20121012071449_add_on_demand_to_product_and_variant.rb +6 -0
- data/db/migrate/20121017010007_remove_not_null_constraint_from_products_on_hand.rb +11 -0
- data/db/migrate/20121031162139_split_prices_from_variants.rb +31 -0
- data/db/migrate/20121107003422_remove_not_null_from_spree_prices_amount.rb +9 -0
- data/db/migrate/20121107184631_add_currency_to_line_items.rb +5 -0
- data/db/migrate/20121107194006_add_currency_to_orders.rb +5 -0
- data/db/migrate/20121109173623_add_cost_currency_to_variants.rb +5 -0
- data/db/migrate/20121111231553_remove_display_on_from_payment_methods.rb +5 -0
- data/db/migrate/20121124203911_add_position_to_taxonomies.rb +5 -0
- data/db/migrate/20121126040517_add_last_ip_to_spree_orders.rb +5 -0
- data/db/migrate/20121213162028_add_state_to_spree_adjustments.rb +6 -0
- data/db/migrate/20130114053446_add_display_on_to_spree_payment_methods.rb +9 -0
- data/db/migrate/20130120201805_add_position_to_product_properties.spree.rb +6 -0
- data/db/migrate/20130203232234_add_identifier_to_spree_payments.rb +5 -0
- data/db/migrate/20130207155350_add_order_id_index_to_payments.rb +9 -0
- data/db/migrate/20130208032954_add_primary_to_spree_products_taxons.rb +5 -0
- data/db/migrate/20130211190146_create_spree_stock_items.rb +14 -0
- data/db/migrate/20130211191120_create_spree_stock_locations.rb +11 -0
- data/db/migrate/20130213191427_create_default_stock.rb +34 -0
- data/db/migrate/20130222032153_add_order_id_index_to_shipments.rb +5 -0
- data/db/migrate/20130226032817_change_meta_description_on_spree_products_to_text.rb +5 -0
- data/db/migrate/20130226191231_add_stock_location_id_to_spree_shipments.rb +5 -0
- data/db/migrate/20130227143905_add_pending_to_inventory_unit.rb +6 -0
- data/db/migrate/20130228164411_remove_on_demand_from_product_and_variant.rb +6 -0
- data/db/migrate/20130228210442_create_shipping_method_zone.rb +21 -0
- data/db/migrate/20130301162745_remove_shipping_category_id_from_shipping_method.rb +5 -0
- data/db/migrate/20130301162924_create_shipping_method_categories.rb +13 -0
- data/db/migrate/20130301205200_add_tracking_url_to_spree_shipping_methods.rb +5 -0
- data/db/migrate/20130304162240_create_spree_shipping_rates.rb +24 -0
- data/db/migrate/20130304192936_remove_category_match_attributes_from_shipping_method.rb +7 -0
- data/db/migrate/20130305143310_create_stock_movements.rb +12 -0
- data/db/migrate/20130306181701_add_address_fields_to_stock_location.rb +22 -0
- data/db/migrate/20130306191917_add_active_field_to_stock_locations.rb +5 -0
- data/db/migrate/20130306195650_add_backorderable_to_stock_item.rb +5 -0
- data/db/migrate/20130307161754_add_default_quantity_to_stock_movement.rb +5 -0
- data/db/migrate/20130318151756_add_source_and_destination_to_stock_movements.rb +8 -0
- data/db/migrate/20130319062004_change_orders_total_precision.rb +8 -0
- data/db/migrate/20130319063911_change_spree_payments_amount_precision.rb +7 -0
- data/db/migrate/20130319064308_change_spree_return_authorization_amount_precision.rb +7 -0
- data/db/migrate/20130319082943_change_adjustments_amount_precision.rb +7 -0
- data/db/migrate/20130319183250_add_originator_to_stock_movement.rb +7 -0
- data/db/migrate/20130319190507_drop_source_and_destination_from_stock_movement.rb +15 -0
- data/db/migrate/20130325163316_migrate_inventory_unit_sold_to_on_hand.rb +9 -0
- data/db/migrate/20130326175857_add_stock_location_to_rma.rb +5 -0
- data/db/migrate/20130328130308_update_shipment_state_for_canceled_orders.rb +15 -0
- data/db/migrate/20130328195253_add_seo_metas_to_taxons.rb +9 -0
- data/db/migrate/20130329134939_remove_stock_item_and_variant_lock.rb +14 -0
- data/db/migrate/20130413230529_add_name_to_spree_credit_cards.rb +5 -0
- data/db/migrate/20130414000512_update_name_fields_on_spree_credit_cards.rb +13 -0
- data/db/migrate/20130417120034_add_index_to_source_columns_on_adjustments.rb +5 -0
- data/db/migrate/20130417120035_update_adjustment_states.rb +16 -0
- data/db/migrate/20130417123427_add_shipping_rates_to_shipments.rb +15 -0
- data/db/migrate/20130418125341_create_spree_stock_transfers.rb +14 -0
- data/db/migrate/20130423110707_drop_products_count_on_hand.rb +5 -0
- data/db/migrate/20130423223847_set_default_shipping_rate_cost.rb +5 -0
- data/db/migrate/20130509115210_add_number_to_stock_transfer.rb +23 -0
- data/db/migrate/20130514151929_add_sku_index_to_spree_variants.rb +5 -0
- data/db/migrate/20130515180736_add_backorderable_default_to_spree_stock_location.rb +5 -0
- data/db/migrate/20130516151222_add_propage_all_variants_to_spree_stock_location.rb +5 -0
- data/db/migrate/20130611054351_rename_shipping_methods_zones_to_spree_shipping_methods_zones.rb +5 -0
- data/db/migrate/20130611185927_add_user_id_index_to_spree_orders.rb +5 -0
- data/db/migrate/20130618041418_add_updated_at_to_spree_countries.rb +9 -0
- data/db/migrate/20130619012236_add_updated_at_to_spree_states.rb +9 -0
- data/db/migrate/20130626232741_add_cvv_result_code_and_cvv_result_message_to_spree_payments.rb +6 -0
- data/db/migrate/20130628021056_add_unique_index_to_permalink_on_spree_products.rb +5 -0
- data/db/migrate/20130628022817_add_unique_index_to_orders_shipments_and_stock_transfers.rb +7 -0
- data/db/migrate/20130708052307_add_deleted_at_to_spree_tax_rates.rb +5 -0
- data/db/migrate/20130711200933_remove_lock_version_from_inventory_units.rb +6 -0
- data/db/migrate/20130718042445_add_cost_price_to_line_item.rb +5 -0
- data/db/migrate/20130718233855_set_backorderable_to_default_to_false.rb +6 -0
- data/db/migrate/20130725031716_add_created_by_id_to_spree_orders.rb +5 -0
- data/db/migrate/20130729214043_index_completed_at_on_spree_orders.rb +5 -0
- data/db/migrate/20130802014537_add_tax_category_id_to_spree_line_items.rb +5 -0
- data/db/migrate/20130802022321_migrate_tax_categories_to_line_items.rb +10 -0
- data/db/migrate/20130806022521_drop_spree_mail_methods.rb +12 -0
- data/db/migrate/20130806145853_set_default_stock_location_on_shipments.rb +8 -0
- data/db/migrate/20130807024301_upgrade_adjustments.rb +40 -0
- data/db/migrate/20130807024302_rename_adjustment_fields.rb +14 -0
- data/db/migrate/20130809164245_add_admin_name_column_to_spree_shipping_methods.rb +5 -0
- data/db/migrate/20130809164330_add_admin_name_column_to_spree_stock_locations.rb +5 -0
- data/db/migrate/20130813004002_add_shipment_total_to_spree_orders.rb +5 -0
- data/db/migrate/20130813140619_expand_order_number_size.rb +9 -0
- data/db/migrate/20130813232134_rename_activators_to_promotions.rb +5 -0
- data/db/migrate/20130815000406_add_adjustment_total_to_line_items.rb +5 -0
- data/db/migrate/20130815024413_add_adjustment_total_to_shipments.rb +5 -0
- data/db/migrate/20130826062534_add_depth_to_spree_taxons.rb +16 -0
- data/db/migrate/20130828234942_add_tax_total_to_line_items_shipments_and_orders.rb +8 -0
- data/db/migrate/20130830001033_add_shipping_category_to_shipping_methods_and_products.rb +15 -0
- data/db/migrate/20130830001159_migrate_old_shipping_calculators.rb +19 -0
- data/db/migrate/20130903183026_add_code_to_spree_promotion_rules.rb +5 -0
- data/db/migrate/20130909115621_change_states_required_for_countries.rb +9 -0
- data/db/migrate/20130915032339_add_deleted_at_to_spree_stock_items.rb +5 -0
- data/db/migrate/20130917024658_remove_promotions_event_name_field.rb +5 -0
- data/db/migrate/20130924040529_add_promo_total_to_line_items_and_shipments_and_orders.rb +7 -0
- data/db/migrate/20131001013410_remove_unused_credit_card_fields.rb +16 -0
- data/db/migrate/20131026154747_add_track_inventory_to_variant.rb +5 -0
- data/db/migrate/20131107132123_add_tax_category_to_variants.rb +6 -0
- data/db/migrate/20131113035136_add_channel_to_spree_orders.rb +5 -0
- data/db/migrate/20131118043959_add_included_to_adjustments.rb +5 -0
- data/db/migrate/20131118050234_rename_tax_total_fields.rb +11 -0
- data/db/migrate/20131118183431_add_line_item_id_to_spree_inventory_units.rb +21 -0
- data/db/migrate/20131120234456_add_updated_at_to_variants.rb +5 -0
- data/db/migrate/20131127001002_add_position_to_classifications.rb +5 -0
- data/db/migrate/20131211112807_create_spree_orders_promotions.rb +8 -0
- data/db/migrate/20131211192741_unique_shipping_method_categories.rb +24 -0
- data/db/migrate/20131218054603_add_item_count_to_spree_orders.rb +5 -0
- data/db/migrate/20140106065820_remove_value_type_from_spree_preferences.rb +8 -0
- data/db/migrate/20140106224208_rename_permalink_to_slug_for_products.rb +5 -0
- data/db/migrate/20140120160805_add_index_to_variant_id_and_currency_on_prices.rb +5 -0
- data/db/migrate/20140124023232_rename_activator_id_in_rules_and_actions_to_promotion_id.rb +6 -0
- data/db/migrate/20140129024326_add_deleted_at_to_spree_prices.rb +5 -0
- data/db/migrate/20140203161722_add_approver_id_and_approved_at_to_orders.rb +6 -0
- data/db/migrate/20140204115338_add_confirmation_delivered_to_spree_orders.rb +5 -0
- data/db/migrate/20140204192230_add_auto_capture_to_payment_methods.rb +5 -0
- data/db/migrate/20140205120320_create_spree_payment_capture_events.rb +12 -0
- data/db/migrate/20140205144710_add_uncaptured_amount_to_payments.rb +5 -0
- data/db/migrate/20140205181631_default_variant_weight_to_zero.rb +11 -0
- data/db/migrate/20140207085910_add_tax_category_id_to_shipping_methods.rb +5 -0
- data/db/migrate/20140207093021_add_tax_rate_id_to_shipping_rates.rb +5 -0
- data/db/migrate/20140211040159_add_pre_tax_amount_to_line_items_and_shipments.rb +6 -0
- data/db/migrate/20140213184916_add_more_indexes.rb +13 -0
- data/db/migrate/20140219060952_add_considered_risky_to_orders.rb +5 -0
- data/db/migrate/20140227112348_add_preference_store_to_everything.rb +8 -0
- data/db/migrate/20140307235515_add_user_id_to_spree_credit_cards.rb +13 -0
- data/db/migrate/20140309023735_migrate_old_preferences.rb +23 -0
- data/db/migrate/20140309024355_create_spree_stores.rb +25 -0
- data/db/migrate/20140309033438_create_store_from_preferences.rb +30 -0
- data/db/migrate/20140315053743_add_timestamps_to_spree_assets.rb +6 -0
- data/db/migrate/20140318191500_create_spree_taxons_promotion_rules.rb +8 -0
- data/db/migrate/20140331100557_add_additional_store_fields.rb +8 -0
- data/db/migrate/20140410141842_add_many_missing_indexes.rb +17 -0
- data/db/migrate/20140410150358_correct_some_polymorphic_index_and_add_more_missing.rb +66 -0
- data/db/migrate/20140415041315_add_user_id_created_by_id_index_to_order.rb +5 -0
- data/db/migrate/20140508151342_change_spree_price_amount_precision.rb +8 -0
- data/db/migrate/20140518174634_add_token_to_spree_orders.rb +5 -0
- data/db/migrate/20140530024945_move_order_token_from_tokenized_permission.rb +29 -0
- data/db/migrate/20140601011216_set_shipment_total_for_users_upgrading.rb +10 -0
- data/db/migrate/20140604135309_drop_credit_card_first_name_and_last_name.rb +6 -0
- data/db/migrate/20140609201656_add_deleted_at_to_spree_promotion_actions.rb +6 -0
- data/db/migrate/20140616202624_remove_uncaptured_amount_from_spree_payments.rb +5 -0
- data/db/migrate/20140625214618_create_spree_refunds.rb +12 -0
- data/db/migrate/20140702140656_create_spree_return_authorization_inventory_unit.rb +12 -0
- data/db/migrate/20140707125621_rename_return_authorization_inventory_unit_to_return_items.rb +5 -0
- data/db/migrate/20140708132019_create_order_mutex.rb +11 -0
- data/db/migrate/20140709160534_backfill_line_item_pre_tax_amount.rb +10 -0
- data/db/migrate/20140710041921_recreate_spree_return_authorizations.rb +55 -0
- data/db/migrate/20140710181204_add_amount_fields_to_return_items.rb +7 -0
- data/db/migrate/20140710190048_drop_return_authorization_amount.rb +5 -0
- data/db/migrate/20140713140455_create_spree_return_authorization_reasons.rb +28 -0
- data/db/migrate/20140713140527_create_spree_refund_reasons.rb +14 -0
- data/db/migrate/20140713142214_rename_return_authorization_reason.rb +5 -0
- data/db/migrate/20140715182625_create_spree_promotion_categories.rb +11 -0
- data/db/migrate/20140716204111_drop_received_at_on_return_items.rb +9 -0
- data/db/migrate/20140716212330_add_reception_and_acceptance_status_to_return_items.rb +6 -0
- data/db/migrate/20140717155155_create_default_refund_reason.rb +9 -0
- data/db/migrate/20140717185932_add_default_to_spree_stock_locations.rb +7 -0
- data/db/migrate/20140718133010_create_spree_customer_returns.rb +9 -0
- data/db/migrate/20140718133349_add_customer_return_id_to_return_item.rb +6 -0
- data/db/migrate/20140718195325_create_friendly_id_slugs.rb +15 -0
- data/db/migrate/20140723004419_rename_spree_refund_return_authorization_id.rb +5 -0
- data/db/migrate/20140723152808_increase_return_item_pre_tax_amount_precision.rb +13 -0
- data/db/migrate/20140723214541_copy_product_slugs_to_slug_history.rb +15 -0
- data/db/migrate/20140725131539_create_spree_reimbursements.rb +21 -0
- data/db/migrate/20140728225422_add_promotionable_to_spree_products.rb +5 -0
- data/db/migrate/20140729133613_add_exchange_inventory_unit_foreign_keys.rb +7 -0
- data/db/migrate/20140730155938_add_acceptance_status_errors_to_return_item.rb +5 -0
- data/db/migrate/20140731150017_create_spree_reimbursement_types.rb +20 -0
- data/db/migrate/20140804185157_add_default_to_shipment_cost.rb +10 -0
- data/db/migrate/20140805171035_add_default_to_spree_credit_cards.rb +5 -0
- data/db/migrate/20140805171219_make_existing_credit_cards_default.rb +10 -0
- data/db/migrate/20140806144901_add_type_to_reimbursement_type.rb +9 -0
- data/db/migrate/20140808184039_create_spree_reimbursement_credits.rb +10 -0
- data/db/migrate/20140827170513_add_meta_title_to_spree_products.rb +7 -0
- data/db/migrate/20140924164824_add_code_to_spree_tax_categories.rb +5 -0
- data/db/migrate/20140927193717_default_pre_tax_amount_should_be_zero.rb +6 -0
- data/db/migrate/20141002191113_add_code_to_spree_shipping_methods.rb +5 -0
- data/db/migrate/20141007230328_add_cancel_audit_fields_to_spree_orders.rb +6 -0
- data/db/migrate/20141009204607_add_store_id_to_orders.rb +8 -0
- data/db/migrate/20141012083513_create_spree_taxons_prototypes.rb +8 -0
- data/db/migrate/20141021194502_add_state_lock_version_to_order.rb +5 -0
- data/db/migrate/20141023005240_add_counter_cache_from_spree_variants_to_spree_stock_items.rb +8 -0
- data/db/migrate/20141101231208_fix_adjustment_order_presence.rb +13 -0
- data/db/migrate/20141105213646_update_classifications_positions.rb +9 -0
- data/db/migrate/20141120135441_add_guest_token_index_to_spree_orders.rb +5 -0
- data/db/migrate/20141231151320_add_default_column_to_price.rb +5 -0
- data/db/migrate/20150112194216_add_position_to_stock_location.rb +5 -0
- data/db/migrate/20150113002122_create_spree_promotion_codes.rb +13 -0
- data/db/migrate/20150113002123_create_adjustment_promotion_code_association.rb +6 -0
- data/db/migrate/20150121202544_add_restock_inventory_to_stock_location.rb +5 -0
- data/db/migrate/20150122202432_add_code_to_spree_promotion_categories.rb +5 -0
- data/db/migrate/20150127161843_create_order_stock_locations.rb +12 -0
- data/db/migrate/20150203151219_add_fulfillable_to_stock_location.rb +5 -0
- data/db/migrate/20150205210527_add_code_to_refund_reason.rb +5 -0
- data/db/migrate/20150213160148_add_promotion_code_id_to_orders_promotions.rb +7 -0
- data/db/migrate/20150213163612_add_approver_name_to_spree_orders.rb +5 -0
- data/db/migrate/20150225205344_move_promotion_code_to_promotion_code_value.rb +65 -0
- data/db/migrate/20150226195213_downcase_promotion_codes_values.rb +11 -0
- data/db/migrate/20150227161934_add_order_ids_to_adjustments_where_missing.rb +9 -0
- data/db/migrate/20150303212749_add_per_code_usage_limit_to_promotions.rb +5 -0
- data/db/migrate/20150303212826_remove_usage_limit_from_promotion_codes.rb +5 -0
- data/db/migrate/20150304211616_add_timestamps_to_order_promotions.rb +6 -0
- data/db/migrate/20150305043021_create_spree_cartons.rb +24 -0
- data/db/migrate/20150305210403_add_timestamps_to_spree_roles_users.rb +7 -0
- data/db/migrate/20150313140507_remove_considered_risky_from_spree_orders.rb +5 -0
- data/db/migrate/20150313192827_add_index_to_inventory_units_carton_id.rb +5 -0
- data/db/migrate/20150313201235_add_imported_from_shipment_id_to_cartons.rb +8 -0
- data/db/migrate/20150313201503_copy_shipped_shipments_to_cartons.rb +13 -0
- data/db/migrate/20150330144639_create_spree_user_stock_locations.rb +10 -0
- data/db/migrate/20150331134544_add_stock_location_code.rb +5 -0
- data/db/migrate/20150402210430_create_unit_cancels.rb +10 -0
- data/db/migrate/20150407173305_add_fields_to_stock_transfer.rb +12 -0
- data/db/migrate/20150407173531_create_transfer_items.rb +14 -0
- data/db/migrate/20150424143547_drop_stock_transfer_type.rb +10 -0
- data/db/migrate/20150424161102_add_stock_transfer_finalized_at.rb +8 -0
- data/db/migrate/20150429125822_rename_stock_transfer_reference.rb +5 -0
- data/db/migrate/20150430233803_create_line_item_actions.rb +10 -0
- data/db/migrate/20150506181159_create_spree_store_credit_categories.rb +10 -0
- data/db/migrate/20150506181244_create_spree_store_credits.rb +19 -0
- data/db/migrate/20150506181539_create_spree_store_credit_events.rb +17 -0
- data/db/migrate/20150506181611_create_spree_store_credit_payment_method.rb +13 -0
- data/db/migrate/20150506181715_create_store_credit_types.rb +17 -0
- data/db/migrate/20150506182045_create_store_credit_reimbursement_type.rb +5 -0
- data/db/migrate/20150508044622_add_resellable_to_return_items.rb +5 -0
- data/db/migrate/20150514185559_add_invalidated_at_to_spree_store_credits.rb +5 -0
- data/db/migrate/20150514201836_migrate_deleted_store_credits_to_invalidated.rb +13 -0
- data/db/migrate/20150515170322_add_check_stock_on_transfer.rb +5 -0
- data/db/migrate/20150528125647_delete_inventory_units_without_shipment.rb +25 -0
- data/db/migrate/20150601191251_add_deleted_at_to_stock_transfers.rb +5 -0
- data/db/migrate/20150601204148_add_deleted_at_to_transfer_items.rb +5 -0
- data/db/migrate/20150609193231_add_preferences_to_promotion_actions.rb +5 -0
- data/db/migrate/20150610182638_add_id_to_spree_option_values_variants.rb +5 -0
- data/db/migrate/20150611200247_add_frontend_viewable_to_spree_orders.rb +5 -0
- data/db/migrate/20150612205731_remove_spree_configurations.rb +15 -0
- data/db/migrate/20150618191713_remove_credit_card_address_id.rb +7 -0
- data/db/migrate/20150626214817_remove_counter_cache_from_spree_variants_to_spree_stock_items.rb +10 -0
- data/db/seeds.rb +5 -0
- data/lib/generators/spree/custom_user/custom_user_generator.rb +56 -0
- data/lib/generators/spree/custom_user/templates/authentication_helpers.rb.tt +36 -0
- data/lib/generators/spree/custom_user/templates/initializer.rb.tt +1 -0
- data/lib/generators/spree/custom_user/templates/migration.rb.tt +7 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +140 -0
- data/lib/generators/spree/dummy/templates/initializers/custom_user.rb +1 -0
- data/lib/generators/spree/dummy/templates/initializers/devise.rb +3 -0
- data/lib/generators/spree/dummy/templates/rails/application.rb +10 -0
- data/lib/generators/spree/dummy/templates/rails/boot.rb +6 -0
- data/lib/generators/spree/dummy/templates/rails/database.yml +65 -0
- data/lib/generators/spree/dummy/templates/rails/routes.rb +2 -0
- data/lib/generators/spree/dummy/templates/rails/script/rails +6 -0
- data/lib/generators/spree/dummy/templates/rails/test.rb +34 -0
- data/lib/generators/spree/install/install_generator.rb +191 -0
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +41 -0
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +13 -0
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +13 -0
- data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/backend/all.css +12 -0
- data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +12 -0
- data/lib/solidus_core.rb +1 -0
- data/lib/spree/core.rb +95 -0
- data/lib/spree/core/controller_helpers/auth.rb +83 -0
- data/lib/spree/core/controller_helpers/common.rb +74 -0
- data/lib/spree/core/controller_helpers/order.rb +106 -0
- data/lib/spree/core/controller_helpers/respond_with.rb +65 -0
- data/lib/spree/core/controller_helpers/search.rb +14 -0
- data/lib/spree/core/controller_helpers/store.rb +19 -0
- data/lib/spree/core/controller_helpers/strong_parameters.rb +42 -0
- data/lib/spree/core/delegate_belongs_to.rb +95 -0
- data/lib/spree/core/engine.rb +114 -0
- data/lib/spree/core/environment.rb +15 -0
- data/lib/spree/core/environment/calculators.rb +12 -0
- data/lib/spree/core/environment_extension.rb +25 -0
- data/lib/spree/core/importer.rb +9 -0
- data/lib/spree/core/importer/order.rb +202 -0
- data/lib/spree/core/importer/product.rb +62 -0
- data/lib/spree/core/permalinks.rb +71 -0
- data/lib/spree/core/product_duplicator.rb +74 -0
- data/lib/spree/core/product_filters.rb +194 -0
- data/lib/spree/core/routes.rb +46 -0
- data/lib/spree/core/search/base.rb +97 -0
- data/lib/spree/core/search/variant.rb +46 -0
- data/lib/spree/core/unreturned_item_charger.rb +102 -0
- data/lib/spree/core/validators/email.rb +7 -0
- data/lib/spree/core/version.rb +5 -0
- data/lib/spree/i18n.rb +37 -0
- data/lib/spree/i18n/base.rb +17 -0
- data/lib/spree/i18n/initializer.rb +1 -0
- data/lib/spree/localized_number.rb +24 -0
- data/lib/spree/migrations.rb +76 -0
- data/lib/spree/money.rb +72 -0
- data/lib/spree/permitted_attributes.rb +114 -0
- data/lib/spree/promo/environment.rb +9 -0
- data/lib/spree/responder.rb +45 -0
- data/lib/spree/testing_support/ability_helpers.rb +105 -0
- data/lib/spree/testing_support/authorization_helpers.rb +63 -0
- data/lib/spree/testing_support/bar_ability.rb +14 -0
- data/lib/spree/testing_support/caching.rb +47 -0
- data/lib/spree/testing_support/capybara_ext.rb +163 -0
- data/lib/spree/testing_support/common_rake.rb +40 -0
- data/lib/spree/testing_support/controller_requests.rb +83 -0
- data/lib/spree/testing_support/extension_rake.rb +10 -0
- data/lib/spree/testing_support/factories.rb +20 -0
- data/lib/spree/testing_support/factories/address_factory.rb +22 -0
- data/lib/spree/testing_support/factories/adjustment_factory.rb +26 -0
- data/lib/spree/testing_support/factories/calculator_factory.rb +24 -0
- data/lib/spree/testing_support/factories/carton_factory.rb +21 -0
- data/lib/spree/testing_support/factories/country_factory.rb +9 -0
- data/lib/spree/testing_support/factories/credit_card_factory.rb +10 -0
- data/lib/spree/testing_support/factories/customer_return_factory.rb +31 -0
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +10 -0
- data/lib/spree/testing_support/factories/line_item_factory.rb +14 -0
- data/lib/spree/testing_support/factories/options_factory.rb +13 -0
- data/lib/spree/testing_support/factories/order_factory.rb +100 -0
- data/lib/spree/testing_support/factories/order_promotion_factory.rb +6 -0
- data/lib/spree/testing_support/factories/payment_factory.rb +28 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +27 -0
- data/lib/spree/testing_support/factories/price_factory.rb +7 -0
- data/lib/spree/testing_support/factories/product_factory.rb +36 -0
- data/lib/spree/testing_support/factories/product_option_type_factory.rb +6 -0
- data/lib/spree/testing_support/factories/product_property_factory.rb +6 -0
- data/lib/spree/testing_support/factories/promotion_category_factory.rb +6 -0
- data/lib/spree/testing_support/factories/promotion_code_factory.rb +6 -0
- data/lib/spree/testing_support/factories/promotion_factory.rb +62 -0
- data/lib/spree/testing_support/factories/property_factory.rb +6 -0
- data/lib/spree/testing_support/factories/prototype_factory.rb +6 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +14 -0
- data/lib/spree/testing_support/factories/reimbursement_factory.rb +16 -0
- data/lib/spree/testing_support/factories/reimbursement_type_factory.rb +7 -0
- data/lib/spree/testing_support/factories/return_authorization_factory.rb +18 -0
- data/lib/spree/testing_support/factories/return_item_factory.rb +16 -0
- data/lib/spree/testing_support/factories/role_factory.rb +9 -0
- data/lib/spree/testing_support/factories/shipment_factory.rb +28 -0
- data/lib/spree/testing_support/factories/shipping_category_factory.rb +5 -0
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +25 -0
- data/lib/spree/testing_support/factories/state_factory.rb +13 -0
- data/lib/spree/testing_support/factories/stock_factory.rb +31 -0
- data/lib/spree/testing_support/factories/stock_item_factory.rb +9 -0
- data/lib/spree/testing_support/factories/stock_location_factory.rb +28 -0
- data/lib/spree/testing_support/factories/stock_movement_factory.rb +11 -0
- data/lib/spree/testing_support/factories/stock_transfer_factory.rb +28 -0
- data/lib/spree/testing_support/factories/store_credit_category_factory.rb +6 -0
- data/lib/spree/testing_support/factories/store_credit_event_factory.rb +15 -0
- data/lib/spree/testing_support/factories/store_credit_factory.rb +10 -0
- data/lib/spree/testing_support/factories/store_credit_type_factory.rb +13 -0
- data/lib/spree/testing_support/factories/store_factory.rb +8 -0
- data/lib/spree/testing_support/factories/tax_category_factory.rb +7 -0
- data/lib/spree/testing_support/factories/tax_rate_factory.rb +8 -0
- data/lib/spree/testing_support/factories/taxon_factory.rb +7 -0
- data/lib/spree/testing_support/factories/taxonomy_factory.rb +5 -0
- data/lib/spree/testing_support/factories/tracker_factory.rb +7 -0
- data/lib/spree/testing_support/factories/user_factory.rb +22 -0
- data/lib/spree/testing_support/factories/variant_factory.rb +39 -0
- data/lib/spree/testing_support/factories/zone_factory.rb +17 -0
- data/lib/spree/testing_support/flash.rb +27 -0
- data/lib/spree/testing_support/i18n.rb +98 -0
- data/lib/spree/testing_support/mail.rb +20 -0
- data/lib/spree/testing_support/order_walkthrough.rb +78 -0
- data/lib/spree/testing_support/preferences.rb +29 -0
- data/lib/spree/testing_support/rspec-activemodel-mocks_patch.rb +8 -0
- data/lib/spree/testing_support/url_helpers.rb +9 -0
- data/lib/spree_core.rb +1 -0
- data/lib/tasks/core.rake +101 -0
- data/lib/tasks/email.rake +7 -0
- data/lib/tasks/exchanges.rake +48 -0
- data/lib/tasks/migrations/copy_shipped_shipments_to_cartons.rake +180 -0
- data/lib/tasks/order_capturing.rake +23 -0
- data/vendor/assets/javascripts/jquery-migrate-1.0.0.js +498 -0
- data/vendor/assets/javascripts/jquery.payment.js +497 -0
- data/vendor/assets/javascripts/jsuri.js +2 -0
- data/vendor/assets/stylesheets/normalize.css +375 -0
- data/vendor/assets/stylesheets/skeleton.css +242 -0
- metadata +993 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Products represent an entity for sale in a store. Products can have
|
|
3
|
+
# variations, called variants. Product properties include description,
|
|
4
|
+
# permalink, availability, shipping category, etc. that do not change by
|
|
5
|
+
# variant.
|
|
6
|
+
#
|
|
7
|
+
# @note this model uses {https://github.com/radar/paranoia paranoia}.
|
|
8
|
+
# +#destroy+ will only soft-destroy records and the default scope hides
|
|
9
|
+
# soft-destroyed records using +WHERE deleted_at IS NULL+.
|
|
10
|
+
class Product < Spree::Base
|
|
11
|
+
extend FriendlyId
|
|
12
|
+
friendly_id :slug_candidates, use: :history
|
|
13
|
+
|
|
14
|
+
acts_as_paranoid
|
|
15
|
+
|
|
16
|
+
has_many :product_option_types, dependent: :destroy, inverse_of: :product
|
|
17
|
+
has_many :option_types, through: :product_option_types
|
|
18
|
+
has_many :product_properties, dependent: :destroy, inverse_of: :product
|
|
19
|
+
has_many :properties, through: :product_properties
|
|
20
|
+
|
|
21
|
+
has_many :classifications, dependent: :delete_all, inverse_of: :product
|
|
22
|
+
has_many :taxons, through: :classifications
|
|
23
|
+
has_and_belongs_to_many :promotion_rules, join_table: :spree_products_promotion_rules
|
|
24
|
+
|
|
25
|
+
belongs_to :tax_category, class_name: 'Spree::TaxCategory'
|
|
26
|
+
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', inverse_of: :products
|
|
27
|
+
|
|
28
|
+
has_one :master,
|
|
29
|
+
-> { where is_master: true },
|
|
30
|
+
inverse_of: :product,
|
|
31
|
+
class_name: 'Spree::Variant'
|
|
32
|
+
|
|
33
|
+
has_many :variants,
|
|
34
|
+
-> { where(is_master: false).order("#{::Spree::Variant.quoted_table_name}.position ASC") },
|
|
35
|
+
inverse_of: :product,
|
|
36
|
+
class_name: 'Spree::Variant'
|
|
37
|
+
|
|
38
|
+
has_many :variants_including_master,
|
|
39
|
+
-> { order("#{::Spree::Variant.quoted_table_name}.position ASC") },
|
|
40
|
+
inverse_of: :product,
|
|
41
|
+
class_name: 'Spree::Variant',
|
|
42
|
+
dependent: :destroy
|
|
43
|
+
|
|
44
|
+
has_many :prices, -> { order('spree_variants.position, spree_variants.id, currency') }, through: :variants
|
|
45
|
+
|
|
46
|
+
has_many :stock_items, through: :variants_including_master
|
|
47
|
+
|
|
48
|
+
has_many :line_items, through: :variants_including_master
|
|
49
|
+
has_many :orders, through: :line_items
|
|
50
|
+
|
|
51
|
+
delegate_belongs_to :master, :sku, :price, :currency, :display_amount, :display_price, :weight, :height, :width, :depth, :is_master, :has_default_price?, :cost_currency, :price_in, :amount_in
|
|
52
|
+
|
|
53
|
+
delegate_belongs_to :master, :cost_price
|
|
54
|
+
|
|
55
|
+
delegate :images, to: :master, prefix: true
|
|
56
|
+
alias_method :images, :master_images
|
|
57
|
+
|
|
58
|
+
has_many :variant_images, -> { order(:position) }, source: :images, through: :variants_including_master
|
|
59
|
+
|
|
60
|
+
after_create :set_master_variant_defaults
|
|
61
|
+
after_create :add_associations_from_prototype
|
|
62
|
+
after_create :build_variants_from_option_values_hash, if: :option_values_hash
|
|
63
|
+
|
|
64
|
+
after_destroy :punch_slug
|
|
65
|
+
|
|
66
|
+
after_initialize :ensure_master
|
|
67
|
+
|
|
68
|
+
after_save :save_master
|
|
69
|
+
after_save :run_touch_callbacks, if: :anything_changed?
|
|
70
|
+
after_save :reset_nested_changes
|
|
71
|
+
after_touch :touch_taxons
|
|
72
|
+
|
|
73
|
+
before_validation :normalize_slug, on: :update
|
|
74
|
+
before_validation :validate_master
|
|
75
|
+
|
|
76
|
+
validates :meta_keywords, length: { maximum: 255 }
|
|
77
|
+
validates :meta_title, length: { maximum: 255 }
|
|
78
|
+
validates :name, presence: true
|
|
79
|
+
validates :price, presence: true, if: proc { Spree::Config[:require_master_price] }
|
|
80
|
+
validates :shipping_category_id, presence: true
|
|
81
|
+
validates :slug, length: { minimum: 3 }, uniqueness: { allow_blank: true }
|
|
82
|
+
|
|
83
|
+
attr_accessor :option_values_hash
|
|
84
|
+
|
|
85
|
+
accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
|
|
86
|
+
|
|
87
|
+
alias :options :product_option_types
|
|
88
|
+
|
|
89
|
+
# @return [Boolean] true if there are any variants
|
|
90
|
+
def has_variants?
|
|
91
|
+
variants.any?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @return [Spree::TaxCategory] tax category for this product, or the default tax category
|
|
95
|
+
def tax_category
|
|
96
|
+
if self[:tax_category_id].nil?
|
|
97
|
+
TaxCategory.where(is_default: true).first
|
|
98
|
+
else
|
|
99
|
+
TaxCategory.find(self[:tax_category_id])
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Overrides the prototype_id setter in order to ensure it is cast to an
|
|
104
|
+
# integer.
|
|
105
|
+
#
|
|
106
|
+
# @param value [#to_i] the intended new value
|
|
107
|
+
# @!attribute [rw] prototype_id
|
|
108
|
+
# @return [Fixnum]
|
|
109
|
+
attr_reader :prototype_id
|
|
110
|
+
def prototype_id=(value)
|
|
111
|
+
@prototype_id = value.to_i
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Ensures option_types and product_option_types exist for keys in
|
|
115
|
+
# option_values_hash.
|
|
116
|
+
#
|
|
117
|
+
# @return [Array] the option_values
|
|
118
|
+
def ensure_option_types_exist_for_values_hash
|
|
119
|
+
return if option_values_hash.nil?
|
|
120
|
+
option_values_hash.keys.map(&:to_i).each do |id|
|
|
121
|
+
self.option_type_ids << id unless option_type_ids.include?(id)
|
|
122
|
+
product_option_types.create(option_type_id: id) unless product_option_types.pluck(:option_type_id).include?(id)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Creates a new product with the same attributes, variants, etc.
|
|
127
|
+
#
|
|
128
|
+
# @return [Spree::Product] the duplicate
|
|
129
|
+
def duplicate
|
|
130
|
+
duplicator = ProductDuplicator.new(self)
|
|
131
|
+
duplicator.duplicate
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Use for checking whether this product has been deleted. Provided for
|
|
135
|
+
# overriding the logic for determining if a product is deleted.
|
|
136
|
+
#
|
|
137
|
+
# @return [Boolean] true if this product is deleted
|
|
138
|
+
def deleted?
|
|
139
|
+
!!deleted_at
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Determines if product is available. A product is available if it has not
|
|
143
|
+
# been deleted and the available_on date is in the past.
|
|
144
|
+
#
|
|
145
|
+
# @return [Boolean] true if this product is available
|
|
146
|
+
def available?
|
|
147
|
+
!(available_on.nil? || available_on.future?) && !deleted?
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Groups variants by the specified option type.
|
|
151
|
+
#
|
|
152
|
+
# @param opt_type [String] the name of the option type to group by
|
|
153
|
+
# @return [Hash] option_type as keys, array of variants as values.
|
|
154
|
+
def categorise_variants_from_option(opt_type)
|
|
155
|
+
return {} unless option_types.include?(opt_type)
|
|
156
|
+
variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type} }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Poor man's full text search.
|
|
160
|
+
#
|
|
161
|
+
# Filters products to those which have any of the strings in +values+ in
|
|
162
|
+
# any of the fields in +fields+.
|
|
163
|
+
#
|
|
164
|
+
# @param fields [Array{String,Symbol}] columns of the products table to search for values
|
|
165
|
+
# @param values [Array{String}] strings to search through fields for
|
|
166
|
+
# @return [ActiveRecord::Relation] scope with WHERE clause for search applied
|
|
167
|
+
def self.like_any(fields, values)
|
|
168
|
+
where fields.map { |field|
|
|
169
|
+
values.map { |value|
|
|
170
|
+
arel_table[field].matches("%#{value}%")
|
|
171
|
+
}.inject(:or)
|
|
172
|
+
}.inject(:or)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# @param current_currency [String] currency to filter variants by; defaults to Spree's default
|
|
176
|
+
# @return [Array<Spree::Variant>] all variants with at least one option value
|
|
177
|
+
def variants_and_option_values(current_currency = nil)
|
|
178
|
+
variants.includes(:option_values).active(current_currency).select do |variant|
|
|
179
|
+
variant.option_values.any?
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @return [Boolean] true if there are no option values
|
|
184
|
+
def empty_option_values?
|
|
185
|
+
options.empty? || options.any? do |opt|
|
|
186
|
+
opt.option_type.option_values.empty?
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# @param property_name [String] the name of the property to find
|
|
191
|
+
# @return [String] the value of the given property. nil if property is undefined on this product
|
|
192
|
+
def property(property_name)
|
|
193
|
+
return nil unless prop = properties.find_by(name: property_name)
|
|
194
|
+
product_properties.find_by(property: prop).try(:value)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Assigns the given value to the given property.
|
|
198
|
+
#
|
|
199
|
+
# @param property_name [String] the name of the property
|
|
200
|
+
# @param property_value [String] the property value
|
|
201
|
+
def set_property(property_name, property_value)
|
|
202
|
+
ActiveRecord::Base.transaction do
|
|
203
|
+
# Works around spree_i18n #301
|
|
204
|
+
property = if Property.exists?(name: property_name)
|
|
205
|
+
Property.where(name: property_name).first
|
|
206
|
+
else
|
|
207
|
+
Property.create(name: property_name, presentation: property_name)
|
|
208
|
+
end
|
|
209
|
+
product_property = ProductProperty.where(product: self, property: property).first_or_initialize
|
|
210
|
+
product_property.value = property_value
|
|
211
|
+
product_property.save!
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# @return [Array] all advertised and not-rejected promotions
|
|
216
|
+
def possible_promotions
|
|
217
|
+
promotion_ids = promotion_rules.map(&:promotion_id).uniq
|
|
218
|
+
Spree::Promotion.advertised.where(id: promotion_ids).reject(&:expired?)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# The number of on-hand stock items; Infinity if any variant does not track
|
|
222
|
+
# inventory.
|
|
223
|
+
#
|
|
224
|
+
# @return [Fixnum, Infinity]
|
|
225
|
+
def total_on_hand
|
|
226
|
+
if any_variants_not_track_inventory?
|
|
227
|
+
Float::INFINITY
|
|
228
|
+
else
|
|
229
|
+
stock_items.sum(:count_on_hand)
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Override so if the master variant is deleted, we can still find it.
|
|
234
|
+
#
|
|
235
|
+
# @return [Spree::Variant] the master variant
|
|
236
|
+
def master
|
|
237
|
+
super || variants_including_master.with_deleted.where(is_master: true).first
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
private
|
|
241
|
+
|
|
242
|
+
def add_associations_from_prototype
|
|
243
|
+
if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
|
|
244
|
+
prototype.properties.each do |property|
|
|
245
|
+
product_properties.create(property: property)
|
|
246
|
+
end
|
|
247
|
+
self.option_types = prototype.option_types
|
|
248
|
+
self.taxons = prototype.taxons
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def any_variants_not_track_inventory?
|
|
253
|
+
if variants_including_master.loaded?
|
|
254
|
+
variants_including_master.any? { |v| !v.should_track_inventory? }
|
|
255
|
+
else
|
|
256
|
+
!Spree::Config.track_inventory_levels || variants_including_master.where(track_inventory: false).any?
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Builds variants from a hash of option types & values
|
|
261
|
+
def build_variants_from_option_values_hash
|
|
262
|
+
ensure_option_types_exist_for_values_hash
|
|
263
|
+
values = option_values_hash.values
|
|
264
|
+
values = values.inject(values.shift) { |memo, value| memo.product(value).map(&:flatten) }
|
|
265
|
+
|
|
266
|
+
values.each do |ids|
|
|
267
|
+
variant = variants.create(
|
|
268
|
+
option_value_ids: ids,
|
|
269
|
+
price: master.price
|
|
270
|
+
)
|
|
271
|
+
end
|
|
272
|
+
save
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def ensure_master
|
|
276
|
+
return unless new_record?
|
|
277
|
+
self.master ||= build_master
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def normalize_slug
|
|
281
|
+
self.slug = normalize_friendly_id(slug)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def punch_slug
|
|
285
|
+
update_column :slug, "#{Time.now.to_i}_#{slug}" # punch slug with date prefix to allow reuse of original
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def anything_changed?
|
|
289
|
+
changed? || @nested_changes
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def reset_nested_changes
|
|
293
|
+
@nested_changes = false
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# there's a weird quirk with the delegate stuff that does not automatically save the delegate object
|
|
297
|
+
# when saving so we force a save using a hook
|
|
298
|
+
# Fix for issue #5306
|
|
299
|
+
def save_master
|
|
300
|
+
if master && (master.changed? || master.new_record? || (master.default_price && (master.default_price.changed? || master.default_price.new_record?)))
|
|
301
|
+
master.save!
|
|
302
|
+
@nested_changes = true
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# If the master cannot be saved, the Product object will get its errors
|
|
307
|
+
# and will be destroyed
|
|
308
|
+
def validate_master
|
|
309
|
+
# We call master.default_price here to ensure price is initialized.
|
|
310
|
+
# Required to avoid Variant#check_price validation failing on create.
|
|
311
|
+
unless master.default_price && master.valid?
|
|
312
|
+
master.errors.each do |att, error|
|
|
313
|
+
self.errors.add(att, error)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# ensures the master variant is flagged as such
|
|
319
|
+
def set_master_variant_defaults
|
|
320
|
+
master.is_master = true
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Try building a slug based on the following fields in increasing order of specificity.
|
|
324
|
+
def slug_candidates
|
|
325
|
+
[
|
|
326
|
+
:name,
|
|
327
|
+
[:name, :sku]
|
|
328
|
+
]
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def run_touch_callbacks
|
|
332
|
+
run_callbacks(:touch)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# Iterate through this products taxons and taxonomies and touch their timestamps in a batch
|
|
336
|
+
def touch_taxons
|
|
337
|
+
taxons_to_touch = taxons.map(&:self_and_ancestors).flatten.uniq
|
|
338
|
+
Spree::Taxon.where(id: taxons_to_touch.map(&:id)).update_all(updated_at: Time.current)
|
|
339
|
+
|
|
340
|
+
taxonomy_ids_to_touch = taxons_to_touch.map(&:taxonomy_id).flatten.uniq
|
|
341
|
+
Spree::Taxonomy.where(id: taxonomy_ids_to_touch).update_all(updated_at: Time.current)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
require_dependency 'spree/product/scopes'
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class Product < Spree::Base
|
|
3
|
+
cattr_accessor :search_scopes do
|
|
4
|
+
[]
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.add_search_scope(name, &block)
|
|
8
|
+
self.singleton_class.send(:define_method, name.to_sym, &block)
|
|
9
|
+
search_scopes << name.to_sym
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.simple_scopes
|
|
13
|
+
[
|
|
14
|
+
:ascend_by_updated_at,
|
|
15
|
+
:descend_by_updated_at,
|
|
16
|
+
:ascend_by_name,
|
|
17
|
+
:descend_by_name
|
|
18
|
+
]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.add_simple_scopes(scopes)
|
|
22
|
+
scopes.each do |name|
|
|
23
|
+
# We should not define price scopes here, as they require something slightly different
|
|
24
|
+
next if name.to_s.include?("master_price")
|
|
25
|
+
parts = name.to_s.match(/(.*)_by_(.*)/)
|
|
26
|
+
self.scope(name.to_s, -> { order("#{Product.quoted_table_name}.#{parts[2]} #{parts[1] == 'ascend' ? "ASC" : "DESC"}") })
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.property_conditions(property)
|
|
31
|
+
properties = Property.table_name
|
|
32
|
+
conditions = case property
|
|
33
|
+
when String then { "#{properties}.name" => property }
|
|
34
|
+
when Property then { "#{properties}.id" => property.id }
|
|
35
|
+
else { "#{properties}.id" => property.to_i }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
add_simple_scopes simple_scopes
|
|
40
|
+
|
|
41
|
+
add_search_scope :ascend_by_master_price do
|
|
42
|
+
joins(:master => :default_price).order("#{price_table_name}.amount ASC")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
add_search_scope :descend_by_master_price do
|
|
46
|
+
joins(:master => :default_price).order("#{price_table_name}.amount DESC")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
add_search_scope :price_between do |low, high|
|
|
50
|
+
joins(:master => :default_price).where(Price.table_name => { :amount => low..high })
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
add_search_scope :master_price_lte do |price|
|
|
54
|
+
joins(:master => :default_price).where("#{price_table_name}.amount <= ?", price)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
add_search_scope :master_price_gte do |price|
|
|
58
|
+
joins(:master => :default_price).where("#{price_table_name}.amount >= ?", price)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# This scope selects products in taxon AND all its descendants
|
|
62
|
+
# If you need products only within one taxon use
|
|
63
|
+
#
|
|
64
|
+
# Spree::Product.joins(:taxons).where(Taxon.table_name => { :id => taxon.id })
|
|
65
|
+
#
|
|
66
|
+
# If you're using count on the result of this scope, you must use the
|
|
67
|
+
# `:distinct` option as well:
|
|
68
|
+
#
|
|
69
|
+
# Spree::Product.in_taxon(taxon).count(:distinct => true)
|
|
70
|
+
#
|
|
71
|
+
# This is so that the count query is distinct'd:
|
|
72
|
+
#
|
|
73
|
+
# SELECT COUNT(DISTINCT "spree_products"."id") ...
|
|
74
|
+
#
|
|
75
|
+
# vs.
|
|
76
|
+
#
|
|
77
|
+
# SELECT COUNT(*) ...
|
|
78
|
+
add_search_scope :in_taxon do |taxon|
|
|
79
|
+
includes(:classifications).
|
|
80
|
+
where("spree_products_taxons.taxon_id" => taxon.self_and_descendants.pluck(:id)).
|
|
81
|
+
order("spree_products_taxons.position ASC")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# This scope selects products in all taxons AND all its descendants
|
|
85
|
+
# If you need products only within one taxon use
|
|
86
|
+
#
|
|
87
|
+
# Spree::Product.taxons_id_eq([x,y])
|
|
88
|
+
add_search_scope :in_taxons do |*taxons|
|
|
89
|
+
taxons = get_taxons(taxons)
|
|
90
|
+
taxons.first ? prepare_taxon_conditions(taxons) : where(nil)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# a scope that finds all products having property specified by name, object or id
|
|
94
|
+
add_search_scope :with_property do |property|
|
|
95
|
+
joins(:properties).where(property_conditions(property))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# a simple test for product with a certain property-value pairing
|
|
99
|
+
# note that it can test for properties with NULL values, but not for absent values
|
|
100
|
+
add_search_scope :with_property_value do |property, value|
|
|
101
|
+
joins(:properties)
|
|
102
|
+
.where("#{ProductProperty.table_name}.value = ?", value)
|
|
103
|
+
.where(property_conditions(property))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
add_search_scope :with_option do |option|
|
|
107
|
+
option_types = OptionType.table_name
|
|
108
|
+
conditions = case option
|
|
109
|
+
when String then { "#{option_types}.name" => option }
|
|
110
|
+
when OptionType then { "#{option_types}.id" => option.id }
|
|
111
|
+
else { "#{option_types}.id" => option.to_i }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
joins(:option_types).where(conditions)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
add_search_scope :with_option_value do |option, value|
|
|
118
|
+
option_values = OptionValue.table_name
|
|
119
|
+
option_type_id = case option
|
|
120
|
+
when String then OptionType.find_by(name: option) || option.to_i
|
|
121
|
+
when OptionType then option.id
|
|
122
|
+
else option.to_i
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
conditions = "#{option_values}.name = ? AND #{option_values}.option_type_id = ?", value, option_type_id
|
|
126
|
+
group('spree_products.id').joins(variants_including_master: :option_values).where(conditions)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Finds all products which have either:
|
|
130
|
+
# 1) have an option value with the name matching the one given
|
|
131
|
+
# 2) have a product property with a value matching the one given
|
|
132
|
+
add_search_scope :with do |value|
|
|
133
|
+
includes(variants_including_master: :option_values).
|
|
134
|
+
includes(:product_properties).
|
|
135
|
+
where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Finds all products that have a name containing the given words.
|
|
139
|
+
add_search_scope :in_name do |words|
|
|
140
|
+
like_any([:name], prepare_words(words))
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Finds all products that have a name or meta_keywords containing the given words.
|
|
144
|
+
add_search_scope :in_name_or_keywords do |words|
|
|
145
|
+
like_any([:name, :meta_keywords], prepare_words(words))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Finds all products that have a name, description, meta_description or meta_keywords containing the given keywords.
|
|
149
|
+
add_search_scope :in_name_or_description do |words|
|
|
150
|
+
like_any([:name, :description, :meta_description, :meta_keywords], prepare_words(words))
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Finds all products that have the ids matching the given collection of ids.
|
|
154
|
+
# Alternatively, you could use find(collection_of_ids), but that would raise an exception if one product couldn't be found
|
|
155
|
+
add_search_scope :with_ids do |*ids|
|
|
156
|
+
where(id: ids)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Sorts products from most popular (popularity is extracted from how many
|
|
160
|
+
# times use has put product in cart, not completed orders)
|
|
161
|
+
#
|
|
162
|
+
# there is alternative faster and more elegant solution, it has small drawback though,
|
|
163
|
+
# it doesn stack with other scopes :/
|
|
164
|
+
#
|
|
165
|
+
# :joins => "LEFT OUTER JOIN (SELECT line_items.variant_id as vid, COUNT(*) as cnt FROM line_items GROUP BY line_items.variant_id) AS popularity_count ON variants.id = vid",
|
|
166
|
+
# :order => 'COALESCE(cnt, 0) DESC'
|
|
167
|
+
add_search_scope :descend_by_popularity do
|
|
168
|
+
joins(:master).
|
|
169
|
+
order(%Q{
|
|
170
|
+
COALESCE((
|
|
171
|
+
SELECT
|
|
172
|
+
COUNT(#{LineItem.quoted_table_name}.id)
|
|
173
|
+
FROM
|
|
174
|
+
#{LineItem.quoted_table_name}
|
|
175
|
+
JOIN
|
|
176
|
+
#{Variant.quoted_table_name} AS popular_variants
|
|
177
|
+
ON
|
|
178
|
+
popular_variants.id = #{LineItem.quoted_table_name}.variant_id
|
|
179
|
+
WHERE
|
|
180
|
+
popular_variants.product_id = #{Product.quoted_table_name}.id
|
|
181
|
+
), 0) DESC
|
|
182
|
+
})
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
add_search_scope :not_deleted do
|
|
186
|
+
where("#{Product.quoted_table_name}.deleted_at IS NULL or #{Product.quoted_table_name}.deleted_at >= ?", Time.zone.now)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Can't use add_search_scope for this as it needs a default argument
|
|
190
|
+
def self.available(available_on = nil, currency = nil)
|
|
191
|
+
joins(:master => :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on || Time.now)
|
|
192
|
+
end
|
|
193
|
+
search_scopes << :available
|
|
194
|
+
|
|
195
|
+
def self.active(currency = nil)
|
|
196
|
+
not_deleted.available(nil, currency)
|
|
197
|
+
end
|
|
198
|
+
search_scopes << :active
|
|
199
|
+
|
|
200
|
+
add_search_scope :taxons_name_eq do |name|
|
|
201
|
+
group("spree_products.id").joins(:taxons).where(Taxon.arel_table[:name].eq(name))
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def self.distinct_by_product_ids(sort_order = nil)
|
|
205
|
+
sort_column = sort_order.split(" ").first
|
|
206
|
+
|
|
207
|
+
# Postgres will complain when using ordering by expressions not present in
|
|
208
|
+
# SELECT DISTINCT. e.g.
|
|
209
|
+
#
|
|
210
|
+
# PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
|
|
211
|
+
# expressions must appear in select list. e.g.
|
|
212
|
+
#
|
|
213
|
+
# SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
|
|
214
|
+
# "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
|
|
215
|
+
# AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
|
|
216
|
+
# "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
|
|
217
|
+
# AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
|
|
218
|
+
# ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
|
|
219
|
+
#
|
|
220
|
+
# Don't allow sort_column, a variable coming from params,
|
|
221
|
+
# to be anything but a column in the database
|
|
222
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
|
|
223
|
+
all
|
|
224
|
+
else
|
|
225
|
+
distinct
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
private
|
|
230
|
+
|
|
231
|
+
def self.price_table_name
|
|
232
|
+
Price.quoted_table_name
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# specifically avoid having an order for taxon search (conflicts with main order)
|
|
236
|
+
def self.prepare_taxon_conditions(taxons)
|
|
237
|
+
ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
|
|
238
|
+
joins(:taxons).where("#{Taxon.table_name}.id" => ids)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Produce an array of keywords for use in scopes.
|
|
242
|
+
# Always return array with at least an empty string to avoid SQL errors
|
|
243
|
+
def self.prepare_words(words)
|
|
244
|
+
return [''] if words.blank?
|
|
245
|
+
a = words.split(/[,\s]/).map(&:strip)
|
|
246
|
+
a.any? ? a : ['']
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def self.get_taxons(*ids_or_records_or_names)
|
|
250
|
+
taxons = Taxon.table_name
|
|
251
|
+
ids_or_records_or_names.flatten.map { |t|
|
|
252
|
+
case t
|
|
253
|
+
when Integer then Taxon.find_by(id: t)
|
|
254
|
+
when ActiveRecord::Base then t
|
|
255
|
+
when String
|
|
256
|
+
Taxon.find_by(name: t) ||
|
|
257
|
+
Taxon.where("#{taxons}.permalink LIKE ? OR #{taxons}.permalink = ?", "%/#{t}/", "#{t}/").first
|
|
258
|
+
end
|
|
259
|
+
}.compact.flatten.uniq
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|