nimbleshop_core 0.0.1.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +13 -0
- data/Rakefile +15 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/american_express.png +0 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/authorize_net_big.png +0 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/authorizedotnet_big.png +0 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/discover.png +0 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/mastercard.png +0 -0
- data/app/assets/images/engines/nimbleshop_authorizedotnet/visa.png +0 -0
- data/app/assets/images/engines/nimbleshop_cod/cod_small.png +0 -0
- data/app/assets/images/engines/nimbleshop_paypalwp/paypal_big.png +0 -0
- data/app/assets/images/engines/nimbleshop_paypalwp/paypal_small.png +0 -0
- data/app/assets/images/engines/nimbleshop_splitable/splitable.png +0 -0
- data/app/assets/images/engines/nimbleshop_splitable/splitable_big.png +0 -0
- data/app/assets/images/engines/nimbleshop_splitable/splitable_small.png +0 -0
- data/app/assets/javascripts/admin/products/edit.js.coffee +19 -0
- data/app/assets/javascripts/admin/shipping_methods/edit.js.coffee +6 -0
- data/app/assets/javascripts/admin.js +25 -0
- data/app/assets/javascripts/fadeout_success.js.coffee +2 -0
- data/app/assets/javascripts/payment_method.js.coffee +19 -0
- data/app/assets/javascripts/product-group-condition.js.coffee +33 -0
- data/app/assets/javascripts/remove_deletion_of_product_pictures.js.coffee +5 -0
- data/app/assets/javascripts/shipit.js.coffee +10 -0
- data/app/assets/javascripts/twitter_bootstrap.js.coffee +4 -0
- data/app/assets/stylesheets/admin.css +9 -0
- data/app/assets/stylesheets/admin_bootstrap_and_overrides.css.less +38 -0
- data/app/assets/stylesheets/admin_custom.css +104 -0
- data/app/assets/twitter/bootstrap/glyphicons-halflings-white.png +0 -0
- data/app/assets/twitter/bootstrap/glyphicons-halflings.png +0 -0
- data/app/controllers/admin/custom_fields_controller.rb +56 -0
- data/app/controllers/admin/link_groups_controller.rb +76 -0
- data/app/controllers/admin/main_controller.rb +9 -0
- data/app/controllers/admin/navigations_controller.rb +49 -0
- data/app/controllers/admin/orders_controller.rb +47 -0
- data/app/controllers/admin/payment_methods_controller.rb +26 -0
- data/app/controllers/admin/product_groups_controller.rb +70 -0
- data/app/controllers/admin/products_controller.rb +71 -0
- data/app/controllers/admin/shipments_controller.rb +19 -0
- data/app/controllers/admin/shipping_methods_controller.rb +93 -0
- data/app/controllers/admin/shipping_zones_controller.rb +62 -0
- data/app/controllers/admin/shops_controller.rb +33 -0
- data/app/controllers/admin_controller.rb +38 -0
- data/app/helpers/admin_helper.rb +83 -0
- data/app/helpers/nimbleshop_helper.rb +43 -0
- data/app/helpers/payment_method_helper.rb +52 -0
- data/app/mailers/admin_mailer.rb +22 -0
- data/app/mailers/mailer.rb +31 -0
- data/app/models/address.rb +69 -0
- data/app/models/country_shipping_zone.rb +36 -0
- data/app/models/creditcard.rb +95 -0
- data/app/models/custom_field.rb +8 -0
- data/app/models/custom_field_answer/field.rb +101 -0
- data/app/models/custom_field_answer.rb +17 -0
- data/app/models/line_item.rb +48 -0
- data/app/models/link.rb +3 -0
- data/app/models/link_group.rb +8 -0
- data/app/models/navigation.rb +7 -0
- data/app/models/order.rb +158 -0
- data/app/models/payment_method.rb +20 -0
- data/app/models/payment_transaction.rb +11 -0
- data/app/models/picture.rb +30 -0
- data/app/models/product.rb +76 -0
- data/app/models/product_group.rb +65 -0
- data/app/models/product_group_condition.rb +8 -0
- data/app/models/regional_shipping_zone.rb +25 -0
- data/app/models/shipment.rb +19 -0
- data/app/models/shipment_carrier.rb +3 -0
- data/app/models/shipping_cost_calculator.rb +9 -0
- data/app/models/shipping_method.rb +103 -0
- data/app/models/shipping_zone.rb +9 -0
- data/app/models/shop.rb +26 -0
- data/app/models/tax_calculator.rb +18 -0
- data/app/observers/order_observer.rb +53 -0
- data/app/uploaders/picture_uploader.rb +65 -0
- data/app/views/admin/custom_fields/_form.html.erb +45 -0
- data/app/views/admin/custom_fields/edit.html.erb +7 -0
- data/app/views/admin/custom_fields/index.html.erb +31 -0
- data/app/views/admin/custom_fields/new.html.erb +7 -0
- data/app/views/admin/link_groups/_form.html.erb +31 -0
- data/app/views/admin/link_groups/_link_group.html.erb +50 -0
- data/app/views/admin/link_groups/_link_group_title.html.erb +5 -0
- data/app/views/admin/link_groups/edit.html.erb +8 -0
- data/app/views/admin/link_groups/index.html.erb +29 -0
- data/app/views/admin/link_groups/new.html.erb +9 -0
- data/app/views/admin/mailer/new_order_notification.text.erb +31 -0
- data/app/views/admin/main/index.html.erb +5 -0
- data/app/views/admin/navigations/new.html.erb +29 -0
- data/app/views/admin/orders/_line_item.html.erb +11 -0
- data/app/views/admin/orders/_line_items.html.erb +39 -0
- data/app/views/admin/orders/_payment_info.html.erb +20 -0
- data/app/views/admin/orders/_shipping_info.html.erb +40 -0
- data/app/views/admin/orders/index.html.erb +33 -0
- data/app/views/admin/orders/show.html.erb +40 -0
- data/app/views/admin/payment_methods/index.html.erb +6 -0
- data/app/views/admin/product_groups/_condition.html.mustache +20 -0
- data/app/views/admin/product_groups/_form.html.erb +72 -0
- data/app/views/admin/product_groups/edit.html.erb +7 -0
- data/app/views/admin/product_groups/index.html.erb +30 -0
- data/app/views/admin/product_groups/new.html.erb +7 -0
- data/app/views/admin/product_groups/show.html.erb +9 -0
- data/app/views/admin/products/_custom_field_answer.html.erb +9 -0
- data/app/views/admin/products/_form.html.erb +69 -0
- data/app/views/admin/products/_handle_pictures.html.erb +32 -0
- data/app/views/admin/products/_pictures.html.erb +33 -0
- data/app/views/admin/products/edit.html.erb +26 -0
- data/app/views/admin/products/index.html.erb +34 -0
- data/app/views/admin/products/new.html.erb +9 -0
- data/app/views/admin/shipping_methods/_form.html.erb +58 -0
- data/app/views/admin/shipping_methods/_shipping_method.html.erb +31 -0
- data/app/views/admin/shipping_methods/edit.html.erb +18 -0
- data/app/views/admin/shipping_methods/new.html.erb +7 -0
- data/app/views/admin/shipping_zones/_form.html.erb +31 -0
- data/app/views/admin/shipping_zones/_shipping_method.html.erb +13 -0
- data/app/views/admin/shipping_zones/_shipping_zone.html.erb +47 -0
- data/app/views/admin/shipping_zones/edit.html.erb +8 -0
- data/app/views/admin/shipping_zones/index.html.erb +16 -0
- data/app/views/admin/shipping_zones/new.html.erb +8 -0
- data/app/views/admin/shops/edit.html.erb +119 -0
- data/app/views/layouts/_admin_footer.html.erb +23 -0
- data/app/views/layouts/_admin_sidebar.html.erb +0 -0
- data/app/views/layouts/_container.html.erb +33 -0
- data/app/views/layouts/_top_nav_bar.html.erb +30 -0
- data/app/views/layouts/admin.html.erb +35 -0
- data/app/views/layouts/payment_method.html.erb +12 -0
- data/app/views/mailer/order_notification_to_buyer.text.erb +31 -0
- data/app/views/mailer/shipment_notification_to_buyer.text.erb +34 -0
- data/config/initializers/001_settings_application.rb +10 -0
- data/config/initializers/002_load_core_extensions.rb +8 -0
- data/config/initializers/field_with_error.rb +2 -0
- data/config/initializers/strip_and_nullify.rb +13 -0
- data/config/initializers/time_formats.rb +1 -0
- data/config/locales/en.yml +61 -0
- data/config/routes.rb +56 -0
- data/db/development.sqlite3 +0 -0
- data/db/migrate/20111022144421_create_product_groups.rb +12 -0
- data/db/migrate/20111022144426_create_products.rb +16 -0
- data/db/migrate/20111022144653_create_orders.rb +21 -0
- data/db/migrate/20111022144725_create_line_items.rb +15 -0
- data/db/migrate/20111022234951_create_shops.rb +20 -0
- data/db/migrate/20111026193227_create_link_groups.rb +12 -0
- data/db/migrate/20111026193435_create_navigations.rb +10 -0
- data/db/migrate/20111031135810_create_links.rb +10 -0
- data/db/migrate/20111106193938_create_custom_fields.rb +10 -0
- data/db/migrate/20111106195112_create_custom_field_answers.rb +14 -0
- data/db/migrate/20111106201548_create_product_group_conditions.rb +12 -0
- data/db/migrate/20111107035350_create_creditcard_transactions.rb +15 -0
- data/db/migrate/20111109190754_create_addresses.rb +24 -0
- data/db/migrate/20111125173344_create_pictures.rb +16 -0
- data/db/migrate/20111201024408_create_shipping_methods.rb +16 -0
- data/db/migrate/20111202143154_create_shipping_zones.rb +17 -0
- data/db/migrate/20111203034020_create_payment_methods.rb +14 -0
- data/db/migrate/20111221190000_create_preferences.rb +14 -0
- data/db/migrate/20120105234047_create_shipments.rb +11 -0
- data/db/migrate/20120105234553_create_shipment_carriers.rb +11 -0
- data/db/migrate/20120606165355_create_delayed_jobs.rb +22 -0
- data/db/production.sqlite3 +0 -0
- data/db/schema.rb +265 -0
- data/db/seeds.rb +1 -0
- data/db/test.sqlite3 +0 -0
- data/lib/assets/javascripts/loading_state_for_buttons.js.coffee +3 -0
- data/lib/assets/javascripts/show_help_on_hover.js.coffee +2 -0
- data/lib/assets/javascripts/utils/autoresize.js.coffee +3 -0
- data/lib/assets/javascripts/utils/focus.js.coffee +3 -0
- data/lib/assets/javascripts/utils/formatNumber.js.coffee +25 -0
- data/lib/assets/javascripts/utils/formatPrice.js.coffee +24 -0
- data/lib/generators/nimbleshop/app/app_generator.rb +84 -0
- data/lib/generators/nimbleshop/app/templates/config/application.yml +61 -0
- data/lib/generators/nimbleshop/app/templates/config/initializers/airbrake.rb +3 -0
- data/lib/generators/nimbleshop/app/templates/config/initializers/cache_images.rb +4 -0
- data/lib/generators/nimbleshop/app/templates/config/initializers/carrierwave.rb +36 -0
- data/lib/generators/nimbleshop/app/templates/config/initializers/delayed_job.rb +15 -0
- data/lib/generators/nimbleshop/app/templates/config/initializers/setup_email.rb +24 -0
- data/lib/nimbleshop/core_ext/activerecord_base.rb +18 -0
- data/lib/nimbleshop/core_ext/filelessio.rb +4 -0
- data/lib/nimbleshop/core_ext/force_ssl.rb +26 -0
- data/lib/nimbleshop/core_ext/mustache_templater_handler.rb +10 -0
- data/lib/nimbleshop/engine.rb +23 -0
- data/lib/nimbleshop/permalink/builder.rb +46 -0
- data/lib/nimbleshop/processor/base.rb +51 -0
- data/lib/nimbleshop/processor.rb +3 -0
- data/lib/nimbleshop/product_group_search/base_field.rb +19 -0
- data/lib/nimbleshop/product_group_search/core_field_strategy.rb +31 -0
- data/lib/nimbleshop/product_group_search/custom_field_strategy.rb +39 -0
- data/lib/nimbleshop/product_group_search/date_field.rb +16 -0
- data/lib/nimbleshop/product_group_search/extension.rb +46 -0
- data/lib/nimbleshop/product_group_search/number_field.rb +17 -0
- data/lib/nimbleshop/product_group_search/text_field.rb +33 -0
- data/lib/nimbleshop/product_group_search.rb +74 -0
- data/lib/nimbleshop/sampledata/data.rb +246 -0
- data/lib/nimbleshop/sampledata/pictures/product1/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product2/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product2/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product3/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product3/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product3/pic3.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product3/pic4.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product3/pic5.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product4/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product4/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product5/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product5/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic10.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic11.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic12.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic13.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic14.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic15.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic16.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic17.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic3.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic4.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic5.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic6.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic7.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic8.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product6/pic9.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product7/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product7/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product7/pic3.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic2.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic3.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic4.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic5.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic6.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic7.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product8/pic8.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product9/pic1.jpg +0 -0
- data/lib/nimbleshop/sampledata/pictures/product9/pic2.jpg +0 -0
- data/lib/nimbleshop/util.rb +60 -0
- data/lib/nimbleshop/version.rb +18 -0
- data/lib/nimbleshop_core.rb +23 -0
- data/lib/tasks/localhost2public.rake +8 -0
- data/lib/tasks/setup.rake +26 -0
- data/test/factories/address_factory.rb +31 -0
- data/test/factories/creditcard_factory.rb +30 -0
- data/test/factories/custom_field_answer_factory.rb +6 -0
- data/test/factories/custom_field_factory.rb +21 -0
- data/test/factories/line_item_factory.rb +7 -0
- data/test/factories/link_factory.rb +6 -0
- data/test/factories/link_group_factory.rb +5 -0
- data/test/factories/navigation_factory.rb +6 -0
- data/test/factories/order_factory.rb +49 -0
- data/test/factories/payment_method_factory.rb +6 -0
- data/test/factories/payment_transaction_factory.rb +42 -0
- data/test/factories/picture_factory.rb +11 -0
- data/test/factories/product_group_condition_factory.rb +40 -0
- data/test/factories/product_group_factory.rb +5 -0
- data/test/factories/products_factory.rb +11 -0
- data/test/factories/shipment_carrier_factory.rb +6 -0
- data/test/factories/shipment_factory.rb +6 -0
- data/test/factories/shipping_method_factory.rb +15 -0
- data/test/factories/shipping_zone_factory.rb +5 -0
- data/test/factories/shop_factory.rb +8 -0
- data/test/fixtures/files/avatar.png +0 -0
- data/test/fixtures/link_groups.yml +13 -0
- data/test/fixtures/payment_methods.yml +39 -0
- data/test/fixtures/shops.yml +15 -0
- data/test/helpers/admin_helper_test.rb +37 -0
- data/test/helpers/nimbleshop_helper_test.rb +17 -0
- data/test/integration/admin/link_groups_acceptance_test.rb +39 -0
- data/test/integration/admin/orders_acceptance_test.rb +63 -0
- data/test/integration/admin/payment_methods_acceptance_test.rb +13 -0
- data/test/integration/admin/product_groups_acceptance_test.rb +89 -0
- data/test/integration/admin/products_acceptance_test.rb +105 -0
- data/test/integration/admin/shipping_methods_acceptance_test.rb +63 -0
- data/test/integration/admin/shipping_zones_acceptance_test.rb +16 -0
- data/test/integration/admin/shops_acceptance_test.rb +44 -0
- data/test/integration/checkout/cart_acceptance_test.rb +113 -0
- data/test/integration/checkout/payment_confirmation_acceptance_test.rb +24 -0
- data/test/integration/checkout/paypal_acceptance_test.rb +34 -0
- data/test/integration/checkout/shipping_address_acceptance_test.rb +91 -0
- data/test/integration/checkout/shipping_method_acceptance_test.rb +51 -0
- data/test/integration/homepage_acceptance_test.rb +24 -0
- data/test/integration/products_acceptance_test.rb +12 -0
- data/test/integration/static_pages_acceptance_test.rb +13 -0
- data/test/mailers/mailer_test.rb +25 -0
- data/test/rails_app/Gemfile +27 -0
- data/test/rails_app/Gemfile.lock +218 -0
- data/test/rails_app/Rakefile +10 -0
- data/test/rails_app/app/controllers/application_controller.rb +6 -0
- data/test/rails_app/app/helpers/application_helper.rb +3 -0
- data/test/rails_app/app/views/layouts/application.html.erb +10 -0
- data/test/rails_app/config/application.rb +25 -0
- data/test/rails_app/config/application.yml +61 -0
- data/test/rails_app/config/boot.rb +5 -0
- data/test/rails_app/config/database.yml +18 -0
- data/test/rails_app/config/environment.rb +5 -0
- data/test/rails_app/config/environments/development.rb +18 -0
- data/test/rails_app/config/environments/production.rb +33 -0
- data/test/rails_app/config/environments/test.rb +33 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/inflections.rb +2 -0
- data/test/rails_app/config/initializers/secret_token.rb +2 -0
- data/test/rails_app/config/routes.rb +10 -0
- data/test/rails_app/config.ru +4 -0
- data/test/rails_app/db/development.sqlite3 +0 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +74 -0
- data/test/rails_app/db/schema.rb +52 -0
- data/test/rails_app/log/development.log +94 -0
- data/test/rails_app/log/test.log +0 -0
- data/test/rails_app/public/404.html +26 -0
- data/test/rails_app/public/422.html +26 -0
- data/test/rails_app/public/500.html +26 -0
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/rails_app/script/rails +10 -0
- data/test/support/address_test_helper.rb +24 -0
- data/test/support/checkout_test_helper.rb +40 -0
- data/test/support/dbify_sql_helper.rb +12 -0
- data/test/support/images/cookware.jpg +0 -0
- data/test/support/must_be_like.rb +24 -0
- data/test/support/shipping_method_test_helper.rb +5 -0
- data/test/support/wait_for_ajax.rb +4 -0
- data/test/test_helper.rb +65 -0
- data/test/unit/address_test.rb +33 -0
- data/test/unit/country_shipping_zone_test.rb +17 -0
- data/test/unit/creditcard_test.rb +33 -0
- data/test/unit/custom_field_answer/field_test.rb +93 -0
- data/test/unit/order_test.rb +70 -0
- data/test/unit/payment_method/authorizedotnet_test.rb +21 -0
- data/test/unit/payment_method/paypalwp_test.rb +17 -0
- data/test/unit/payment_method/splitable_test.rb +18 -0
- data/test/unit/picture_test.rb +24 -0
- data/test/unit/processor/authorize_net_test.rb +236 -0
- data/test/unit/processor/paypal_test.rb +40 -0
- data/test/unit/processor/splitable_test.rb +123 -0
- data/test/unit/product_group_condition_test.rb +188 -0
- data/test/unit/product_group_test.rb +109 -0
- data/test/unit/product_test.rb +60 -0
- data/test/unit/shipping_cost_calculator_test.rb +19 -0
- data/test/unit/shipping_method_test.rb +197 -0
- data/test/unit/shop_test.rb +11 -0
- data/test/unit/tax_calculator_test.rb +13 -0
- data/test/vcr_cassettes/authorize_net/authorize-failure.yml +38 -0
- data/test/vcr_cassettes/authorize_net/authorize-success.yml +38 -0
- data/test/vcr_cassettes/authorize_net/capture-failure.yml +38 -0
- data/test/vcr_cassettes/authorize_net/capture-success.yml +38 -0
- data/test/vcr_cassettes/authorize_net/purchase-failure.yml +38 -0
- data/test/vcr_cassettes/authorize_net/purchase-success.yml +38 -0
- data/test/vcr_cassettes/authorize_net/refund-failure.yml +38 -0
- data/test/vcr_cassettes/authorize_net/refund-success.yml +38 -0
- data/test/vcr_cassettes/authorize_net/void-authorize.yml +38 -0
- data/test/vcr_cassettes/authorize_net/void-failure.yml +38 -0
- data/test/vcr_cassettes/authorize_net/void-success.yml +38 -0
- data/test/vcr_cassettes/splitable/split-create-failure.yml +48 -0
- data/test/vcr_cassettes/splitable/split-create-success.yml +50 -0
- data/test/vcr_cassettes/splitable/split-draft-create-failure.yml +50 -0
- data/test/vcr_cassettes/splitable/split-draft-create-success.yml +50 -0
- data/vendor/assets/javascripts/accounting.js +406 -0
- data/vendor/assets/javascripts/autoresize.js +275 -0
- data/vendor/assets/javascripts/jquery-1.7.1.js +9267 -0
- data/vendor/assets/javascripts/jquery-form.js +980 -0
- data/vendor/assets/javascripts/jquery-json.js +193 -0
- data/vendor/assets/javascripts/jquery-ui-1.8.16.js +11768 -0
- data/vendor/assets/javascripts/jquery-ujs.js +374 -0
- data/vendor/assets/javascripts/mustache.js +436 -0
- data/vendor/assets/javascripts/nested_form.js +51 -0
- metadata +740 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class CountryShippingZone < ShippingZone
|
|
2
|
+
|
|
3
|
+
has_many :regional_shipping_zones, dependent: :destroy
|
|
4
|
+
|
|
5
|
+
validates :country_code, presence: true
|
|
6
|
+
validate :code_validity
|
|
7
|
+
|
|
8
|
+
before_save :set_name, if: :country_code_changed?
|
|
9
|
+
after_create :create_regions
|
|
10
|
+
|
|
11
|
+
def country
|
|
12
|
+
Carmen::Country.coded(country_code)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.all_country_codes
|
|
16
|
+
CountryShippingZone.pluck(:country_code)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def code_validity
|
|
22
|
+
unless country
|
|
23
|
+
errors.add(:country_code, "is invalid")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create_regions
|
|
28
|
+
country.subregions.each do | region |
|
|
29
|
+
regional_shipping_zones.create({ state_code: region.code, country_code: country_code })
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_name
|
|
34
|
+
self.name = country.name
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
class Creditcard
|
|
2
|
+
extend ActiveModel::Naming
|
|
3
|
+
include ActiveModel::Conversion
|
|
4
|
+
include ActiveModel::Validations
|
|
5
|
+
extend ActiveModel::Callbacks
|
|
6
|
+
include ActiveModel::Validations::Callbacks
|
|
7
|
+
|
|
8
|
+
attr_accessor :cvv, :expires_on, :number, :first_name, :last_name, :address1, :address2,
|
|
9
|
+
:cardtype, :month, :year, :state, :zipcode
|
|
10
|
+
|
|
11
|
+
alias :verification_value :cvv # ActiveMerchant needs this
|
|
12
|
+
|
|
13
|
+
delegate :display_number, to: :active_merchant_creditcard
|
|
14
|
+
|
|
15
|
+
before_validation :strip_non_numeric_values, if: :number
|
|
16
|
+
|
|
17
|
+
validates_presence_of :last_name, :first_name
|
|
18
|
+
|
|
19
|
+
validates_presence_of :number, message: "^Please enter credit card number"
|
|
20
|
+
validates_numericality_of :number, message: "^Please check the credit card number you entered"
|
|
21
|
+
validates_presence_of :cvv, message: "^Please enter CVV"
|
|
22
|
+
|
|
23
|
+
validate :validation_of_cardtype, if: lambda { |r| r.errors.empty? }
|
|
24
|
+
validate :validation_by_active_merchant, if: lambda { |r| r.errors.empty? }
|
|
25
|
+
|
|
26
|
+
def initialize(attrs = {})
|
|
27
|
+
sanitize_month_and_year(attrs)
|
|
28
|
+
|
|
29
|
+
attrs.each do | name, value |
|
|
30
|
+
send("#{name}=", value)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def verification_value?
|
|
35
|
+
true # ActiveMerchant needs this
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def persisted?
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def add_user_data(options = {})
|
|
45
|
+
options[:first_name] = first_name
|
|
46
|
+
options[:last_name] = last_name
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def add_credit_card_data(options = {})
|
|
50
|
+
options[:year] = year
|
|
51
|
+
options[:month] = month
|
|
52
|
+
options[:number] = number
|
|
53
|
+
options[:type] = cardtype
|
|
54
|
+
options[:verification_value] = verification_value
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def strip_non_numeric_values
|
|
58
|
+
self.number = number.to_s.gsub('-', '').strip
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def validation_of_cardtype
|
|
62
|
+
if cardtype = ActiveMerchant::Billing::CreditCard.type?(number)
|
|
63
|
+
self.cardtype = cardtype
|
|
64
|
+
else
|
|
65
|
+
errors.add(:base, 'Please check credit card number. It does not seem right.')
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def validation_by_active_merchant
|
|
70
|
+
amcard = active_merchant_creditcard
|
|
71
|
+
|
|
72
|
+
unless amcard.valid?
|
|
73
|
+
amcard.errors.full_messages.each { |message| errors.add(:base, message) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
amcard.errors.any?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def active_merchant_creditcard
|
|
80
|
+
options = {}
|
|
81
|
+
add_user_data(options)
|
|
82
|
+
add_credit_card_data(options)
|
|
83
|
+
|
|
84
|
+
ActiveMerchant::Billing::CreditCard.new(options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def sanitize_month_and_year(attrs)
|
|
88
|
+
month = attrs.delete("expires_on(2i)")
|
|
89
|
+
year = attrs.delete("expires_on(1i)")
|
|
90
|
+
day = attrs.delete("expires_on(3i)")
|
|
91
|
+
attrs.reverse_merge!(month: month)
|
|
92
|
+
attrs.reverse_merge!(year: year)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
class CustomFieldAnswer
|
|
2
|
+
module Field
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
def custom_field=(custom_field)
|
|
6
|
+
set_custom_field(custom_field)
|
|
7
|
+
|
|
8
|
+
extend_module
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# when question_id is assigned extend the module
|
|
12
|
+
def custom_field_id=(question_id)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
extend_module
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Override Answer initialize method to extend proper Response module
|
|
19
|
+
# For example
|
|
20
|
+
# Answer instance whose question is TextFieldQuestion will extend TextFieldResponse
|
|
21
|
+
def initialize(attributes = nil, options = {})
|
|
22
|
+
super
|
|
23
|
+
|
|
24
|
+
extend_module
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# We need to override after_initialize module to force instance to extend proper module
|
|
28
|
+
# ActiveRecord instances are created sometimes using malloc which will not invoke the initialize
|
|
29
|
+
# but they will call after_initialize
|
|
30
|
+
def after_initialize
|
|
31
|
+
extend_module
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def extend_module
|
|
35
|
+
if target_module = module_to_extend
|
|
36
|
+
# Don't include module twice
|
|
37
|
+
kind_of?(target_module) || extend(target_module)
|
|
38
|
+
|
|
39
|
+
# Force value coersion for extended module
|
|
40
|
+
#
|
|
41
|
+
# For example
|
|
42
|
+
# if answer is created as shown below
|
|
43
|
+
# case(1)
|
|
44
|
+
# q = NumberQuestion.new
|
|
45
|
+
# a = Answer.new(:question => q, :value => 23.45)
|
|
46
|
+
# a.float_value ==> nil
|
|
47
|
+
# a.value ==> '23.45'
|
|
48
|
+
#
|
|
49
|
+
# case(2)
|
|
50
|
+
# a = Answer.new(:question => q)
|
|
51
|
+
# a.value = 23.45
|
|
52
|
+
# a.float_value ==> 23.45
|
|
53
|
+
# a.value ==> '23.45'
|
|
54
|
+
#
|
|
55
|
+
# Above case appears bcoz modules are extended after
|
|
56
|
+
# attributes are assigned. reassign_value method will
|
|
57
|
+
# give the modules to fix this problem please refer
|
|
58
|
+
# to NumberResponse reassign_value
|
|
59
|
+
#
|
|
60
|
+
# Note: currently both cases will work as expected
|
|
61
|
+
reassign_value
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# This method will determine which module to extend
|
|
66
|
+
# Answer instances which are created using select might throw exception
|
|
67
|
+
# For example Answer.find(:conditions => [], :select => "value")
|
|
68
|
+
# retrieve_module_name will throw exception when it tries to access question field
|
|
69
|
+
# This is the only case Answer will fail to extend proper module
|
|
70
|
+
def module_to_extend
|
|
71
|
+
begin
|
|
72
|
+
CustomFieldAnswer::Field.const_get("#{custom_field.field_type.camelize}Field")
|
|
73
|
+
rescue
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def reassign_value
|
|
79
|
+
self.value = self.value
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
module DateField
|
|
83
|
+
def value=(value)
|
|
84
|
+
super
|
|
85
|
+
|
|
86
|
+
self.datetime_value = value
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
module NumberField
|
|
91
|
+
def value=(value)
|
|
92
|
+
super
|
|
93
|
+
|
|
94
|
+
self.number_value = value
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
module TextAnswerField
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
class CustomFieldAnswer < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :product
|
|
4
|
+
|
|
5
|
+
belongs_to :custom_field
|
|
6
|
+
alias_method :set_custom_field, :custom_field=
|
|
7
|
+
|
|
8
|
+
# this module must be included only after belong_to :custom_field definition
|
|
9
|
+
# this module overrides the dynamic methods which are added by belongs_to
|
|
10
|
+
include Field
|
|
11
|
+
|
|
12
|
+
def custom_field=(custom_field)
|
|
13
|
+
set_custom_field(custom_field)
|
|
14
|
+
|
|
15
|
+
extend_module
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class LineItem < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
# this is used only to pull the picture of the line_item. If after an order is created a product
|
|
4
|
+
# is deleted then that product and all the pictures are gone. In that case line item should
|
|
5
|
+
# display image not available. Besides image line_item should not pull any data from product and
|
|
6
|
+
# instead used the attributes copied from product to line_item
|
|
7
|
+
belongs_to :product
|
|
8
|
+
|
|
9
|
+
store :metadata, accessors: [ :picture_tiny, :picture_small, :picture_medium, :picture_large,
|
|
10
|
+
:picture_tiny_plus, :picture_small_plus, :picture_medium_plus, :picture_large_plus,
|
|
11
|
+
:product_permalink ]
|
|
12
|
+
|
|
13
|
+
belongs_to :order
|
|
14
|
+
|
|
15
|
+
validates_presence_of :order_id
|
|
16
|
+
validates_presence_of :product_id
|
|
17
|
+
validates_numericality_of :quantity, minimum: 1
|
|
18
|
+
|
|
19
|
+
before_create :copy_product_attributes
|
|
20
|
+
|
|
21
|
+
alias_attribute :name, :product_name
|
|
22
|
+
alias_attribute :description, :product_description
|
|
23
|
+
|
|
24
|
+
def price
|
|
25
|
+
product_price * quantity
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# updates quantity count. If count is zero then deletes the line_item .
|
|
29
|
+
def update_quantity(count)
|
|
30
|
+
count = count.to_i
|
|
31
|
+
(count > 0) ? update_attributes(quantity: count) : destroy
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def copy_product_attributes
|
|
37
|
+
self.product_name = product.name
|
|
38
|
+
self.product_description = product.description
|
|
39
|
+
self.product_price = product.price
|
|
40
|
+
self.product_permalink = product.permalink
|
|
41
|
+
|
|
42
|
+
if product.picture
|
|
43
|
+
%w(tiny tiny_plus small small_plus medium medium_plus large large_plus).each do |size|
|
|
44
|
+
send("picture_#{size}=", product.picture.picture_url(size.intern))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/app/models/link.rb
ADDED
data/app/models/order.rb
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
class Order < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
# to allow extensions to store any type of information
|
|
4
|
+
store :metadata
|
|
5
|
+
|
|
6
|
+
attr_accessor :validate_email, :billing_address_same_as_shipping
|
|
7
|
+
attr_protected :number
|
|
8
|
+
|
|
9
|
+
belongs_to :user
|
|
10
|
+
belongs_to :payment_method
|
|
11
|
+
belongs_to :shipping_method
|
|
12
|
+
|
|
13
|
+
has_one :shipping_address, dependent: :destroy
|
|
14
|
+
has_one :billing_address, dependent: :destroy
|
|
15
|
+
|
|
16
|
+
has_many :shipments
|
|
17
|
+
has_many :line_items, dependent: :destroy
|
|
18
|
+
has_many :products, through: :line_items
|
|
19
|
+
has_many :payment_transactions, dependent: :destroy
|
|
20
|
+
|
|
21
|
+
accepts_nested_attributes_for :shipping_address, allow_destroy: true
|
|
22
|
+
accepts_nested_attributes_for :billing_address, reject_if: :billing_address_same_as_shipping? , allow_destroy: true
|
|
23
|
+
|
|
24
|
+
delegate :tax, to: :tax_calculator
|
|
25
|
+
delegate :shipping_cost, to: :shipping_cost_calculator
|
|
26
|
+
|
|
27
|
+
validates :email, email: true, if: :validate_email
|
|
28
|
+
|
|
29
|
+
validates_inclusion_of :shipping_status, in: %W( nothing_to_ship shipped shipping_pending cancelled )
|
|
30
|
+
validates_inclusion_of :status, in: %W( open closed )
|
|
31
|
+
validates_inclusion_of :checkout_status, in: %W( items_added_to_cart billing_address_provided shipping_method_provided )
|
|
32
|
+
|
|
33
|
+
before_create :set_order_number
|
|
34
|
+
|
|
35
|
+
# Look at order_observer to see all the callbacks.
|
|
36
|
+
#
|
|
37
|
+
# capture is a method defined on kernel by Rails hence kapture is used .
|
|
38
|
+
#
|
|
39
|
+
# An order goes into pending state when it is paid for using 'Cash on delivery'
|
|
40
|
+
state_machine :payment_status, initial: :abandoned do
|
|
41
|
+
|
|
42
|
+
event(:authorize) { transition abandoned: :authorized }
|
|
43
|
+
event(:pending) { transition abandoned: :pending }
|
|
44
|
+
event(:kapture ) { transition authorized: :purchased }
|
|
45
|
+
event(:refund) { transition purchased: :refunded }
|
|
46
|
+
|
|
47
|
+
event(:purchase) { transition [:abandoned, :pending] => :purchased }
|
|
48
|
+
event(:void) { transition [:authorized, :pending] => :voided }
|
|
49
|
+
|
|
50
|
+
state all - [ :abandoned ] do
|
|
51
|
+
validates :payment_method, presence: true
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
state_machine :shipping_status, initial: :nothing_to_ship do
|
|
56
|
+
after_transition on: :shipped, do: :after_shipped
|
|
57
|
+
|
|
58
|
+
event(:shipping_pending) { transition nothing_to_ship: :shipping_pending }
|
|
59
|
+
event(:shipped) { transition shipping_pending: :shipped }
|
|
60
|
+
event(:cancel_shipment) { transition shipping_pending: :nothing_to_ship }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def mark_as_purchased!
|
|
64
|
+
touch(:purchased_at) unless purchased_at
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def available_shipping_methods
|
|
68
|
+
ShippingMethod.available_for(line_items_total, shipping_address)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def item_count
|
|
72
|
+
line_items.count
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def add(product)
|
|
76
|
+
options = { product_id: product.id }
|
|
77
|
+
if line_items.where(options).empty?
|
|
78
|
+
line_items.create(options.merge(quantity: 1))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def update_quantity(data = {})
|
|
83
|
+
data.each do |product_id, quantity|
|
|
84
|
+
if line_item = line_item_for(product_id)
|
|
85
|
+
line_item.update_quantity(quantity)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def remove(product)
|
|
91
|
+
update_quantity({product.id => 0})
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns the total price of all line items in float.
|
|
95
|
+
def line_items_total
|
|
96
|
+
line_items.reduce(BigDecimal('0')) do |sum, line_item|
|
|
97
|
+
sum + BigDecimal(line_item.price.to_s)
|
|
98
|
+
end.round(2).to_f
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def total_amount
|
|
102
|
+
line_items_total + shipping_cost + tax
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def total_amount_in_cents
|
|
106
|
+
Util.in_cents(total_amount)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def to_param
|
|
110
|
+
number
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def final_billing_address
|
|
114
|
+
(shipping_address && !shipping_address.use_for_billing) ? billing_address : shipping_address
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def initialize_addresses
|
|
118
|
+
shipping_address || build_shipping_address(country_code: "US", use_for_billing: true)
|
|
119
|
+
billing_address || build_billing_address(country_code: "US", use_for_billing: false)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def billing_address_same_as_shipping?
|
|
123
|
+
billing_address_same_as_shipping
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def line_item_for(product_id)
|
|
127
|
+
line_items.find_by_product_id(product_id)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def shippable_countries
|
|
131
|
+
ShippingMethod.available_for_countries(line_items_total)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
def set_order_number
|
|
137
|
+
num = Random.new.rand(11111111...99999999).to_s
|
|
138
|
+
while self.class.exists?(number: num) do
|
|
139
|
+
num = Random.new.rand(11111111...99999999).to_s
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
self.number = num
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def tax_calculator
|
|
146
|
+
@_tax_calculator ||= TaxCalculator.new(self)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def shipping_cost_calculator
|
|
150
|
+
@_shipping_cost_calculator ||= ShippingCostCalculator.new(self)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def after_shipped
|
|
154
|
+
Mailer.delay.shipment_notification_to_buyer(number)
|
|
155
|
+
touch(:shipped_at)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class PaymentMethod < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
store :metadata
|
|
4
|
+
|
|
5
|
+
include Permalink::Builder
|
|
6
|
+
|
|
7
|
+
# By default payment_method does not require that application must use SSL.
|
|
8
|
+
# Individual payment method should override this method.
|
|
9
|
+
def use_ssl?
|
|
10
|
+
false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def demodulized_underscore
|
|
14
|
+
self.class.name.demodulize.underscore
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.partialize
|
|
18
|
+
name.gsub("PaymentMethod::","").underscore
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Picture < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
belongs_to :product
|
|
4
|
+
|
|
5
|
+
mount_uploader :picture, PictureUploader
|
|
6
|
+
|
|
7
|
+
validates_presence_of :picture
|
|
8
|
+
|
|
9
|
+
before_save :update_picture_attributes
|
|
10
|
+
|
|
11
|
+
%w(tiny tiny_plus small small_plus medium medium_plus large large_plus).each do |version|
|
|
12
|
+
define_method :"#{version}_height" do
|
|
13
|
+
picture.send(version).height
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
define_method :"#{version}_width" do
|
|
17
|
+
picture.send(version).width
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def update_picture_attributes
|
|
24
|
+
if picture.present?
|
|
25
|
+
self.content_type = picture.file.content_type
|
|
26
|
+
self.file_size = picture.file.size
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
class Product < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
include Permalink::Builder
|
|
4
|
+
|
|
5
|
+
alias_attribute :title, :name
|
|
6
|
+
|
|
7
|
+
attr_accessor :pictures_order
|
|
8
|
+
|
|
9
|
+
validates :status, inclusion: { in: %w(active hidden sold_out) }, presence: true
|
|
10
|
+
|
|
11
|
+
has_many :pictures, order: 'pictures.position'
|
|
12
|
+
|
|
13
|
+
has_many :custom_field_answers, dependent: :destroy
|
|
14
|
+
|
|
15
|
+
accepts_nested_attributes_for :pictures, allow_destroy: true, reject_if: proc { |r| r[:picture].blank? }
|
|
16
|
+
|
|
17
|
+
accepts_nested_attributes_for :custom_field_answers, allow_destroy: true
|
|
18
|
+
|
|
19
|
+
after_initialize :initialize_status
|
|
20
|
+
|
|
21
|
+
scope :with_prictures, includes: 'pictures'
|
|
22
|
+
|
|
23
|
+
scope :active, where(status: 'active')
|
|
24
|
+
scope :hidden, where(status: 'hidden')
|
|
25
|
+
scope :sold_out, where(status: 'sold_out')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
validates_presence_of :name, :description, :price
|
|
29
|
+
|
|
30
|
+
validates_numericality_of :price
|
|
31
|
+
|
|
32
|
+
def picture
|
|
33
|
+
pictures.first
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# path is full path to the picture.
|
|
37
|
+
#
|
|
38
|
+
# Rails.root.join('db', 'original_pictures', filename )
|
|
39
|
+
#
|
|
40
|
+
# This method is used only in development and test to attach a picture.
|
|
41
|
+
def attach_picture(filename, path)
|
|
42
|
+
img = File.open(path) {|i| i.read}
|
|
43
|
+
encoded_img = Base64.encode64 img
|
|
44
|
+
io = FilelessIO.new(Base64.decode64(encoded_img))
|
|
45
|
+
io.original_filename = filename
|
|
46
|
+
p = Picture.new(product: self, picture: io)
|
|
47
|
+
p.save
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def find_or_build_answer_for_field(field)
|
|
51
|
+
custom_field_answers.detect {|t| t.custom_field_id.to_s == field.id.to_s } ||
|
|
52
|
+
custom_field_answers.build(custom_field_id: field.id)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def find_or_build_all_answers
|
|
56
|
+
CustomField.all.each { |f| find_or_build_answer_for_field(f) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def pictures_order=(value)
|
|
61
|
+
return if value.empty?
|
|
62
|
+
ordered_pictures = ActiveSupport::JSON.decode(value)
|
|
63
|
+
current_pictures = pictures
|
|
64
|
+
|
|
65
|
+
ordered_pictures.each{|position, picture_id|
|
|
66
|
+
if picture_id.present?
|
|
67
|
+
pic = current_pictures.find { |x| x.id == picture_id.to_i }
|
|
68
|
+
pic.update_column(:position, position) if pic
|
|
69
|
+
end
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def initialize_status
|
|
74
|
+
self.status ||= 'active'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class ProductGroup < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
include Permalink::Builder
|
|
4
|
+
|
|
5
|
+
validates :name, presence: true
|
|
6
|
+
|
|
7
|
+
has_many :product_group_conditions, dependent: :destroy, extend: ProductGroupSearch::Extension
|
|
8
|
+
|
|
9
|
+
has_many :navigations, dependent: :destroy
|
|
10
|
+
|
|
11
|
+
has_many :link_groups, through: :navigations
|
|
12
|
+
|
|
13
|
+
accepts_nested_attributes_for :product_group_conditions, allow_destroy: true
|
|
14
|
+
|
|
15
|
+
# determines if the given product exists in the product group
|
|
16
|
+
def contains?(product)
|
|
17
|
+
products.include?(product)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.fields
|
|
21
|
+
c = []
|
|
22
|
+
c << { "id" => 'name', "name" => 'Name', "field_type" => 'text' }
|
|
23
|
+
c << { "id" => 'price', "name" => 'Price', "field_type" => 'number' }
|
|
24
|
+
|
|
25
|
+
CustomField.all.map do | field |
|
|
26
|
+
c << field.attributes.slice("id", "name", "field_type")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
c
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.operators
|
|
33
|
+
{
|
|
34
|
+
text: [{ name: 'Contains', value: 'contains' },
|
|
35
|
+
{ name: 'Starts With', value: 'starts'},
|
|
36
|
+
{ name: 'Ends With', value:'ends'}],
|
|
37
|
+
|
|
38
|
+
number: [{ name: 'Equal', value: 'eq' },
|
|
39
|
+
{ name: 'Greater Than', value: 'gt' },
|
|
40
|
+
{ name: 'Grater Than Equal To', value:'gteq' },
|
|
41
|
+
{ name: 'Less Than', value: 'lt' },
|
|
42
|
+
{ name: 'Less Than Equal To', value: 'lteq'}],
|
|
43
|
+
|
|
44
|
+
date: [{ name: 'On', value: 'eq' },
|
|
45
|
+
{ name: 'After', value: 'gt' },
|
|
46
|
+
{ name: 'On or After', value:'gteq' },
|
|
47
|
+
{ name: 'Before', value: 'lt' },
|
|
48
|
+
{ name: 'On or Before', value: 'lteq'}],
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def products
|
|
53
|
+
product_group_conditions.search
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def summarize
|
|
57
|
+
product_group_conditions.map(&:summary).join(' and ')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# list of all product groups containing input product
|
|
61
|
+
def self.contains_product(product)
|
|
62
|
+
all.select { | product_group | product_group.contains?(product) }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|