Working with ngForm and subcontrollers. Also fixing bulk order specs

This commit is contained in:
Will Marshall
2014-04-10 16:32:08 +10:00
parent 00f5d09d65
commit 5f62cb7ddb
15 changed files with 205 additions and 172 deletions

View File

@@ -338,4 +338,4 @@ formatDate = (date) ->
twoDigitNumber = (number) ->
twoDigits = "" + number
twoDigits = ("0" + number) if number < 10
twoDigits
twoDigits

View File

@@ -0,0 +1,3 @@
Darkswarm.controller "BillingCtrl", ($scope) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.name = "billing"

View File

@@ -0,0 +1,3 @@
Darkswarm.controller "ShippingCtrl", ($scope) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.name = "shipping"

View File

@@ -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()

View File

@@ -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 ", "

View File

@@ -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

View File

@@ -4,3 +4,6 @@ checkout
orderdetails
.button, table
width: 100%
dd.valid
background: green

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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 ->

View File

@@ -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 ", "

View File

@@ -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 ", "

View File

@@ -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)