goca-spree-core 3.1.14.rails.5.0
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/Gemfile +3 -0
- data/LICENSE +26 -0
- data/Rakefile +15 -0
- data/app/assets/images/logo/spree_50.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 +59 -0
- data/app/controllers/spree/base_controller.rb +15 -0
- data/app/helpers/spree/base_helper.rb +123 -0
- data/app/helpers/spree/products_helper.rb +91 -0
- data/app/mailers/spree/base_mailer.rb +27 -0
- data/app/mailers/spree/order_mailer.rb +17 -0
- data/app/mailers/spree/reimbursement_mailer.rb +10 -0
- data/app/mailers/spree/shipment_mailer.rb +10 -0
- data/app/mailers/spree/test_mailer.rb +8 -0
- data/app/models/concerns/spree/adjustment_source.rb +53 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +34 -0
- data/app/models/concerns/spree/default_price.rb +40 -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/ransackable_attributes.rb +24 -0
- data/app/models/concerns/spree/user_address.rb +30 -0
- data/app/models/concerns/spree/user_api_authentication.rb +19 -0
- data/app/models/concerns/spree/user_methods.rb +57 -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/concerns/spree/vat_price_calculation.rb +47 -0
- data/app/models/friendly_id/slug_decorator.rb +3 -0
- data/app/models/spree/ability.rb +80 -0
- data/app/models/spree/address.rb +145 -0
- data/app/models/spree/adjustable/adjuster/base.rb +25 -0
- data/app/models/spree/adjustable/adjuster/promotion.rb +41 -0
- data/app/models/spree/adjustable/adjuster/tax.rb +26 -0
- data/app/models/spree/adjustable/adjustments_updater.rb +47 -0
- data/app/models/spree/adjustable/promotion_accumulator.rb +75 -0
- data/app/models/spree/adjustment.rb +104 -0
- data/app/models/spree/app_configuration.rb +74 -0
- data/app/models/spree/asset.rb +6 -0
- data/app/models/spree/base.rb +24 -0
- data/app/models/spree/calculator/default_tax.rb +59 -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 +22 -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/calculator.rb +47 -0
- data/app/models/spree/classification.rb +15 -0
- data/app/models/spree/country.rb +40 -0
- data/app/models/spree/credit_card.rb +166 -0
- data/app/models/spree/customer_return.rb +67 -0
- data/app/models/spree/exchange.rb +46 -0
- data/app/models/spree/gateway/bogus.rb +91 -0
- data/app/models/spree/gateway/bogus_simple.rb +26 -0
- data/app/models/spree/gateway.rb +80 -0
- data/app/models/spree/image.rb +43 -0
- data/app/models/spree/inventory_unit.rb +105 -0
- data/app/models/spree/legacy_user.rb +13 -0
- data/app/models/spree/line_item.rb +158 -0
- data/app/models/spree/log_entry.rb +17 -0
- data/app/models/spree/option_type.rb +32 -0
- data/app/models/spree/option_type_prototype.rb +9 -0
- data/app/models/spree/option_value.rb +26 -0
- data/app/models/spree/option_value_variant.rb +6 -0
- data/app/models/spree/order/checkout.rb +336 -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/store_credit.rb +96 -0
- data/app/models/spree/order.rb +685 -0
- data/app/models/spree/order_contents.rb +120 -0
- data/app/models/spree/order_inventory.rb +103 -0
- data/app/models/spree/order_merger.rb +65 -0
- data/app/models/spree/order_promotion.rb +6 -0
- data/app/models/spree/order_updater.rb +177 -0
- data/app/models/spree/payment/gateway_options.rb +90 -0
- data/app/models/spree/payment/processing.rb +175 -0
- data/app/models/spree/payment.rb +276 -0
- data/app/models/spree/payment_capture_event.rb +9 -0
- data/app/models/spree/payment_method/check.rb +43 -0
- data/app/models/spree/payment_method/store_credit.rb +130 -0
- data/app/models/spree/payment_method.rb +71 -0
- data/app/models/spree/preference.rb +5 -0
- data/app/models/spree/preferences/configuration.rb +71 -0
- data/app/models/spree/preferences/preferable.rb +133 -0
- data/app/models/spree/preferences/preferable_class_methods.rb +51 -0
- data/app/models/spree/preferences/scoped_store.rb +33 -0
- data/app/models/spree/preferences/store.rb +98 -0
- data/app/models/spree/price.rb +53 -0
- data/app/models/spree/product/scopes.rb +271 -0
- data/app/models/spree/product.rb +384 -0
- data/app/models/spree/product_option_type.rb +12 -0
- data/app/models/spree/product_promotion_rule.rb +9 -0
- data/app/models/spree/product_property.rb +28 -0
- data/app/models/spree/promotion/actions/create_adjustment.rb +21 -0
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +24 -0
- data/app/models/spree/promotion/actions/create_line_items.rb +62 -0
- data/app/models/spree/promotion/actions/free_shipping.rb +18 -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 +65 -0
- data/app/models/spree/promotion/rules/taxon.rb +70 -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.rb +198 -0
- data/app/models/spree/promotion_action.rb +25 -0
- data/app/models/spree/promotion_action_line_item.rb +6 -0
- data/app/models/spree/promotion_category.rb +6 -0
- data/app/models/spree/promotion_handler/cart.rb +51 -0
- data/app/models/spree/promotion_handler/coupon.rb +107 -0
- data/app/models/spree/promotion_handler/free_shipping.rb +33 -0
- data/app/models/spree/promotion_handler/page.rb +24 -0
- data/app/models/spree/promotion_rule.rb +43 -0
- data/app/models/spree/promotion_rule_taxon.rb +9 -0
- data/app/models/spree/promotion_rule_user.rb +9 -0
- data/app/models/spree/property.rb +23 -0
- data/app/models/spree/property_prototype.rb +9 -0
- data/app/models/spree/prototype.rb +14 -0
- data/app/models/spree/prototype_taxon.rb +9 -0
- data/app/models/spree/refund.rb +89 -0
- data/app/models/spree/refund_reason.rb +13 -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.rb +164 -0
- data/app/models/spree/reimbursement_performer.rb +43 -0
- data/app/models/spree/reimbursement_tax_calculator.rb +44 -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 +67 -0
- data/app/models/spree/reimbursement_type/store_credit.rb +28 -0
- data/app/models/spree/reimbursement_type.rb +16 -0
- data/app/models/spree/return_authorization.rb +98 -0
- data/app/models/spree/return_authorization_reason.rb +7 -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 +16 -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/return_item.rb +236 -0
- data/app/models/spree/returns_calculator.rb +8 -0
- data/app/models/spree/role.rb +8 -0
- data/app/models/spree/role_user.rb +6 -0
- data/app/models/spree/shipment.rb +419 -0
- data/app/models/spree/shipment_handler.rb +43 -0
- data/app/models/spree/shipping_calculator.rb +22 -0
- data/app/models/spree/shipping_category.rb +11 -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_method_zone.rb +6 -0
- data/app/models/spree/shipping_rate.rb +44 -0
- data/app/models/spree/state.rb +41 -0
- data/app/models/spree/state_change.rb +10 -0
- data/app/models/spree/stock/adjuster.rb +27 -0
- data/app/models/spree/stock/availability_validator.rb +30 -0
- data/app/models/spree/stock/content_item.rb +54 -0
- data/app/models/spree/stock/coordinator.rb +65 -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/package.rb +104 -0
- data/app/models/spree/stock/packer.rb +48 -0
- data/app/models/spree/stock/prioritizer.rb +47 -0
- data/app/models/spree/stock/quantifier.rb +29 -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 +34 -0
- data/app/models/spree/stock_item.rb +90 -0
- data/app/models/spree/stock_location.rb +115 -0
- data/app/models/spree/stock_movement.rb +35 -0
- data/app/models/spree/stock_transfer.rb +50 -0
- data/app/models/spree/store.rb +48 -0
- data/app/models/spree/store_credit.rb +252 -0
- data/app/models/spree/store_credit_category.rb +22 -0
- data/app/models/spree/store_credit_event.rb +38 -0
- data/app/models/spree/store_credit_type.rb +6 -0
- data/app/models/spree/tax_category.rb +18 -0
- data/app/models/spree/tax_rate.rb +110 -0
- data/app/models/spree/taxon.rb +102 -0
- data/app/models/spree/taxonomy.rb +24 -0
- data/app/models/spree/tracker.rb +19 -0
- data/app/models/spree/validations/db_maximum_length_validator.rb +23 -0
- data/app/models/spree/variant.rb +312 -0
- data/app/models/spree/zone.rb +190 -0
- data/app/models/spree/zone_member.rb +12 -0
- data/app/validators/db_maximum_length_validator.rb +11 -0
- data/app/views/layouts/spree/base_mailer.html.erb +41 -0
- data/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb +19 -0
- data/app/views/spree/order_mailer/_adjustment.html.erb +8 -0
- data/app/views/spree/order_mailer/_subtotal.html.erb +8 -0
- data/app/views/spree/order_mailer/_total.html.erb +8 -0
- data/app/views/spree/order_mailer/cancel_email.html.erb +30 -0
- data/app/views/spree/order_mailer/cancel_email.text.erb +16 -0
- data/app/views/spree/order_mailer/confirm_email.html.erb +70 -0
- data/app/views/spree/order_mailer/confirm_email.text.erb +38 -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 +29 -0
- data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +777 -0
- data/app/views/spree/shared/_error_messages.html.erb +11 -0
- data/app/views/spree/shared/_mailer_line_item.html.erb +12 -0
- data/app/views/spree/shipment_mailer/shipped_email.html.erb +41 -0
- data/app/views/spree/shipment_mailer/shipped_email.text.erb +16 -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/assets.rb +1 -0
- data/config/initializers/friendly_id.rb +88 -0
- data/config/initializers/premailer_assets.rb +1 -0
- data/config/initializers/premailer_rails.rb +3 -0
- data/config/initializers/user_class_extensions.rb +10 -0
- data/config/locales/en.yml +1499 -0
- data/config/routes.rb +8 -0
- data/db/default/spree/countries.rb +29 -0
- data/db/default/spree/default_reimbursement_type.rb +1 -0
- data/db/default/spree/roles.rb +2 -0
- data/db/default/spree/states.rb +28 -0
- data/db/default/spree/stores.rb +9 -0
- data/db/default/spree/zones.rb +11 -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 +33 -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 +37 -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 +18 -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/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/20140911173301_add_kind_to_zone.rb +11 -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 +13 -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/20141215232040_remove_token_permissions_table.rb +6 -0
- data/db/migrate/20141215235502_remove_extra_products_slug_index.rb +5 -0
- data/db/migrate/20141217215630_update_product_slug_index.rb +6 -0
- data/db/migrate/20141218025915_rename_identifier_to_number_for_payment.rb +5 -0
- data/db/migrate/20150118210639_create_spree_store_credits.rb +24 -0
- data/db/migrate/20150118211500_create_spree_store_credit_categories.rb +8 -0
- data/db/migrate/20150118212051_create_spree_store_credit_events.rb +17 -0
- data/db/migrate/20150118212101_create_spree_store_credit_types.rb +10 -0
- data/db/migrate/20150121022521_remove_environment_from_payment_method.rb +6 -0
- data/db/migrate/20150122145607_add_resellable_to_return_items.rb +5 -0
- data/db/migrate/20150122202432_add_code_to_spree_promotion_categories.rb +5 -0
- data/db/migrate/20150128032538_remove_environment_from_tracker.rb +6 -0
- data/db/migrate/20150128060325_remove_spree_configurations.rb +16 -0
- data/db/migrate/20150216173445_add_index_to_spree_stock_items_variant_id.rb +13 -0
- data/db/migrate/20150309161154_ensure_payments_have_numbers.rb +9 -0
- data/db/migrate/20150314013438_add_missing_indexes_on_spree_tables.rb +67 -0
- data/db/migrate/20150317174308_remove_duplicated_indexes_from_multi_columns.rb +18 -0
- data/db/migrate/20150324104002_remove_user_index_from_spree_state_changes.rb +14 -0
- data/db/migrate/20150515211137_fix_adjustment_order_id.rb +70 -0
- data/db/migrate/20150522071831_add_position_to_spree_payment_methods.rb +5 -0
- data/db/migrate/20150522181728_add_deleted_at_to_friendly_id_slugs.rb +6 -0
- data/db/migrate/20150609093816_increase_scale_on_pre_tax_amounts.rb +16 -0
- data/db/migrate/20150626181949_add_taxable_adjustment_total_to_line_item.rb +19 -0
- data/db/migrate/20150627090949_migrate_payment_methods_display.rb +12 -0
- data/db/migrate/20150707204155_enable_acts_as_paranoid_on_calculators.rb +6 -0
- data/db/migrate/20150714154102_spree_payment_method_store_credits.rb +12 -0
- data/db/migrate/20150726141425_rename_has_and_belongs_to_associations_to_model_names.rb +18 -0
- data/db/migrate/20150727191614_spree_store_credit_types.rb +11 -0
- data/db/migrate/20150819154308_add_discontinued_to_products_and_variants.rb +68 -0
- data/db/migrate/20151220072838_remove_shipping_method_id_from_spree_orders.rb +13 -0
- data/db/migrate/20160207191757_add_id_column_to_earlier_habtm_tables.rb +16 -0
- data/db/migrate/20160219165458_add_indexes.rb +14 -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 +72 -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 +35 -0
- data/lib/generators/spree/install/install_generator.rb +233 -0
- data/lib/generators/spree/install/templates/config/initializers/spree.rb +18 -0
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +17 -0
- data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +17 -0
- data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/backend/all.css +16 -0
- data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +16 -0
- data/lib/spree/core/controller_helpers/auth.rb +84 -0
- data/lib/spree/core/controller_helpers/common.rb +74 -0
- data/lib/spree/core/controller_helpers/order.rb +103 -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 +51 -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 +134 -0
- data/lib/spree/core/environment/calculators.rb +12 -0
- data/lib/spree/core/environment.rb +15 -0
- data/lib/spree/core/environment_extension.rb +25 -0
- data/lib/spree/core/importer/order.rb +284 -0
- data/lib/spree/core/importer/product.rb +62 -0
- data/lib/spree/core/importer.rb +9 -0
- data/lib/spree/core/number_generator.rb +52 -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 +102 -0
- data/lib/spree/core/token_generator.rb +22 -0
- data/lib/spree/core/validators/email.rb +11 -0
- data/lib/spree/core/version.rb +5 -0
- data/lib/spree/core.rb +96 -0
- data/lib/spree/i18n/base.rb +17 -0
- data/lib/spree/i18n/initializer.rb +1 -0
- data/lib/spree/i18n.rb +37 -0
- data/lib/spree/localized_number.rb +22 -0
- data/lib/spree/migrations.rb +77 -0
- data/lib/spree/money.rb +61 -0
- data/lib/spree/permitted_attributes.rb +115 -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 +179 -0
- data/lib/spree/testing_support/common_rake.rb +39 -0
- data/lib/spree/testing_support/controller_requests.rb +93 -0
- data/lib/spree/testing_support/extension_rake.rb +10 -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 +20 -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/image_factory.rb +5 -0
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +10 -0
- data/lib/spree/testing_support/factories/line_item_factory.rb +12 -0
- data/lib/spree/testing_support/factories/options_factory.rb +13 -0
- data/lib/spree/testing_support/factories/order_factory.rb +91 -0
- data/lib/spree/testing_support/factories/payment_factory.rb +28 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +23 -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_factory.rb +52 -0
- data/lib/spree/testing_support/factories/promotion_rule_factory.rb +5 -0
- data/lib/spree/testing_support/factories/property_factory.rb +6 -0
- data/lib/spree/testing_support/factories/prototype_factory.rb +11 -0
- data/lib/spree/testing_support/factories/refund_factory.rb +22 -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 +20 -0
- data/lib/spree/testing_support/factories/return_item_factory.rb +14 -0
- data/lib/spree/testing_support/factories/role_factory.rb +9 -0
- data/lib/spree/testing_support/factories/shipment_factory.rb +23 -0
- data/lib/spree/testing_support/factories/shipping_category_factory.rb +5 -0
- data/lib/spree/testing_support/factories/shipping_method_factory.rb +21 -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/store_credit_category_factory.rb +9 -0
- data/lib/spree/testing_support/factories/store_credit_event_factory.rb +8 -0
- data/lib/spree/testing_support/factories/store_credit_factory.rb +17 -0
- data/lib/spree/testing_support/factories/store_credit_type_factory.rb +11 -0
- data/lib/spree/testing_support/factories/store_factory.rb +8 -0
- data/lib/spree/testing_support/factories/tax_category_factory.rb +6 -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 +6 -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 +25 -0
- data/lib/spree/testing_support/factories/zone_member_factory.rb +6 -0
- data/lib/spree/testing_support/factories.rb +19 -0
- data/lib/spree/testing_support/flash.rb +27 -0
- data/lib/spree/testing_support/i18n.rb +97 -0
- data/lib/spree/testing_support/microdata.rb +189 -0
- data/lib/spree/testing_support/order_walkthrough.rb +72 -0
- data/lib/spree/testing_support/preferences.rb +31 -0
- data/lib/spree/testing_support/url_helpers.rb +9 -0
- data/lib/spree_core.rb +1 -0
- data/lib/tasks/core.rake +169 -0
- data/lib/tasks/email.rake +10 -0
- data/lib/tasks/exchanges.rake +70 -0
- data/script/rails +9 -0
- data/spec/fixtures/microdata.html +22 -0
- data/spec/fixtures/microdata_itemref.html +15 -0
- data/spec/fixtures/microdata_no_itemscope.html +20 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spree_core.gemspec +47 -0
- data/vendor/assets/javascripts/jquery-migrate-1.0.0.js +498 -0
- data/vendor/assets/javascripts/jquery.payment.js +652 -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 +971 -0
@@ -0,0 +1,271 @@
|
|
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
|
+
def self.not_discontinued(only_not_discontinued = true)
|
190
|
+
if only_not_discontinued != '0' && only_not_discontinued
|
191
|
+
where("#{Product.quoted_table_name}.discontinue_on IS NULL or #{Product.quoted_table_name}.discontinue_on >= ?", Time.zone.now)
|
192
|
+
else
|
193
|
+
all
|
194
|
+
end
|
195
|
+
end
|
196
|
+
search_scopes << :not_discontinued
|
197
|
+
# Can't use add_search_scope for this as it needs a default argument
|
198
|
+
def self.available(available_on = nil, currency = nil)
|
199
|
+
available_on ||= Time.current
|
200
|
+
not_discontinued.joins(master: :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on).uniq
|
201
|
+
end
|
202
|
+
search_scopes << :available
|
203
|
+
|
204
|
+
def self.active(currency = nil)
|
205
|
+
not_discontinued.available(nil, currency)
|
206
|
+
end
|
207
|
+
search_scopes << :active
|
208
|
+
|
209
|
+
add_search_scope :taxons_name_eq do |name|
|
210
|
+
group("spree_products.id").joins(:taxons).where(Taxon.arel_table[:name].eq(name))
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.distinct_by_product_ids(sort_order = nil)
|
214
|
+
sort_column = sort_order.split(" ").first
|
215
|
+
|
216
|
+
# Postgres will complain when using ordering by expressions not present in
|
217
|
+
# SELECT DISTINCT. e.g.
|
218
|
+
#
|
219
|
+
# PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY
|
220
|
+
# expressions must appear in select list. e.g.
|
221
|
+
#
|
222
|
+
# SELECT DISTINCT "spree_products".* FROM "spree_products" LEFT OUTER JOIN
|
223
|
+
# "spree_variants" ON "spree_variants"."product_id" = "spree_products"."id" AND "spree_variants"."is_master" = 't'
|
224
|
+
# AND "spree_variants"."deleted_at" IS NULL LEFT OUTER JOIN "spree_prices" ON
|
225
|
+
# "spree_prices"."variant_id" = "spree_variants"."id" AND "spree_prices"."currency" = 'USD'
|
226
|
+
# AND "spree_prices"."deleted_at" IS NULL WHERE "spree_products"."deleted_at" IS NULL AND ('t'='t')
|
227
|
+
# ORDER BY "spree_prices"."amount" ASC LIMIT 10 OFFSET 0
|
228
|
+
#
|
229
|
+
# Don't allow sort_column, a variable coming from params,
|
230
|
+
# to be anything but a column in the database
|
231
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && !column_names.include?(sort_column)
|
232
|
+
all
|
233
|
+
else
|
234
|
+
distinct
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
private
|
239
|
+
|
240
|
+
def self.price_table_name
|
241
|
+
Price.quoted_table_name
|
242
|
+
end
|
243
|
+
|
244
|
+
# specifically avoid having an order for taxon search (conflicts with main order)
|
245
|
+
def self.prepare_taxon_conditions(taxons)
|
246
|
+
ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
|
247
|
+
joins(:taxons).where("#{Taxon.table_name}.id" => ids)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Produce an array of keywords for use in scopes.
|
251
|
+
# Always return array with at least an empty string to avoid SQL errors
|
252
|
+
def self.prepare_words(words)
|
253
|
+
return [''] if words.blank?
|
254
|
+
a = words.split(/[,\s]/).map(&:strip)
|
255
|
+
a.any? ? a : ['']
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.get_taxons(*ids_or_records_or_names)
|
259
|
+
taxons = Taxon.table_name
|
260
|
+
ids_or_records_or_names.flatten.map { |t|
|
261
|
+
case t
|
262
|
+
when Integer then Taxon.find_by(id: t)
|
263
|
+
when ActiveRecord::Base then t
|
264
|
+
when String
|
265
|
+
Taxon.find_by(name: t) ||
|
266
|
+
Taxon.where("#{taxons}.permalink LIKE ? OR #{taxons}.permalink = ?", "%/#{t}/", "#{t}/").first
|
267
|
+
end
|
268
|
+
}.compact.flatten.uniq
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
@@ -0,0 +1,384 @@
|
|
1
|
+
# PRODUCTS
|
2
|
+
# Products represent an entity for sale in a store.
|
3
|
+
# Products can have variations, called variants
|
4
|
+
# Products properties include description, permalink, availability,
|
5
|
+
# shipping category, etc. that do not change by variant.
|
6
|
+
#
|
7
|
+
# MASTER VARIANT
|
8
|
+
# Every product has one master variant, which stores master price and sku, size and weight, etc.
|
9
|
+
# The master variant does not have option values associated with it.
|
10
|
+
# Price, SKU, size, weight, etc. are all delegated to the master variant.
|
11
|
+
# Contains on_hand inventory levels only when there are no variants for the product.
|
12
|
+
#
|
13
|
+
# VARIANTS
|
14
|
+
# All variants can access the product properties directly (via reverse delegation).
|
15
|
+
# Inventory units are tied to Variant.
|
16
|
+
# The master variant can have inventory units, but not option values.
|
17
|
+
# All other variants have option values and may have inventory units.
|
18
|
+
# Sum of on_hand each variant's inventory level determine "on_hand" level for the product.
|
19
|
+
#
|
20
|
+
|
21
|
+
module Spree
|
22
|
+
class Product < Spree::Base
|
23
|
+
extend FriendlyId
|
24
|
+
friendly_id :slug_candidates, use: :history
|
25
|
+
|
26
|
+
acts_as_paranoid
|
27
|
+
|
28
|
+
# we need to have this callback before any dependent: :destroy associations
|
29
|
+
# https://github.com/rails/rails/issues/3458
|
30
|
+
before_destroy :ensure_no_line_items
|
31
|
+
|
32
|
+
has_many :product_option_types, dependent: :destroy, inverse_of: :product
|
33
|
+
has_many :option_types, through: :product_option_types
|
34
|
+
has_many :product_properties, dependent: :destroy, inverse_of: :product
|
35
|
+
has_many :properties, through: :product_properties
|
36
|
+
|
37
|
+
has_many :classifications, dependent: :delete_all, inverse_of: :product
|
38
|
+
has_many :taxons, through: :classifications, before_remove: :remove_taxon
|
39
|
+
|
40
|
+
has_many :product_promotion_rules, class_name: 'Spree::ProductPromotionRule'
|
41
|
+
has_many :promotion_rules, through: :product_promotion_rules, class_name: 'Spree::PromotionRule'
|
42
|
+
|
43
|
+
has_many :promotions, through: :promotion_rules, class_name: 'Spree::Promotion'
|
44
|
+
|
45
|
+
has_many :possible_promotions, -> { advertised.active }, through: :promotion_rules,
|
46
|
+
class_name: 'Spree::Promotion',
|
47
|
+
source: :promotion
|
48
|
+
|
49
|
+
belongs_to :tax_category, class_name: 'Spree::TaxCategory'
|
50
|
+
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', inverse_of: :products
|
51
|
+
|
52
|
+
has_one :master,
|
53
|
+
-> { where is_master: true },
|
54
|
+
inverse_of: :product,
|
55
|
+
class_name: 'Spree::Variant'
|
56
|
+
|
57
|
+
has_many :variants,
|
58
|
+
-> { where(is_master: false).order(:position) },
|
59
|
+
inverse_of: :product,
|
60
|
+
class_name: 'Spree::Variant'
|
61
|
+
|
62
|
+
has_many :variants_including_master,
|
63
|
+
-> { order(:position) },
|
64
|
+
inverse_of: :product,
|
65
|
+
class_name: 'Spree::Variant',
|
66
|
+
dependent: :destroy
|
67
|
+
|
68
|
+
has_many :prices, -> { order('spree_variants.position, spree_variants.id, currency') }, through: :variants
|
69
|
+
|
70
|
+
has_many :stock_items, through: :variants_including_master
|
71
|
+
|
72
|
+
has_many :line_items, through: :variants_including_master
|
73
|
+
has_many :orders, through: :line_items
|
74
|
+
|
75
|
+
delegate_belongs_to :master, :sku, :price, :currency, :display_amount, :display_price, :weight, :height, :width, :depth,
|
76
|
+
:is_master, :has_default_price?, :cost_currency, :price_in, :amount_in, :cost_price, :images
|
77
|
+
|
78
|
+
alias_method :master_images, :images
|
79
|
+
|
80
|
+
has_many :variant_images, -> { order(:position) }, source: :images, through: :variants_including_master
|
81
|
+
|
82
|
+
after_create :add_associations_from_prototype
|
83
|
+
after_create :build_variants_from_option_values_hash, if: :option_values_hash
|
84
|
+
|
85
|
+
after_destroy :punch_slug
|
86
|
+
after_restore :update_slug_history
|
87
|
+
|
88
|
+
after_initialize :ensure_master
|
89
|
+
|
90
|
+
after_save :save_master
|
91
|
+
after_save :run_touch_callbacks, if: :anything_changed?
|
92
|
+
after_save :reset_nested_changes
|
93
|
+
after_touch :touch_taxons
|
94
|
+
|
95
|
+
before_validation :normalize_slug, on: :update
|
96
|
+
before_validation :validate_master
|
97
|
+
|
98
|
+
with_options length: { maximum: 255 }, allow_blank: true do
|
99
|
+
validates :meta_keywords
|
100
|
+
validates :meta_title
|
101
|
+
end
|
102
|
+
with_options presence: true do
|
103
|
+
validates :name, :shipping_category
|
104
|
+
validates :price, if: proc { Spree::Config[:require_master_price] }
|
105
|
+
end
|
106
|
+
|
107
|
+
validates :slug, length: { minimum: 3 }, allow_blank: true, uniqueness: true
|
108
|
+
validate :discontinue_on_must_be_later_than_available_on, if: -> { available_on && discontinue_on }
|
109
|
+
|
110
|
+
attr_accessor :option_values_hash
|
111
|
+
|
112
|
+
accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
|
113
|
+
|
114
|
+
alias :options :product_option_types
|
115
|
+
|
116
|
+
self.whitelisted_ransackable_associations = %w[stores variants_including_master master variants]
|
117
|
+
self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on]
|
118
|
+
self.whitelisted_ransackable_scopes = %w[not_discontinued]
|
119
|
+
|
120
|
+
# the master variant is not a member of the variants array
|
121
|
+
def has_variants?
|
122
|
+
variants.any?
|
123
|
+
end
|
124
|
+
|
125
|
+
def tax_category
|
126
|
+
super || TaxCategory.find_by(is_default: true)
|
127
|
+
end
|
128
|
+
|
129
|
+
# Adding properties and option types on creation based on a chosen prototype
|
130
|
+
attr_reader :prototype_id
|
131
|
+
def prototype_id=(value)
|
132
|
+
@prototype_id = value.to_i
|
133
|
+
end
|
134
|
+
|
135
|
+
# Ensures option_types and product_option_types exist for keys in option_values_hash
|
136
|
+
def ensure_option_types_exist_for_values_hash
|
137
|
+
return if option_values_hash.nil?
|
138
|
+
required_option_type_ids = option_values_hash.keys.map(&:to_i)
|
139
|
+
missing_option_type_ids = required_option_type_ids - option_type_ids
|
140
|
+
missing_option_type_ids.each do |id|
|
141
|
+
product_option_types.create(option_type_id: id)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# for adding products which are closely related to existing ones
|
146
|
+
# define "duplicate_extra" for site-specific actions, eg for additional fields
|
147
|
+
def duplicate
|
148
|
+
duplicator = ProductDuplicator.new(self)
|
149
|
+
duplicator.duplicate
|
150
|
+
end
|
151
|
+
|
152
|
+
# use deleted? rather than checking the attribute directly. this
|
153
|
+
# allows extensions to override deleted? if they want to provide
|
154
|
+
# their own definition.
|
155
|
+
def deleted?
|
156
|
+
!!deleted_at
|
157
|
+
end
|
158
|
+
|
159
|
+
# determine if product is available.
|
160
|
+
# deleted products and products with nil or future available_on date
|
161
|
+
# are not available
|
162
|
+
def available?
|
163
|
+
!(available_on.nil? || available_on.future?) && !deleted? && !discontinued?
|
164
|
+
end
|
165
|
+
|
166
|
+
def discontinue!
|
167
|
+
update_attribute(:discontinue_on, Time.current)
|
168
|
+
end
|
169
|
+
|
170
|
+
def discontinued?
|
171
|
+
!!discontinue_on && discontinue_on <= Time.current
|
172
|
+
end
|
173
|
+
|
174
|
+
# determine if any variant (including master) can be supplied
|
175
|
+
def can_supply?
|
176
|
+
variants_including_master.any?(&:can_supply?)
|
177
|
+
end
|
178
|
+
|
179
|
+
# split variants list into hash which shows mapping of opt value onto matching variants
|
180
|
+
# eg categorise_variants_from_option(color) => {"red" -> [...], "blue" -> [...]}
|
181
|
+
def categorise_variants_from_option(opt_type)
|
182
|
+
return {} unless option_types.include?(opt_type)
|
183
|
+
variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type} }
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.like_any(fields, values)
|
187
|
+
conditions = fields.product(values).map do |(field, value)|
|
188
|
+
arel_table[field].matches("%#{value}%")
|
189
|
+
end
|
190
|
+
where conditions.inject(:or)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Suitable for displaying only variants that has at least one option value.
|
194
|
+
# There may be scenarios where an option type is removed and along with it
|
195
|
+
# all option values. At that point all variants associated with only those
|
196
|
+
# values should not be displayed to frontend users. Otherwise it breaks the
|
197
|
+
# idea of having variants
|
198
|
+
def variants_and_option_values(current_currency = nil)
|
199
|
+
variants.includes(:option_values).active(current_currency).select do |variant|
|
200
|
+
variant.option_values.any?
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def empty_option_values?
|
205
|
+
options.empty? || options.any? do |opt|
|
206
|
+
opt.option_type.option_values.empty?
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def property(property_name)
|
211
|
+
product_properties.joins(:property).find_by(spree_properties: { name: property_name }).try(:value)
|
212
|
+
end
|
213
|
+
|
214
|
+
def set_property(property_name, property_value, property_presentation = property_name)
|
215
|
+
ActiveRecord::Base.transaction do
|
216
|
+
# Works around spree_i18n #301
|
217
|
+
property = Property.create_with(presentation: property_presentation).find_or_create_by(name: property_name)
|
218
|
+
product_property = ProductProperty.where(product: self, property: property).first_or_initialize
|
219
|
+
product_property.value = property_value
|
220
|
+
product_property.save!
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def total_on_hand
|
225
|
+
if any_variants_not_track_inventory?
|
226
|
+
Float::INFINITY
|
227
|
+
else
|
228
|
+
stock_items.sum(:count_on_hand)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Master variant may be deleted (i.e. when the product is deleted)
|
233
|
+
# which would make AR's default finder return nil.
|
234
|
+
# This is a stopgap for that little problem.
|
235
|
+
def master
|
236
|
+
super || variants_including_master.with_deleted.find_by(is_master: true)
|
237
|
+
end
|
238
|
+
|
239
|
+
private
|
240
|
+
|
241
|
+
def add_associations_from_prototype
|
242
|
+
if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
|
243
|
+
prototype.properties.each do |property|
|
244
|
+
product_properties.create(property: property)
|
245
|
+
end
|
246
|
+
self.option_types = prototype.option_types
|
247
|
+
self.taxons = prototype.taxons
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def any_variants_not_track_inventory?
|
252
|
+
return true unless Spree::Config.track_inventory_levels
|
253
|
+
if variants_including_master.loaded?
|
254
|
+
variants_including_master.any? { |v| !v.track_inventory? }
|
255
|
+
else
|
256
|
+
variants_including_master.where(track_inventory: false).exists?
|
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
|
+
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
|
+
# punch slug with date prefix to allow reuse of original
|
286
|
+
update_column :slug, "#{Time.current.to_i}_#{slug}"[0..254] unless frozen?
|
287
|
+
end
|
288
|
+
|
289
|
+
def update_slug_history
|
290
|
+
self.save!
|
291
|
+
end
|
292
|
+
|
293
|
+
def anything_changed?
|
294
|
+
changed? || @nested_changes
|
295
|
+
end
|
296
|
+
|
297
|
+
def reset_nested_changes
|
298
|
+
@nested_changes = false
|
299
|
+
end
|
300
|
+
|
301
|
+
def master_updated?
|
302
|
+
master && (
|
303
|
+
master.new_record? ||
|
304
|
+
master.changed? ||
|
305
|
+
(
|
306
|
+
master.default_price &&
|
307
|
+
(
|
308
|
+
master.default_price.new_record? ||
|
309
|
+
master.default_price.changed?
|
310
|
+
)
|
311
|
+
)
|
312
|
+
)
|
313
|
+
end
|
314
|
+
|
315
|
+
# there's a weird quirk with the delegate stuff that does not automatically save the delegate object
|
316
|
+
# when saving so we force a save using a hook
|
317
|
+
# Fix for issue #5306
|
318
|
+
def save_master
|
319
|
+
if master_updated?
|
320
|
+
master.save!
|
321
|
+
@nested_changes = true
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# If the master cannot be saved, the Product object will get its errors
|
326
|
+
# and will be destroyed
|
327
|
+
def validate_master
|
328
|
+
# We call master.default_price here to ensure price is initialized.
|
329
|
+
# Required to avoid Variant#check_price validation failing on create.
|
330
|
+
unless master.default_price && master.valid?
|
331
|
+
master.errors.each do |att, error|
|
332
|
+
self.errors.add(att, error)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# Try building a slug based on the following fields in increasing order of specificity.
|
338
|
+
def slug_candidates
|
339
|
+
[
|
340
|
+
:name,
|
341
|
+
[:name, :sku]
|
342
|
+
]
|
343
|
+
end
|
344
|
+
|
345
|
+
def run_touch_callbacks
|
346
|
+
run_callbacks(:touch)
|
347
|
+
end
|
348
|
+
|
349
|
+
def taxon_and_ancestors
|
350
|
+
taxons.map(&:self_and_ancestors).flatten.uniq
|
351
|
+
end
|
352
|
+
|
353
|
+
# Get the taxonomy ids of all taxons assigned to this product and their ancestors.
|
354
|
+
def taxonomy_ids
|
355
|
+
taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
|
356
|
+
end
|
357
|
+
|
358
|
+
# Iterate through this products taxons and taxonomies and touch their timestamps in a batch
|
359
|
+
def touch_taxons
|
360
|
+
Spree::Taxon.where(id: taxon_and_ancestors.map(&:id)).update_all(updated_at: Time.current)
|
361
|
+
Spree::Taxonomy.where(id: taxonomy_ids).update_all(updated_at: Time.current)
|
362
|
+
end
|
363
|
+
|
364
|
+
def ensure_no_line_items
|
365
|
+
if line_items.any?
|
366
|
+
errors.add(:base, Spree.t(:cannot_destroy_if_attached_to_line_items))
|
367
|
+
return false
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def remove_taxon(taxon)
|
372
|
+
removed_classifications = classifications.where(taxon: taxon)
|
373
|
+
removed_classifications.each &:remove_from_list
|
374
|
+
end
|
375
|
+
|
376
|
+
def discontinue_on_must_be_later_than_available_on
|
377
|
+
if discontinue_on < available_on
|
378
|
+
errors.add(:discontinue_on, :invalid_date_range)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
require_dependency 'spree/product/scopes'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductOptionType < Spree::Base
|
3
|
+
with_options inverse_of: :product_option_types do
|
4
|
+
belongs_to :product, class_name: 'Spree::Product'
|
5
|
+
belongs_to :option_type, class_name: 'Spree::OptionType'
|
6
|
+
end
|
7
|
+
acts_as_list scope: :product
|
8
|
+
|
9
|
+
validates :product, :option_type, presence: true
|
10
|
+
validates :product_id, uniqueness: { scope: :option_type_id }, allow_nil: true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Spree
|
2
|
+
class ProductPromotionRule < Spree::Base
|
3
|
+
belongs_to :product, class_name: 'Spree::Product'
|
4
|
+
belongs_to :promotion_rule, class_name: 'Spree::PromotionRule'
|
5
|
+
|
6
|
+
validates :product, :promotion_rule, presence: true
|
7
|
+
validates :product_id, uniqueness: { scope: :promotion_rule_id }, allow_nil: true
|
8
|
+
end
|
9
|
+
end
|