diff --git a/app/assets/javascripts/admin/bulk_order_management.js.coffee b/app/assets/javascripts/admin/bulk_order_management.js.coffee index 22cc1660cf..2d97b68ed7 100644 --- a/app/assets/javascripts/admin/bulk_order_management.js.coffee +++ b/app/assets/javascripts/admin/bulk_order_management.js.coffee @@ -338,4 +338,4 @@ formatDate = (date) -> twoDigitNumber = (number) -> twoDigits = "" + number twoDigits = ("0" + number) if number < 10 - twoDigits \ No newline at end of file + twoDigits diff --git a/app/assets/javascripts/darkswarm/controllers/checkout/billing_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout/billing_controller.js.coffee new file mode 100644 index 0000000000..2c07d96da5 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/checkout/billing_controller.js.coffee @@ -0,0 +1,3 @@ +Darkswarm.controller "BillingCtrl", ($scope) -> + angular.extend(this, new FieldsetMixin($scope)) + $scope.name = "billing" diff --git a/app/assets/javascripts/darkswarm/controllers/checkout/shipping_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout/shipping_controller.js.coffee new file mode 100644 index 0000000000..82b435852b --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/checkout/shipping_controller.js.coffee @@ -0,0 +1,3 @@ +Darkswarm.controller "ShippingCtrl", ($scope) -> + angular.extend(this, new FieldsetMixin($scope)) + $scope.name = "shipping" diff --git a/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee index bbde0d123a..7ad47f5398 100644 --- a/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/checkout_controller.js.coffee @@ -1,5 +1,4 @@ Darkswarm.controller "CheckoutCtrl", ($scope, Order, storage) -> - window.tmp = $scope $scope.Order = Order $scope.order = Order.order $scope.accordion = {} @@ -12,8 +11,9 @@ Darkswarm.controller "CheckoutCtrl", ($scope, Order, storage) -> storage.bind $scope, "accordion.billing" storage.bind $scope, "accordion.shipping" storage.bind $scope, "accordion.payment" + storage.bind $scope, "order.ship_address_same_as_billing", { defaultValue: true} + storage.bind $scope, "order.shipping_method_id" $scope.purchase = (event)-> event.preventDefault() $scope.Order.submit() - diff --git a/app/assets/javascripts/darkswarm/mixins/fieldset_mixin.js.coffee b/app/assets/javascripts/darkswarm/mixins/fieldset_mixin.js.coffee index 6bc0424744..0bd1b78ef3 100644 --- a/app/assets/javascripts/darkswarm/mixins/fieldset_mixin.js.coffee +++ b/app/assets/javascripts/darkswarm/mixins/fieldset_mixin.js.coffee @@ -1,6 +1,12 @@ window.FieldsetMixin = ($scope)-> + $scope.valid = -> + $scope.form().$valid + + $scope.form = -> + $scope[$scope.name] + $scope.field = (path)-> - $scope[$scope.name][path] + $scope.form()[path] $scope.fieldValid = (path)-> not ($scope.dirty(path) and $scope.invalid(path)) @@ -23,6 +29,3 @@ window.FieldsetMixin = ($scope)-> when "number" then "must be number" when "email" then "must be email address" (errors.filter (error) -> error?).join ", " - - - diff --git a/app/assets/javascripts/darkswarm/services/order.js.coffee b/app/assets/javascripts/darkswarm/services/order.js.coffee index 72c69bb589..e5ae4d4bb1 100644 --- a/app/assets/javascripts/darkswarm/services/order.js.coffee +++ b/app/assets/javascripts/darkswarm/services/order.js.coffee @@ -3,17 +3,21 @@ Darkswarm.factory 'Order', ($resource, Product, order, $http)-> errors: {} constructor: -> @order = order - # Here we default to the first shipping method if none is selected + # Default to first shipping method if none selected @order.shipping_method_id ||= parseInt(Object.keys(@order.shipping_methods)[0]) - @order.ship_address_same_as_billing ?= true + + navigate: (path)-> + console.log path + window.location.pathname = path submit: -> $http.put('/shop/checkout', {order: @preprocess()}).success (data, status)=> - console.log data - window.location.pathname = data.path + @navigate(data.path) .error (errors, status)=> console.log "error" @errors = errors + + # Rails wants our Spree::Address data to be provided with _attributes preprocess: -> @@ -27,6 +31,9 @@ Darkswarm.factory 'Order', ($resource, Product, order, $http)-> munged_order["payments_attributes"] = [{payment_method_id: value}] else munged_order[name] = value + # TODO: this + if munged_order.ship_address_same_as_billing + munged_order.ship_address_attributes = munged_order.bill_address_attributes munged_order shippingMethod: -> @@ -43,4 +50,3 @@ Darkswarm.factory 'Order', ($resource, Product, order, $http)-> cartTotal: -> @shippingPrice() + @order.display_total - diff --git a/app/assets/stylesheets/darkswarm/checkout.css.sass b/app/assets/stylesheets/darkswarm/checkout.css.sass index 676ab08e43..1d6819d57a 100644 --- a/app/assets/stylesheets/darkswarm/checkout.css.sass +++ b/app/assets/stylesheets/darkswarm/checkout.css.sass @@ -4,3 +4,6 @@ checkout orderdetails .button, table width: 100% + + dd.valid + background: green diff --git a/app/views/shop/checkout/_billing.html.haml b/app/views/shop/checkout/_billing.html.haml index f05908ddf4..b32c0d2498 100644 --- a/app/views/shop/checkout/_billing.html.haml +++ b/app/views/shop/checkout/_billing.html.haml @@ -1,34 +1,32 @@ %fieldset#billing - %accordion-group{"is-open" => "accordion.billing"} - %accordion-heading - .row - .large-6.columns - Billing - .large-6.columns.text-right - {{ order.bill_address.address1 }} - {{ order.bill_address.city }} - = f.fields_for :bill_address, @order.bill_address do |ba| - .row - .large-12.columns - = ba.text_field :address1, - "ng-model" => "order.bill_address.address1" - .row - .large-12.columns - = ba.text_field :address2, - "ng-model" => "order.bill_address.address2" - .row - .large-6.columns + %ng-form{"ng-controller" => "BillingCtrl", name: "billing"} + %accordion-group{"is-open" => "accordion.billing", + "ng-class" => "{valid: billing.$valid}"} + %accordion-heading + .row + .large-6.columns + Billing + .large-6.columns.text-right + {{ order.bill_address.address1 }} + {{ order.bill_address.city }} + = f.fields_for :bill_address, @order.bill_address do |ba| + .row + .large-12.columns + = validated_input "Address", "order.bill_address.address1" + .row + .large-12.columns + = validated_input "Address (contd.)", "order.bill_address.address2", required: false + .row + .large-6.columns + = validated_input "City", "order.bill_address.city" - = ba.text_field :city, - "ng-model" => "order.bill_address.city" + .large-6.columns + = ba.select :state_id, @order.billing_address.country.states.map{|c|[c.name, c.id]}, {include_blank: false}, + "ng-model" => "order.bill_address.state_id" + .row + .large-6.columns + = validated_input "Postcode", "order.bill_address.zipcode" - .large-6.columns - = ba.select :state_id, @order.billing_address.country.states.map{|c|[c.name, c.id]}, {include_blank: false}, - "ng-model" => "order.bill_address.state_id" - .row - .large-6.columns - = ba.text_field :zipcode, label: "Postcode", - "ng-model" => "order.bill_address.zipcode" - .large-6.columns.right - = ba.select :country_id, available_countries.map{|c|[c.name, c.id]}, - {include_blank: false}, "ng-model" => "order.bill_address.country_id" + .large-6.columns.right + = ba.select :country_id, available_countries.map{|c|[c.name, c.id]}, + {include_blank: false}, "ng-model" => "order.bill_address.country_id" diff --git a/app/views/shop/checkout/_details.html.haml b/app/views/shop/checkout/_details.html.haml index 74f0ad2c26..0faa40e858 100644 --- a/app/views/shop/checkout/_details.html.haml +++ b/app/views/shop/checkout/_details.html.haml @@ -1,25 +1,26 @@ %fieldset#details - %accordion-group{"is-open" => "accordion.details"} - %div{"ng-controller" => "DetailsCtrl"} - %ng-form{name: "details"} - %accordion-heading - .row - .large-6.columns - Customer Details - .large-6.columns.text-right - {{ order.bill_address.firstname }} - {{ order.bill_address.lastname }} + %ng-form{"ng-controller" => "DetailsCtrl", name: "details"} + %accordion-group{"is-open" => "accordion.details", + "ng-class" => "{valid: details.$valid}"} + %accordion-heading .row .large-6.columns - = validated_input('Email', 'order.email', type: :email) - = f.fields_for :bill_address, @order.bill_address do |ba| - .large-6.columns - = validated_input 'Phone', 'order.bill_address.phone' + Customer Details + .large-6.columns.text-right + {{ order.bill_address.firstname }} + {{ order.bill_address.lastname }} + .row + .large-6.columns + = validated_input('Email', 'order.email', type: :email) = f.fields_for :bill_address, @order.bill_address do |ba| - .row - .large-6.columns - = ba.text_field :firstname, "ng-model" => "order.bill_address.firstname" + .large-6.columns + = validated_input 'Phone', 'order.bill_address.phone' - .large-6.columns - = ba.text_field :lastname, "ng-model" => "order.bill_address.lastname" + = f.fields_for :bill_address, @order.bill_address do |ba| + .row + .large-6.columns + = validated_input "First Name", "order.bill_address.firstname" + + .large-6.columns + = validated_input "Last Name", "order.bill_address.lastname" diff --git a/app/views/shop/checkout/_shipping.html.haml b/app/views/shop/checkout/_shipping.html.haml index 62aed1d235..06bad5836b 100644 --- a/app/views/shop/checkout/_shipping.html.haml +++ b/app/views/shop/checkout/_shipping.html.haml @@ -1,76 +1,75 @@ %fieldset#shipping - %accordion-group{"is-open" => "shipping"} - %accordion-heading - .row - .large-6.columns - Shipping - .large-6.columns.text-right - {{ Order.shippingMethod().name }} - - for ship_method, i in current_distributor.shipping_methods.uniq - .row - .large-12.columns + %ng-form{"ng-controller" => "ShippingCtrl", name: "shipping"} + %accordion-group{"is-open" => "accordion.shipping", + "ng-class" => "{valid: shipping.$valid}"} + %accordion-heading + .row + .large-6.columns + Shipping + .large-6.columns.text-right + {{ Order.shippingMethod().name }} + - for ship_method, i in current_distributor.shipping_methods.uniq + .row + .large-12.columns + %label + = radio_button_tag "order[shipping_method_id]", ship_method.id, false, + "ng-model" => "order.shipping_method_id" + = ship_method.name + + #distributor_address.panel{"ng-show" => "!Order.requireShipAddress()"} + = @order.distributor.distributor_info.andand.html_safe + = @order.order_cycle.pickup_time_for(@order.distributor) + = @order.order_cycle.pickup_instructions_for(@order.distributor) + + = f.fields_for :ship_address, @order.ship_address do |sa| + #ship_address{"ng-show" => "Order.requireShipAddress()"} %label - = radio_button_tag "order[shipping_method_id]", ship_method.id, false, - "ng-model" => "order.shipping_method_id" - = ship_method.name + = hidden_field_tag "order[ship_address_same_as_billing]", "false" + = check_box_tag "order[ship_address_same_as_billing]", true, @order.ship_address_same_as_billing, + "ng-model" => "order.ship_address_same_as_billing" + Shipping address same as billing address? - #distributor_address.panel{"ng-show" => "!order.requireShipAddress()"} - = @order.distributor.distributor_info.andand.html_safe - = @order.order_cycle.pickup_time_for(@order.distributor) - = @order.order_cycle.pickup_instructions_for(@order.distributor) + %div.visible{"ng-show" => "!order.ship_address_same_as_billing"} + .row + .large-12.columns + = validated_input "Address", "order.ship_address.address1" + .row + .large-12.columns + = validated_input "Address (contd.)", "order.ship_address.address2" + .row + .large-6.columns + = validated_input "City", "order.ship_address.city" + .large-6.columns + = sa.select :state_id, @order.shipping_address.country.states.map{|c|[c.name, c.id]} + .row + .large-6.columns + = validated_input "Postcode", "order.ship_address.zipcode" + .large-6.columns.right + = sa.select :country_id, available_countries.map{|c|[c.name, c.id]}, + {include_blank: false} + .row + .large-6.columns + = validated_input "First Name", "order.ship_address.firstname" + .large-6.columns + = validated_input "Last Name", "order.ship_address.last" + .row + .large-6.columns + = validated_input "Phone", "order.ship_address.phone" - = f.fields_for :ship_address, @order.ship_address do |sa| - - #ship_address{"ng-show" => "order.requireShipAddress()"} - %label - = hidden_field_tag "order[ship_address_same_as_billing]", "false" - = check_box_tag "order[ship_address_same_as_billing]", true, @order.ship_address_same_as_billing, - "ng-model" => "order.ship_address_same_as_billing" - Shipping address same as billing address? - - %div.visible{"ng-show" => "!order.ship_address_same_as_billing"} - .row - .large-12.columns - = sa.text_field :address1 - .row - - .large-12.columns - = sa.text_field :address2 - - .row - .large-6.columns - = sa.text_field :city - .large-6.columns - = sa.select :state_id, @order.shipping_address.country.states.map{|c|[c.name, c.id]} - .row - .large-6.columns - = sa.text_field :zipcode, label: "Postcode" - .large-6.columns.right - = sa.select :country_id, available_countries.map{|c|[c.name, c.id]}, - {include_blank: false} - .row - .large-6.columns - = sa.text_field :firstname - .large-6.columns - = sa.text_field :lastname - .row - .large-6.columns - = sa.text_field :phone - - #ship_address_hidden{"ng-show" => "order.ship_address_same_as_billing"} - = sa.hidden_field :address1, "ng-value" => "order.bill_address.address1", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :address2, "ng-value" => "order.bill_address.address2", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :city, "ng-value" => "order.bill_address.city", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :country_id, "ng-value" => "order.bill_address.country_id", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :zipcode, "ng-value" => "order.bill_address.zipcode", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :firstname, "ng-value" => "order.bill_address.firstname", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :lastname, "ng-value" => "order.bill_address.lastname", - "ng-disabled" => "!order.ship_address_same_as_billing" - = sa.hidden_field :phone, "ng-value" => "order.bill_address.phone", - "ng-disabled" => "!order.ship_address_same_as_billing" + -##ship_address_hidden{"ng-show" => "order.ship_address_same_as_billing"} + -#= sa.hidden_field :address1, "ng-value" => "order.bill_address.address1", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :address2, "ng-value" => "order.bill_address.address2", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :city, "ng-value" => "order.bill_address.city", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :country_id, "ng-value" => "order.bill_address.country_id", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :zipcode, "ng-value" => "order.bill_address.zipcode", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :firstname, "ng-value" => "order.bill_address.firstname", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :lastname, "ng-value" => "order.bill_address.lastname", + -#"ng-disabled" => "!order.ship_address_same_as_billing" + -#= sa.hidden_field :phone, "ng-value" => "order.bill_address.phone", + -#"ng-disabled" => "!order.ship_address_same_as_billing" diff --git a/app/views/shop/checkout/edit.html.haml b/app/views/shop/checkout/edit.html.haml index 6d1ef446c7..5adefc5fdb 100644 --- a/app/views/shop/checkout/edit.html.haml +++ b/app/views/shop/checkout/edit.html.haml @@ -8,9 +8,7 @@ %accordion.row{"close-others" => "true"} %checkout{"ng-controller" => "CheckoutCtrl"} - - %pre - {{ Order.errors | json }} + {{ order }} .large-9.columns - unless spree_current_user = render partial: "shop/checkout/authentication" diff --git a/spec/javascripts/unit/bulk_order_management_spec.js.coffee b/spec/javascripts/unit/bulk_order_management_spec.js.coffee index f75e6ed6fe..b770e9b7b1 100644 --- a/spec/javascripts/unit/bulk_order_management_spec.js.coffee +++ b/spec/javascripts/unit/bulk_order_management_spec.js.coffee @@ -23,20 +23,19 @@ describe "AdminOrderMgmtCtrl", -> httpBackend.expectGET("/api/order_cycles/managed").respond returnedOrderCycles spyOn(scope, "initialiseVariables").andCallThrough() spyOn(scope, "fetchOrders").andReturn "nothing" - spyOn(returnedSuppliers, "unshift") - spyOn(returnedDistributors, "unshift") - spyOn(returnedOrderCycles, "unshift") + #spyOn(returnedSuppliers, "unshift") + #spyOn(returnedDistributors, "unshift") + #spyOn(returnedOrderCycles, "unshift") scope.initialise "api_key" httpBackend.flush() - #expect(scope.suppliers).toEqual ["list of suppliers"] - expect(scope.distributors).toEqual ["list of distributors"] - expect(scope.orderCycles).toEqual [ "oc1", "oc2", "oc3" ] - expect(scope.initialiseVariables.calls.length).toEqual 1 - expect(scope.fetchOrders.calls.length).toEqual 1 - expect(returnedSuppliers.unshift.calls.length).toEqual 1 - expect(returnedDistributors.unshift.calls.length).toEqual 1 - expect(returnedOrderCycles.unshift.calls.length).toEqual 1 - expect(scope.spree_api_key_ok).toEqual true + + expect(scope.suppliers).toEqual [{ id : '', name : 'All' }, 'list of suppliers'] + expect(scope.distributors).toEqual [ { id : '', name : 'All' }, 'list of distributors' ] + expect(scope.orderCycles).toEqual [ { id : '', name : 'All' }, 'oc1', 'oc2', 'oc3' ] + + expect(scope.initialiseVariables.calls.length).toBe 1 + expect(scope.fetchOrders.calls.length).toBe 1 + expect(scope.spree_api_key_ok).toBe true describe "fetching orders", -> beforeEach -> diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout/details_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout/details_controller_spec.js.coffee new file mode 100644 index 0000000000..a536988720 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/controllers/checkout/details_controller_spec.js.coffee @@ -0,0 +1,31 @@ +describe "DetailsCtrl", -> + ctrl = null + scope = null + order = null + + beforeEach -> + module("Darkswarm") + inject ($controller, $rootScope) -> + scope = $rootScope.$new() + ctrl = $controller 'DetailsCtrl', {$scope: scope} + + + it "finds a field by path", -> + scope.details = + path: "test" + expect(scope.field('path')).toEqual "test" + + it "tests validity", -> + scope.details = + path: + $dirty: true + $invalid: true + expect(scope.fieldValid('path')).toEqual false + + it "returns errors by path", -> + scope.details = + path: + $error: + email: true + required: true + expect(scope.fieldErrors('path')).toEqual ["must be email address", "must not be blank"].join ", " diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee index 9c267f4976..b4df9d4b9f 100644 --- a/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/checkout_controller_spec.js.coffee @@ -7,6 +7,7 @@ describe "CheckoutCtrl", -> module("Darkswarm") order = { submit: -> + navigate: -> } inject ($controller, $rootScope) -> scope = $rootScope.$new() @@ -22,23 +23,3 @@ describe "CheckoutCtrl", -> spyOn(order, "submit") scope.purchase(event) expect(order.submit).toHaveBeenCalled() - - it "finds a field by path", -> - scope.checkout = - path: "test" - expect(scope.field('path')).toEqual "test" - - it "tests validity", -> - scope.checkout = - path: - $dirty: true - $invalid: true - expect(scope.fieldValid('path')).toEqual false - - it "returns errors by path", -> - scope.checkout = - path: - $error: - email: true - required: true - expect(scope.fieldErrors('path')).toEqual ["must be email address", "must not be blank"].join ", " diff --git a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee index 3606fcef29..9559af0fd2 100644 --- a/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/order_spec.js.coffee @@ -7,8 +7,8 @@ describe 'Order service', -> orderData = { id: 3102 payment_method_id: null - bill_address: {} - ship_address: {} + bill_address: {test: "foo"} + ship_address: {test: "bar"} shipping_methods: 7: require_ship_address: true @@ -26,12 +26,14 @@ describe 'Order service', -> inject ($injector, _$httpBackend_)-> $httpBackend = _$httpBackend_ Order = $injector.get("Order") + spyOn(Order, "navigate") # Stubbing out writes to window.location it "defaults the shipping method to the first", -> expect(Order.order.shipping_method_id).toEqual 7 expect(Order.shippingMethod()).toEqual { require_ship_address : true, price : 0 } - it "defaults to 'same as billing' for address", -> + # This is now handled via localStorage defaults + xit "defaults to 'same as billing' for address", -> expect(Order.order.ship_address_same_as_billing).toEqual true it 'Tracks whether a ship address is required', -> @@ -59,3 +61,9 @@ describe 'Order service', -> expect(Order.preprocess().bill_address).toBe(undefined) expect(Order.preprocess().ship_address_attributes).not.toBe(undefined) expect(Order.preprocess().ship_address).toBe(undefined) + + it "Munges the order attributes to clone ship address from bill address", -> + Order.order.ship_address_same_as_billing = false + expect(Order.preprocess().ship_address_attributes).toEqual(orderData.ship_address) + Order.order.ship_address_same_as_billing = true + expect(Order.preprocess().ship_address_attributes).toEqual(orderData.bill_address)