spree/spree — pull request #5351 by HoyaBoya (2014-09-11 16:03:35+00:00)
Title: Consistent Update Of Payment Source With Payment Attributes

This PR removes the requirement that a payment source can be added only when an order is in the payment step and has that step in the checkout flow.

Per the Spree API documents, adding a payment to an order is through a ``` PUT /api/order/checkouts/order_number``` with the payment_attributes and payment_source for that payment (example below).

However, with my understanding of the code, it's possible for the update of the order to accept the payment_attributes but not accept the associated payment_source due to the payment state machine checks in ```update_params_payment_source```. This results in a payment in the ```checkout``` state that will always fail during processing with no source.

https://github.com/spree/spree/blob/master/core/app/models/spree/payment/processing.rb#L114-L125

This causes a bunch of issues:
1) It feels inconsistent to accept one part of the payment payload but not the other without any sort of feedback to the API client, especially when for Stripe Credit Card payments, that payment_source contains critical information.
2) It feels inconsistent to the rest of the checkout API to accept changes to other payloads, i.e. the ship_address and bill_address (by design?) regardless of the checkout state, but not for payment source?
2b) Due to the way that Spree will only validate CCs on the transition to ```:complete```, and there is currently no way to to move back to ```:payment``` without forcibly updating the state, it's possible for API clients to get stuck on checkout ```:confirm``` when they have an invalid CC that fails payment processing. They cannot add a new CC due to the current check.

The current work around for 2b is something like this and I would love to remove this.

```
Spree::Order.state_machine.after_failure do: :handle_transition_failure
def handle_transition_failure(transition)
if transition.from_name.to_s == 'confirm' && transition.to_name.to_s == 'complete'
self.update_attributes!(state: 'payment')
end
end
```

Related to:
https://github.com/spree/spree/pull/5206

```Stripe Example
{
"order": {
"payments_attributes": [
{
"payment_method_id": "STRIPE GATEWAY ID"
}
]
},
"payment_source": {
"STRIPE GATEWAY ID": {
"cc_type": "visa",
"gateway_customer_profile_id": "cus_XXX",
"gateway_payment_profile_id": "card_YYY"
}
}
}
```