Compare commits

..

257 Commits
v1.9 ... v1.10

Author SHA1 Message Date
Rob H
9642e8295e Merge transifex translations 2017-10-21 00:23:40 +11:00
Enrico Stano
1424d44eab Merge pull request #1919 from nicolauduran/add-dev-doc
Add more development documentation
2017-10-20 14:31:43 +02:00
Nicolau Duran
0a5f0a518d Add development doc 2017-10-20 13:18:21 +02:00
Transifex-Openfoodnetwork
ff1672e411 Updating translations for config/locales/nb.yml [skip ci] 2017-10-20 19:50:21 +11:00
Transifex-Openfoodnetwork
32d8368990 Updating translations for config/locales/fr.yml [skip ci] 2017-10-20 19:42:24 +11:00
Lynne
e7f8102eb9 Update en-GB.yml 2017-10-20 08:29:18 +01:00
Rob Harrington
24e1d0b775 Fix mistyped translation key for 'dashboard' 2017-10-20 16:26:08 +11:00
Rob Harrington
ceadd386aa Update order spec to test an order with a total > 0
This is necessary because the previous commit changed the logic
around payment state, meaning that a complete order with a total
of 0 and no complete paymnents is considered to have a payment
state of 'paid'. I don't think this is problematic, since it is
not possible to check out an order without line items.

This way the spec tests an order modelled on the real world.
2017-10-20 15:21:59 +11:00
Rob Harrington
d42dc2b286 Fix #1902: ensure correct payment state when failed payments are present
Problem: order payments didn't seem to be loaded in any particular order,
and OrderUpdater#update_payment_state was relying on payment order to de-
termine payment state.

Strategy: Adapt a version of this method from a future version of Spree.
I tried to select a version where I would have to make the absolute mini-
mum number of changes to get it to work. See comments in code for justif-
ications of the changes that I did make.
2017-10-20 15:21:59 +11:00
Continuous Integration
e9c8e17710 Merge remote-tracking branch 'origin/master' into HEAD 2017-10-19 20:42:35 +11:00
Lynne
bfd845915c Update en-GB.yml 2017-10-19 10:41:21 +01:00
Rob Harrington
b7976a2356 Do not update finalized fee adjustments 2017-10-19 16:54:39 +11:00
Rob Harrington
cd744dab68 Ignore .byebug_history after recent update of byebug gem 2017-10-19 10:45:24 +11:00
Transifex-Openfoodnetwork
02e3aac3f0 Updating translations for config/locales/fr.yml [skip ci] 2017-10-19 04:38:24 +11:00
Transifex-Openfoodnetwork
50075f02a0 Updating translations for config/locales/es.yml [skip ci] 2017-10-18 19:29:14 +11:00
Enrico Stano
05d8cd09e3 Merge pull request #1890 from coopdevs/add-node-version
Track node version in .node-version
2017-10-18 09:24:06 +02:00
Justyna Field
02fd87158e Add display flex on active table row to fix misalignment 2017-10-18 15:05:55 +11:00
Pierre de Lacroix
165af4b812 Use I18n "lazy" lookup 2017-10-18 14:38:40 +11:00
Pierre de Lacroix
dba8e36752 Change key for uncapitalized "items" translation 2017-10-18 14:38:40 +11:00
Pierre de Lacroix
a245590114 Fix some translations 2017-10-18 14:38:40 +11:00
Continuous Integration
5ecae39051 Merge remote-tracking branch 'origin/master' into HEAD 2017-10-17 19:36:45 +11:00
Transifex-Openfoodnetwork
2508234a7c Updating translations for config/locales/en_GB.yml [skip ci] 2017-10-17 19:23:35 +11:00
Transifex-Openfoodnetwork
da5f9e7ebc Updating translations for config/locales/nb.yml [skip ci] 2017-10-16 20:00:37 +11:00
Rob Harrington
0d483882de Update helper messages in Stripe Connect config UI 2017-10-16 10:37:04 +11:00
Rob Harrington
9e40502876 Update stripe controller routing comments 2017-10-16 09:39:15 +11:00
Continuous Integration
c38e58159f Merge remote-tracking branch 'origin/master' into HEAD 2017-10-13 18:57:25 +11:00
Transifex-Openfoodnetwork
acf0919bfa Updating translations for config/locales/en_GB.yml [skip ci] 2017-10-13 18:33:41 +11:00
Rob Harrington
bca409bfe4 Bumping very outdated versions of pry and byebug 2017-10-13 15:47:59 +11:00
Pierre de Lacroix
1fe10b4b25 Add pointer cursor to other links in products bulk edit 2017-10-13 15:33:30 +11:00
Pierre de Lacroix
768378b147 Add pointer cursor to EXPAND ALL link in products bulk edit 2017-10-13 15:33:30 +11:00
Rob Harrington
1fcbf6b44d Clear shipping_method_id from order when restarting checkout
If the order is allowed to retain a shipping_method_id, then subsequent
saves of the order will cause a new shipment to be initialised. Seems to
only happen for delivery shipping methods. This is undesirable because
fees for the new shipment will appear in the checkout summary, which is
not smart enough to recognise existing shipment fees and adjust the order
total accordingly.
2017-10-13 12:53:35 +11:00
Rob Harrington
f96502c369 Add unit specs for CheckoutController#restart_checkout 2017-10-13 12:53:35 +11:00
Rob Harrington
c031b0e52b Clear shipments and payments after failed payment at checkout 2017-10-13 12:53:35 +11:00
Rob Harrington
6006952603 Moving checkout request specs into their own folder 2017-10-13 12:53:35 +11:00
Duende13
e5fb8712d7 Simplify Product Edit Screen removing fields and adding 2 new menu options for seo and group buy (#1741) 2017-10-13 11:37:57 +11:00
Pierre de Lacroix
508dfa4f23 Fix failing tests assuming localizeCurrency has no "delimiter" 2017-10-13 10:26:13 +11:00
Pierre de Lacroix
65d176f533 Fix wrong way to force currency symbol after the amount 2017-10-13 10:26:13 +11:00
Pierre de Lacroix
089c754f62 Remove conversion of amounts to currency strings via Money in serializers as it's better done in JS 2017-10-13 10:26:13 +11:00
Pierre de Lacroix
aae8f1cbc4 Change localizeCurrency filter to use I18n.toCurrency 2017-10-13 10:26:12 +11:00
Matt-Yorkley
7194db40ee Merge pull request #1895 from Matt-Yorkley/codeclimate-symbol-arrays
Relax rubocop Style/SymbolArray rule
2017-10-13 00:06:32 +01:00
Rob Harrington
f2ad087be5 Change inheritance of StripeAccountsController 2017-10-13 07:57:16 +11:00
Rob Harrington
0b8b5e694e Move Stripe Connect callback action to dedicated controller 2017-10-12 22:47:51 +11:00
Rob Harrington
01f9fd3232 Rename webhook handler status mappings 2017-10-12 22:47:51 +11:00
Rob Harrington
99cac20725 Fall back to 200 when handler returns an unknown result 2017-10-12 22:47:51 +11:00
Rob Harrington
068dbe5013 Add verification to Stripe webhook endpoint 2017-10-12 22:47:45 +11:00
Rob Harrington
ed375a1e2c Build Event object in controller instead of service object 2017-10-12 20:51:17 +11:00
Rob Harrington
4345285164 Allow more granularity in Stripe WebhookHandler responses 2017-10-12 20:51:17 +11:00
Rob Harrington
eb7cb02f33 Namespace stripe webhook controller in Stripe module 2017-10-12 20:50:29 +11:00
Rob Harrington
f22dd7513d Add a service object for handling Stripe webhooks 2017-10-11 17:50:46 +11:00
Rob Harrington
c54119f482 Rename stripe controller action from 'deauthorize' to 'webhook' 2017-10-11 17:11:02 +11:00
Rob Harrington
23d2b3a664 Move Stripe webhook logic into dedicated frontend controller 2017-10-11 16:38:19 +11:00
Rob Harrington
c747bb5305 Remove improper use of quick_login_as_admin from unit spec 2017-10-11 16:10:08 +11:00
Matt-Yorkley
d147d2035d Disable symbol array cop 2017-10-07 11:50:59 +01:00
Maikel Linke
4dd71c1240 Add CSS workaround to display repeated table head
Fixes https://github.com/openfoodfoundation/openfoodnetwork/issues/1738
2017-10-06 16:51:19 +11:00
Maikel Linke
6ad7c7b835 Tidy up HTML indent 2017-10-06 14:24:28 +11:00
Maikel Linke
10bbc5f9ef Hide the menu on embedded group pages 2017-10-06 14:24:28 +11:00
Maikel Linke
b8a124b99e Add preview page for embedded groups 2017-10-06 14:24:28 +11:00
Maikel Linke
28b1ea2d9f Allow group pages to be in iframes 2017-10-06 14:24:28 +11:00
Maikel Linke
2b989f49ea Enable iframes in development environment 2017-10-06 14:24:28 +11:00
Enrico Stano
bdc701f880 Merge pull request #1816 from coopdevs/disable-create-profile-on-submit
Disable create profile on submit
2017-10-05 15:25:37 +02:00
Enrico Stano
7af154d675 Merge pull request #1820 from coopdevs/missing-translations-register
Missing translations in Enterprise Registration
2017-10-05 13:12:09 +02:00
Pau Perez
2552b5faac Track node version in .node-version
This is used by https://github.com/nodenv/nodenv
2017-09-29 16:11:22 +02:00
Pau Perez
d8e3052575 Ensure a callback function is provided 2017-09-29 16:10:11 +02:00
Transifex-Openfoodnetwork
3c797d3b86 Updating translations for config/locales/es.yml [skip ci] 2017-09-27 00:23:20 +10:00
Transifex-Openfoodnetwork
46ca3bc950 Updating translations for config/locales/fr.yml [skip ci] 2017-09-26 19:51:50 +10:00
Rob Harrington
75ec77dc31 Remove the 'confirm' step from the order checkout flow
This step is not being responded to anyway, since we are not rending a page for each checkout step

It was causing an issue whereby an order in the 'confirm' state was not able to progress through the
checkout controller because it was expecting to only redirect to paypal from the 'payment' state.
figured it was easiest to just remove the step, seeing as it wasn't being used in any meaningful way.
It should be fine to bring the 'confirm' step back in the future if we need it, we will just have to
make sure paypal the paypal issue is resolved.
2017-09-23 15:15:06 +10:00
Rob Harrington
a09a54e4cb Set transaction fee adjustments to ineligible if payment is invalid or failed 2017-09-23 15:15:06 +10:00
Rob Harrington
e486dbd4f8 Respond to Stripe webhook with status of 204 if specified account is not found 2017-09-23 14:58:35 +10:00
Rob Harrington
db5503dd80 Allow destruction of StripeAccounts even if deauthorise request fails
Log deauthorise failures to Bugsnag
2017-09-23 14:58:35 +10:00
Rob Harrington
dd3d205536 Update deauthorize webhook to latest version of API (again) 2017-09-23 14:58:35 +10:00
Rob Harrington
90007d7114 Prevent Stripe-based payment methods that are not linked to a StripeAccount from displaying in the checkout 2017-09-23 14:58:35 +10:00
Rob Harrington
7ba99c0fe0 Update Bogus Gateway error message in checkout spec 2017-09-23 14:58:35 +10:00
Rob Harrington
ba61f94906 Expose Stripe token creation error messages in Checkout 2017-09-23 14:58:35 +10:00
Rob Harrington
7c82fa3d44 Show more helpful payment processing error in checkout 2017-09-23 14:58:35 +10:00
Rob Harrington
665749d0c5 Refactor Stripe::AccountConnector
Connector now handles cancellation of the connection wizard by the user more elegantly
2017-09-23 14:58:35 +10:00
Rob Harrington
d3566f9303 Update deauthorize webhook to latest version of API 2017-09-23 14:58:35 +10:00
Rob Harrington
7d2deca969 Ensure cart_spec runs in context where backorders are disabled 2017-09-23 14:58:35 +10:00
Rob Harrington
0f19be4db4 Configure StripeElements service to map cc_type to that used by activemerchant 2017-09-23 14:58:35 +10:00
Rob Harrington
393a4efbf6 Fix flaky OrderSerializer spec
Make sure that completed payment is for an amount less that the order total
2017-09-23 14:58:35 +10:00
Rob Harrington
34b109cbb7 Add basic validation to credit card form on account page 2017-09-23 14:58:35 +10:00
Rob Harrington
4785f3eacc Use lowercased cc_type in CreditCard service 2017-09-23 14:58:34 +10:00
Rob Harrington
e14b017f1f Fix broken Stripe checkout spec 2017-09-23 14:58:34 +10:00
Rob Harrington
d2096cf6d1 Make request stubs less brittle by using regex 2017-09-23 14:58:34 +10:00
Rob Harrington
fbda1a27ad Add missing translation referenced from spree_auth_devise 2017-09-23 14:58:34 +10:00
Rob Harrington
098afc62c1 Fix rubocop issues 2017-09-23 14:58:34 +10:00
Rob Harrington
1cd1e9dc37 Extract filters for available PMs into service object 2017-09-23 14:58:34 +10:00
Rob Harrington
0bbaafbd41 Use guard clause 2017-09-23 14:58:34 +10:00
Rob Harrington
0e42c1cf30 Refactor ProfileStorer, call options as a separate method 2017-09-23 14:58:34 +10:00
Rob Harrington
620721c8cb Use find_by_id instead of find in EnterpriseController 2017-09-23 14:58:34 +10:00
Rob Harrington
5cba635783 Add documentation to StripeConnectSettings controller 2017-09-23 14:58:34 +10:00
Rob Harrington
08c723b10f Use expect syntax instead of should 2017-09-23 14:58:34 +10:00
Rob Harrington
61feb2b27d Rename Stripe existing_card param key to existing_card_id 2017-09-23 14:58:34 +10:00
Rob Harrington
a2dee8d3d8 Create a Struct for Stripe Connect settings once rather than on each request 2017-09-23 14:58:34 +10:00
Rob Harrington
a74c502fd9 Refactor logic for creating a payment profile from a Stripe token into a service object 2017-09-23 14:58:34 +10:00
Rob Harrington
f6c3a2a46e Remove new credit card initialisation logic from Spree::UsersController#show 2017-09-23 14:58:34 +10:00
Rob Harrington
4464a85a74 Add missing controller specs for CreditCardController #destroy 2017-09-23 14:58:34 +10:00
Rob Harrington
22bbe29f3d Call single-use before_filters from actions instead 2017-09-23 14:58:34 +10:00
Rob Harrington
9832966b77 Fix Admin::PaymentsController spec 2017-09-23 14:58:34 +10:00
Rob Harrington
19213a5ca8 Rearrange new card inputs on account page 2017-09-23 14:58:34 +10:00
Rob Harrington
3a0b47c451 Add border to Stripe Elements input, make text larger 2017-09-23 14:58:34 +10:00
Rob Harrington
0cd43987de Hide Stripe payment methods without a preferred_enterprise_id from the front-end 2017-09-23 14:58:34 +10:00
Rob Harrington
ca1987fc87 Prevent Stripe payment methods without account owners from being saved 2017-09-23 14:58:34 +10:00
Rob Harrington
2f153d799b Hide 'save credit card' checkbox for guests 2017-09-23 14:58:34 +10:00
Rob Harrington
742dd0b5dd Clean up jquery dialog styling 2017-09-23 14:58:34 +10:00
Rob Harrington
ecef905444 Allow Stripe-based payments to be voided (refunded) 2017-09-23 14:58:34 +10:00
Rob Harrington
dd56e03be1 Stop setting host for url helpers in specs 2017-09-23 14:58:34 +10:00
Rob Harrington
7b456461f3 Add ng-model directive to save credit card checkbox
I have no idea how this was working before\?!\?!\?!
2017-09-23 14:58:34 +10:00
Rob Harrington
e4872172c8 Move PaymentMethodSerializer to correct path 2017-09-23 14:58:34 +10:00
Rob Harrington
2ed5e144ca Convert problematic embedded shopfronts feature spec into request spec 2017-09-23 14:58:34 +10:00
Rob Harrington
f9df4d4c93 Rewrite js unit specs for Stripe Elements service 2017-09-23 14:58:34 +10:00
Rob Harrington
1aa477c57c Update feature specs to look for Stripe Elements element 2017-09-23 14:58:34 +10:00
Rob Harrington
69385370ee Initialize Stripe object only if a publishable_key has been defined 2017-09-23 14:58:34 +10:00
Rob Harrington
65ab83a9a5 Move StripeElements element to an AngularJS directive, mount from there 2017-09-23 14:58:34 +10:00
Rob Harrington
746c2ffef9 Add 'publishable_key' property to Stripe module (enables stubbing) 2017-09-23 14:58:34 +10:00
stveep
6690f2e9e7 Restyle add card form 2017-09-23 14:58:34 +10:00
stveep
74a7cb82bc Modify to use Stripe Elements to manually add cards in Account page. Remove StripeJS service 2017-09-23 14:58:34 +10:00
stveep
15ed4c32d9 Checkout switched to Stripe Elements from StripeJS 2017-09-23 14:58:34 +10:00
stveep
56ff877b25 Use Stripe Elements instead of StripeJS: https://stripe.com/docs/elements 2017-09-23 14:58:34 +10:00
Maikel Linke
926f196b96 Re-generate rubocop_todo 2017-09-23 14:58:34 +10:00
Maikel Linke
5b7e2f7ca8 Apply style guide 2017-09-23 14:58:34 +10:00
stveep
0a12f78444 Separate files for Payment Method serializers 2017-09-23 14:58:33 +10:00
stveep
da5c907e0f Add/remove comments from PR feedback 2017-09-23 14:58:33 +10:00
stveep
f065cbe251 Fix specs for saved credit cards: Add payment profile ID to fixture (now denotes that a card has been saved), check for current user to avoid error attempting to inject saved cards as a guest 2017-09-23 14:58:33 +10:00
stveep
511afa0ddc Bump Stripe gem version 2017-09-23 14:58:33 +10:00
Rob Harrington
d5ab9eb675 Hide option to 'Remember this card' when an existing card is selected 2017-09-23 14:58:33 +10:00
Rob Harrington
cb08011450 Fix typo in Stripe confirm modal 2017-09-23 14:58:33 +10:00
Rob Harrington
41b7be900c Restrict the meaning of 'Saved Cards' to mean those with a payment profile 2017-09-23 14:58:33 +10:00
Rob Harrington
6133b302af Use guard clause in PaymentMethodsController#restrict_stripe_account_change 2017-09-23 14:58:33 +10:00
Rob Harrington
4fb1c7fd92 Add 'Stripe is in Beta' warning 2017-09-23 14:58:33 +10:00
Rob Harrington
b31881baa5 Add explanation about configuring Stripe API keys 2017-09-23 14:58:33 +10:00
Rob Harrington
4e96487da9 Redirect to #/payment methods from stripe connect callback 2017-09-23 14:58:33 +10:00
Rob Harrington
98317e96d0 Remove unused stripe action abilities 2017-09-23 14:58:33 +10:00
Rob Harrington
4865533f26 Restrict edit permissions on Stripe payment methods 2017-09-23 14:58:33 +10:00
Rob Harrington
1f8890b430 Use an explicit date format for PaymentsSerializer#updated_at 2017-09-23 14:58:33 +10:00
Rob Harrington
11daf89005 Add admin views for Stripe payment methods
These views were pretty much just copied from https://github.com/spree/spree_gateway
2017-09-23 14:58:33 +10:00
Rob Harrington
fab893e60b Fix paypal source_form view
The previous commit broke the selectors used by app/assets/javascripts/spree/backend/paypal_express.js
in the better_spree_paypal_express gem.

We can remove this override of the paypal source_form view when we update better_spree_paypal_express
to a version that includes the following commit:
4360a1fb82
2017-09-23 14:58:33 +10:00
Rob Harrington
a04116466e Fix js for switching form partial for new admin payments
All of the functional changes made in this commit came from a future version of Spree:
8a3a80b08a
2017-09-23 14:58:33 +10:00
Rob Harrington
2f6493bb86 Use ng-cloak for admin/enterprises/edit form 2017-09-23 14:58:33 +10:00
Rob Harrington
589c2a1500 Add a modal to handle explanation of user's responsibilities before redirecting to Stripe 2017-09-23 14:58:33 +10:00
Rob Harrington
8cae874109 Fix styling on jquery dialogs 2017-09-23 14:58:33 +10:00
Rob Harrington
7c406f7c3a Use hash navigation to direct users to #/payment_methods from Stripe PM 2017-09-23 14:58:33 +10:00
Rob Harrington
862443ed6d Add hash navigation to admin Enterprise edit view 2017-09-23 14:58:33 +10:00
Rob Harrington
3b78179dea Ask customer about saving card details used in checkout 2017-09-23 14:58:33 +10:00
Rob Harrington
f317cee9e9 Tweak UI for selecting an existing card at Checkout 2017-09-23 14:58:33 +10:00
Rob Harrington
35912605c3 Include customer name in source attrs for Stripe checkout requests 2017-09-23 14:58:33 +10:00
Rob Harrington
8901af897a Store card details submitted via checkout 2017-09-23 14:58:33 +10:00
Rob Harrington
ee92f46bd5 Fix stripe request spec by providing en enterprise_id
The enterprise_id is used to lookup a StripeAccount which is provided to the Spree::Token#create call in the StripeConnect gateway
2017-09-23 14:58:33 +10:00
Rob Harrington
44ba499ad9 Stub rather than set Stripe api_key in specs 2017-09-23 14:58:33 +10:00
Rob Harrington
44d172f3b4 Mock stripe_account_id for StripeAccount gateway specs 2017-09-23 14:58:33 +10:00
Rob Harrington
d2b6ba4330 Provide a Stripe client_id for StripeAccountsController spec 2017-09-23 14:58:33 +10:00
Rob Harrington
576e4db9be Authorize StripeAccount#status using the account object
Rather than the enterprise
2017-09-23 14:58:33 +10:00
Rob Harrington
692ccf0598 Cleaning up oauth2 extension that is no longer required
(We're using Stripes built-in OAuth Libraries instead)
2017-09-23 14:58:33 +10:00
Rob Harrington
ce65a9d063 Bump stripe gem version to 3.0.1
Allows us to use the stripe gem's built-in OAuth wrappers, rather than our own
2017-09-23 14:58:33 +10:00
Rob Harrington
ffc99df373 Consolidate Stripe routes/actions into StripeAccountsController 2017-09-23 14:58:33 +10:00
Rob Harrington
5c58d30ca7 Create payment from user-specified payment method when using existing card 2017-09-23 14:58:33 +10:00
Rob Harrington
3efabf5c50 Add translations for Stripe connection flashes 2017-09-23 14:58:33 +10:00
Rob Harrington
919e39f950 Provide a valid enterprise for building redirect path for Stripe Connect callback 2017-09-23 14:58:33 +10:00
Rob Harrington
0e14704572 Kill empty space 2017-09-23 14:58:33 +10:00
Rob Harrington
e9d062a8c2 Use nested module/class definitions instead of compact style 2017-09-23 14:58:33 +10:00
Rob Harrington
f3af36deca Disable rubocop Style/PredicateName check against override of Spree method 2017-09-23 14:58:32 +10:00
Rob Harrington
ecb78233d9 Use guard clauses where possible 2017-09-23 14:58:32 +10:00
Rob Harrington
a68ae1fe2d Provide a sensible flash message when CreditCard#destroy action fails 2017-09-23 14:58:32 +10:00
Rob Harrington
28ba05ec6b Fix Lint/UselessAssignment offences for stripe-connect 2017-09-23 14:58:32 +10:00
Rob Harrington
5b675cbaba Make OAuth private methods actually private 2017-09-23 14:58:32 +10:00
Rob Harrington
42dd58426e Auto-correct rubocop offences for stripe-connect 2017-09-23 14:58:32 +10:00
Rob Harrington
c83755f901 Clean up StripeConnect gateway 2017-09-23 14:58:32 +10:00
Rob Harrington
ae2d3d3fd9 Refactoring StripeHelper into service objects 2017-09-23 14:58:32 +10:00
Rob Harrington
e6eb45b453 Name StripeAccountController spec file correctly 2017-09-23 14:58:32 +10:00
Rob Harrington
01ce092ebc Handle Stripe token creation request failure 2017-09-23 14:58:32 +10:00
Rob Harrington
5d77ef52c5 Replace text strings with variables in stripe request spec 2017-09-23 14:58:32 +10:00
Rob Harrington
e8636c0cbf Set dummy Stripe API key for front-end credits cards feature spec 2017-09-23 14:58:32 +10:00
Rob Harrington
f890927423 Implementing the Stripe Connect feature toggle 2017-09-23 14:58:32 +10:00
Rob Harrington
6499d17cb1 Adding feature toggle config variable for Stripe Connect 2017-09-23 14:58:32 +10:00
Rob Harrington
1d1e581c85 Refactoring CreditCardController, rendering card processing errors as json 2017-09-23 14:58:32 +10:00
Rob Harrington
64009a2c9e CheckoutController can render payment gateway error messages as json 2017-09-23 14:58:32 +10:00
Rob Harrington
14f6ea4c01 Adding required Stripe config variables to application.yml.example 2017-09-23 14:58:32 +10:00
Rob Harrington
fdca1f6606 Adding message about having no saved cards to account/cards UI 2017-09-23 14:58:32 +10:00
Rob Harrington
63a15ec392 CreditCardController#destroy redirects to account#/cards 2017-09-23 14:58:32 +10:00
Rob Harrington
356dad73ba Ensure spec has Stripe.api_key set 2017-09-23 14:58:32 +10:00
Rob Harrington
fb5784fbda Allow updating of account settings from account tabs interface 2017-09-23 14:58:32 +10:00
Rob Harrington
4ef97aa418 Showing past orders under the orders tab 2017-09-23 14:58:32 +10:00
Rob Harrington
b9d72ce4cf Refactoring logic for displaying orders on the front-end account page 2017-09-23 14:58:32 +10:00
Rob Harrington
9733bb3a77 Renaming account#history to account#transactions 2017-09-23 14:58:32 +10:00
Rob Harrington
532dc57725 Adding translations for /account tabs 2017-09-23 14:58:32 +10:00
Rob Harrington
f4c3fbf8bc Refactoring credit cards interface, and backend logic 2017-09-23 14:58:32 +10:00
Rob Harrington
778526af2e Rewriting styling for new tabs components 2017-09-23 14:58:32 +10:00
Rob Harrington
1aebee0583 WIP: rebuilding accounts page using tabs infrastructure 2017-09-23 14:58:32 +10:00
Rob Harrington
ed5c650456 Writing a new tabset component for front-end tabs
Modeled on back-end 'panels' infrastructure
2017-09-23 14:58:32 +10:00
Rob Harrington
b8c6da301c Removing unnecessary dependencies from OrdersCtrl 2017-09-23 14:58:32 +10:00
Rob Harrington
269a60b36f Adding request specs for case when using an existing card stored by Stripe for payment 2017-09-23 14:58:32 +10:00
Rob Harrington
25907f97a8 Cleaning up Stripe Connect request spec 2017-09-23 14:58:32 +10:00
Rob Harrington
d1779b9457 Keep timestamps as :null => false in schema 2017-09-23 14:58:32 +10:00
stveep
ddac179f9b Add translations 2017-09-23 14:58:31 +10:00
stveep
25f48d944c Add delete links, tidy up UI a bit (WIP), page refresh after adding still doesn't work 2017-09-23 14:58:31 +10:00
stveep
c9c4680ef6 Backend code to create Stripe customers and store their IDs in CreditCards. Page refresh not working 2017-09-23 14:58:31 +10:00
stveep
1449169b16 Basic UI for adding credit card details and getting a Stripe token without making a payment 2017-09-23 14:58:31 +10:00
stveep
c6e50a3f7f Stub Stripe requests in feature spec 2017-09-23 14:58:31 +10:00
stveep
56295e5ffb Fix request and feature specs 2017-09-23 14:58:31 +10:00
Rob Harrington
33a3db8698 Making :source attr_accessible for Spree::Payment 2017-09-23 14:58:31 +10:00
stveep
c4f9a5a234 Add code to CheckoutController to construct card attributes when using an existing card (via a818fbbecd/core/app/models/spree/order/checkout.rb:212) 2017-09-23 14:58:31 +10:00
stveep
627899bbd4 spec for source attributes to pass for saved card 2017-09-23 14:58:31 +10:00
stveep
12f4f2d17a Add some logic to check whether a saved card has been selected before making a request from Stripe 2017-09-23 14:58:31 +10:00
stveep
300dc3084c Add default card, disable inputs when a card is selected 2017-09-23 14:58:31 +10:00
stveep
50c3d1367d Tidy up comment 2017-09-23 14:58:31 +10:00
stveep
a1cad82564 Only show credit cards if previously saved, split credit card db migrations and tidy up serializer 2017-09-23 14:58:31 +10:00
stveep
298fd057f5 Check for current user before injecting credit cards 2017-09-23 14:58:31 +10:00
stveep
33b570b117 Inject cards for current user into checkout and add selector dropdown to gateway partial. 2017-09-23 14:58:31 +10:00
stveep
3b05b76b80 Bring in ability to store CreditCards against Users from Spree 2.3 (spree commit d470b31798f3). 2017-09-23 14:58:31 +10:00
Rob Harrington
c97a140471 WIP: Storing Stripe card details for later use
NOTE: No interface for actually selecting a stored card to use yet
2017-09-23 14:58:31 +10:00
Rob Harrington
7c831c9844 Adding StripeJS to checkout page
Allow tokens to be request and passed through as payment source_attributes
2017-09-23 14:57:02 +10:00
Rob Harrington
5c16fefe41 Creating basic angular StripeJS wrapper service for requesting tokens 2017-09-23 14:57:02 +10:00
Rob Harrington
5ad88f992c Adding live stripe account status display to payment method create/edit interface 2017-09-23 14:57:02 +10:00
Rob Harrington
f87f4310f0 Adding #status controller action for stripe accounts to fetch current info direct from Stripe 2017-09-23 14:57:02 +10:00
Rob Harrington
987ad0df6c Very basic Stripe Connect payment method interface 2017-09-23 14:57:02 +10:00
Rob Harrington
d500c20d3f Adding new StripeConnect payment gateway 2017-09-23 14:57:02 +10:00
Rob Harrington
99a7665edc Requesting read_write permission when authorizing Stripe standalone account 2017-09-23 14:57:02 +10:00
Rob Harrington
37f60bf7a1 Setting Stripe.api_key in an initializer rather than helper 2017-09-23 14:57:02 +10:00
Rob Harrington
b5a6bcdf9d Opening up restriction on activemerchant version by updating Spree ref
Allows use of v > 1.57 which includes support for Stripe Connect
2017-09-23 14:57:02 +10:00
stveep
858852123d Add configuration example 2017-09-23 14:57:02 +10:00
stveep
ae72ebef5e Fix disconnect button formatting 2017-09-23 14:57:02 +10:00
stveep
1450bfd726 Don't retrieve event from Stripe for a deauthorisation 2017-09-23 14:57:02 +10:00
stveep
22e4a50807 Change Stripe webhook handling to post request 2017-09-23 14:57:02 +10:00
stveep
a039286240 Webhook processing changes: fix expected request data formatting 2017-09-23 14:57:02 +10:00
stveep
9ac638f8ba Fix some leftover refactoring from an earlier modification to enterprises controller (now not needed as moved to admin/enterprises) 2017-09-23 14:57:02 +10:00
stveep
da335703b4 Fix specs for travis 2017-09-23 14:57:02 +10:00
stveep
d374ab569d Undo dodgy redirect changes and set spec to pending 2017-09-23 14:57:02 +10:00
stveep
47df2dc20b Tweaking redirects and links 2017-09-23 14:57:02 +10:00
stveep
5c43c75b00 Specify SHA-256 algorithm for JWT in spec fixture 2017-09-23 14:57:02 +10:00
stveep
f83c7a88df Specify SHA-256 algorithm for JWT 2017-09-23 14:57:02 +10:00
stveep
5ae473e07f Add specs, fix redirect after requring relogin 2017-09-23 14:57:02 +10:00
stveep
e69b27a3c4 Tidy up (temp) UI a bit 2017-09-23 14:57:02 +10:00
stveep
e52e04ba29 Adding Stripe Connect information so we don't forget it later 2017-09-23 14:57:02 +10:00
stveep
1dcffa790d Add JWT encoding to state param 2017-09-23 14:57:02 +10:00
stveep
f22278db51 Don't disconnect if the same Stripe account is connected to multiple Enterprises 2017-09-23 14:57:02 +10:00
stveep
0280e04008 Move OAuth2 patching to an initializer 2017-09-23 14:57:02 +10:00
Steve Pettitt
41607c5846 De-associate accounts in response to webhook (not tested with a real deauth request yet) 2017-09-23 14:57:02 +10:00
Steve Pettitt
1c69f2c670 Stripe Helper specs 2017-09-23 14:57:02 +10:00
Steve Pettitt
05a69ff0c6 Worklow to disconnect Stripe from OFN admin interface 2017-09-23 14:57:02 +10:00
Steve Pettitt
758f57a889 Remove CSRF check - doesn't work properly as implemented, but connect request should probably be changed to POST 2017-09-23 14:57:02 +10:00
Steve Pettitt
eed11faa62 Monkey patching OAuth2 gem to include Stripe disconnection method 2017-09-23 14:57:02 +10:00
Steve Pettitt
7fd8c5956d Check CSRF, allow a Stripe account to be connected to more than one enterprise (but not vice versa) 2017-09-23 14:57:02 +10:00
Steve Pettitt
8ed983cf03 Correct spelling :) 2017-09-23 14:57:02 +10:00
Steve Pettitt
b6292e2723 Add some logic to check for a connected Stripe Account in form 2017-09-23 14:57:02 +10:00
Steve Pettitt
8bdf57d0d9 Add Stripe Connect button (CSS) in admin/enterprises/:id/edit#payment_methods 2017-09-23 14:57:02 +10:00
Steve Pettitt
03f590ccc4 Callback creates a new StripeAccount with id and publishable key. 2017-09-23 14:57:02 +10:00
Steve Pettitt
06279848c6 Stripe auth and callback working. Still need to process callback. 2017-09-23 14:57:02 +10:00
Steve Pettitt
3623325cab Add missing files 2017-09-23 14:57:01 +10:00
Steve Pettitt
df18329233 Starting Stripe integration 2017-09-23 14:57:01 +10:00
Steve Pettitt
1db0bbef09 Create table for stripe accounts 2017-09-23 14:57:01 +10:00
Saimon Moore
09aed63cd4 Add todos to remove redundant i18n keys 2017-09-08 13:57:50 +02:00
Saimon Moore
757f886af5 Use proper namespaced translations
... in enterprise registration wizard Type step
2017-09-08 13:35:19 +02:00
Saimon Moore
f73f0d4bf9 Use proper namespaced translations
... in enterprise registration wizard Details step
2017-09-08 12:50:54 +02:00
Saimon Moore
d4f7efd08a Use proper namespaced translations
... in enterprise registration wizard Contact step
2017-09-08 12:49:08 +02:00
Saimon Moore
a1aac7643a Translate Entp registration modal tab titles
- Add proper namespaced translations for Details and Contact tabs
2017-09-08 12:47:53 +02:00
Pau Perez
d3d4628e29 Add doc 2017-09-08 09:51:06 +02:00
Pau Perez
942ab55ddc Disable create profile from signup when submitting
This prevents people re-submitting the form multiple times. Although the
backend validates it, we show an ugly alert message that is hard for
users to understand.
2017-09-07 16:02:06 +02:00
Pau Perez
1b151ee015 Add missing translations in registration wizard 2017-09-01 14:57:16 +02:00
207 changed files with 5779 additions and 742 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.bundle
.rbenv-version
.byebug_history
.swp
*.swo
*.swp

1
.node-version Normal file
View File

@@ -0,0 +1 @@
5.12.0

View File

@@ -143,6 +143,10 @@ Style/WordArray:
Enabled: false
StyleGuide: http://relaxed.ruby.style/#stylewordarray
Style/SymbolArray:
Enabled: false
StyleGuide: https://rubocop.readthedocs.io/en/latest/cops_style/#stylesymbolarray
Lint/AmbiguousRegexpLiteral:
Enabled: false
StyleGuide: http://relaxed.ruby.style/#lintambiguousregexpliteral

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 100`
# on 2017-07-12 10:36:44 +0200 using RuboCop version 0.49.1.
# on 2017-08-25 14:27:48 +1000 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -14,7 +14,7 @@ Bundler/OrderedGems:
Exclude:
- 'Gemfile'
# Offense count: 77
# Offense count: 128
# Cop supports --auto-correct.
Layout/AlignArray:
Exclude:
@@ -59,7 +59,7 @@ Layout/AlignHash:
- 'spec/models/spree/shipping_method_spec.rb'
- 'spec/models/spree/variant_spec.rb'
# Offense count: 42
# Offense count: 43
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
@@ -113,11 +113,12 @@ Layout/CaseIndentation:
- 'app/models/enterprise.rb'
- 'app/models/product_importer.rb'
# Offense count: 2
# Offense count: 3
# Cop supports --auto-correct.
Layout/ClosingParenthesisIndentation:
Exclude:
- 'app/overrides/add_capture_order_shortcut.rb'
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 8
# Cop supports --auto-correct.
@@ -137,7 +138,7 @@ Layout/ElseAlignment:
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'lib/open_food_network/sales_tax_report.rb'
# Offense count: 223
# Offense count: 215
# Cop supports --auto-correct.
Layout/EmptyLines:
Enabled: false
@@ -152,7 +153,7 @@ Layout/EmptyLinesAroundAccessModifier:
- 'spec/helpers/products_helper_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 73
# Offense count: 70
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, no_empty_lines
@@ -170,7 +171,6 @@ Layout/EmptyLinesAroundBlockBody:
- 'app/models/spree/calculator_decorator.rb'
- 'app/models/spree/money_decorator.rb'
- 'app/models/spree/option_value_decorator.rb'
- 'app/models/spree/payment_decorator.rb'
- 'lib/open_food_network/group_buy_report.rb'
- 'lib/spree/money_decorator.rb'
- 'lib/tasks/dev.rake'
@@ -188,10 +188,10 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/features/admin/orders_spec.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/features/admin/variant_overrides_spec.rb'
- 'spec/features/consumer/shopping/embedded_shopfronts_spec.rb'
- 'spec/features/consumer/shopping/shopping_spec.rb'
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
- 'spec/helpers/admin/business_model_configuration_helper_spec.rb'
- 'spec/helpers/injection_helper_spec.rb'
- 'spec/helpers/shared_helper_spec.rb'
- 'spec/helpers/shop_helper_spec.rb'
- 'spec/helpers/spree/orders_helper_spec.rb'
@@ -212,8 +212,7 @@ Layout/EmptyLinesAroundBlockBody:
- 'spec/models/tag_rule/filter_shipping_methods_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/serializers/order_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/serializers/variant_serializer_spec.rb'
- 'spec/support/matchers/delegate_matchers.rb'
- 'spec/support/matchers/select2_matchers.rb'
- 'spec/support/matchers/table_matchers.rb'
@@ -270,7 +269,7 @@ Layout/EmptyLinesAroundMethodBody:
- 'app/serializers/api/product_serializer.rb'
- 'lib/open_food_network/orders_and_fulfillments_report.rb'
# Offense count: 13
# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
@@ -278,7 +277,6 @@ Layout/EmptyLinesAroundModuleBody:
Exclude:
- 'app/helpers/add_to_cart_helper.rb'
- 'app/helpers/groups_helper.rb'
- 'app/helpers/injection_helper.rb'
- 'app/helpers/spree/admin/base_helper_decorator.rb'
- 'lib/open_food_network/column_preference_defaults.rb'
- 'lib/open_food_network/group_buy_report.rb'
@@ -289,7 +287,7 @@ Layout/EmptyLinesAroundModuleBody:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/ui_component_helper.rb'
# Offense count: 54
# Offense count: 55
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Layout/ExtraSpacing:
@@ -326,29 +324,28 @@ Layout/ExtraSpacing:
- 'spec/models/enterprise_spec.rb'
- 'spec/models/order_cycle_spec.rb'
- 'spec/models/spree/adjustment_spec.rb'
- 'spec/models/spree/gateway/stripe_connect_spec.rb'
- 'spec/models/spree/order_spec.rb'
- 'spec/models/variant_override_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 1
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: consistent, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
Layout/FirstParameterIndentation:
Exclude:
- 'lib/open_food_network/permissions.rb'
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 6
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# Configuration parameters: SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/IndentArray:
Exclude:
- 'lib/open_food_network/users_and_enterprises_report.rb'
- 'spec/features/admin/reports_spec.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
EnforcedStyle: consistent
# Offense count: 2
# Cop supports --auto-correct.
@@ -403,7 +400,7 @@ Layout/IndentationConsistency:
- 'spec/models/spree/line_item_spec.rb'
- 'spec/models/spree/product_spec.rb'
# Offense count: 20
# Offense count: 18
# Cop supports --auto-correct.
# Configuration parameters: Width, IgnoredPatterns.
Layout/IndentationWidth:
@@ -411,13 +408,11 @@ Layout/IndentationWidth:
- 'app/controllers/admin/invoice_settings_controller.rb'
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/api/order_cycles_controller.rb'
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/models/spree/line_item_decorator.rb'
- 'app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb'
- 'app/serializers/api/admin/for_order_cycle/supplied_product_serializer.rb'
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'lib/discourse/single_sign_on.rb'
- 'lib/open_food_network/last_used_address.rb'
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
- 'spec/helpers/admin/business_model_configuration_helper_spec.rb'
- 'spec/helpers/groups_helper_spec.rb'
@@ -525,7 +520,15 @@ Layout/MultilineMethodCallBraceLayout:
- 'lib/open_food_network/products_renderer.rb'
- 'spec/lib/open_food_network/products_and_inventory_report_spec.rb'
# Offense count: 34
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
Exclude:
- 'spec/serializers/variant_serializer_spec.rb'
# Offense count: 33
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented
@@ -538,7 +541,6 @@ Layout/MultilineOperationIndentation:
- 'app/models/producer_property.rb'
- 'app/models/product_importer.rb'
- 'app/models/spree/ability_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/product_set.rb'
- 'app/models/variant_override_set.rb'
- 'lib/open_food_network/accounts_and_billing_settings_validator.rb'
@@ -558,20 +560,18 @@ Layout/SpaceAfterColon:
- 'spec/models/variant_override_spec.rb'
- 'spec/spec_helper.rb'
# Offense count: 58
# Offense count: 53
# Cop supports --auto-correct.
Layout/SpaceAfterComma:
Exclude:
- 'app/controllers/admin/order_cycles_controller.rb'
- 'app/controllers/spree/admin/products_controller_decorator.rb'
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/controllers/spree/orders_controller_decorator.rb'
- 'app/models/column_preference.rb'
- 'app/models/product_importer.rb'
- 'lib/discourse/single_sign_on.rb'
- 'lib/open_food_network/accounts_and_billing_settings_validator.rb'
- 'lib/open_food_network/business_model_configuration_validator.rb'
- 'lib/open_food_network/order_and_distributor_report.rb'
- 'lib/open_food_network/order_cycle_form_applicator.rb'
- 'lib/open_food_network/users_and_enterprises_report.rb'
- 'spec/controllers/admin/enterprises_controller_spec.rb'
@@ -648,7 +648,7 @@ Layout/SpaceAroundEqualsInParameterDefault:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 58
# Offense count: 60
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Layout/SpaceAroundOperators:
@@ -677,6 +677,7 @@ Layout/SpaceAroundOperators:
- 'spec/helpers/order_cycles_helper_spec.rb'
- 'spec/jobs/update_billable_periods_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/lib/stripe/account_connector_spec.rb'
- 'spec/models/calculator/weight_spec.rb'
- 'spec/support/cancan_helper.rb'
- 'spec/support/seeds.rb'
@@ -715,7 +716,7 @@ Layout/SpaceInLambdaLiteral:
- 'app/models/spree/product_decorator.rb'
- 'app/models/spree/variant_decorator.rb'
# Offense count: 194
# Offense count: 187
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
@@ -765,11 +766,9 @@ Layout/SpaceInsideBlockBraces:
- 'spec/models/spree/order_spec.rb'
- 'spec/models/spree/payment_spec.rb'
- 'spec/models/spree/product_spec.rb'
- 'spec/models/spree/user_spec.rb'
- 'spec/models/tag_rule/discount_order_spec.rb'
- 'spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb'
- 'spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/spec_helper.rb'
- 'spec/support/cancan_helper.rb'
@@ -796,7 +795,7 @@ Layout/SpaceInsideBrackets:
- 'spec/lib/open_food_network/users_and_enterprises_report_spec.rb'
- 'spec/performance/orders_controller_spec.rb'
# Offense count: 729
# Offense count: 766
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces.
# SupportedStyles: space, no_space, compact
@@ -823,12 +822,11 @@ Layout/Tab:
- 'spec/lib/spree/product_filters_spec.rb'
- 'spec/models/spree/line_item_spec.rb'
# Offense count: 32
# Offense count: 42
# Cop supports --auto-correct.
Layout/TrailingWhitespace:
Exclude:
- 'app/models/distributor_shipping_method.rb'
- 'app/models/product_importer.rb'
- 'app/models/spree/money_decorator.rb'
- 'app/serializers/api/image_serializer.rb'
- 'app/serializers/api/shipping_method_serializer.rb'
@@ -836,7 +834,6 @@ Layout/TrailingWhitespace:
- 'app/views/json/_enterprises.rabl'
- 'app/views/json/_producer.rabl'
- 'app/views/json/partials/_producer.rabl'
- 'lib/open_food_network/group_buy_report.rb'
- 'lib/tasks/dev.rake'
- 'spec/controllers/spree/store_controller_spec.rb'
- 'spec/features/admin/enterprise_user_spec.rb'
@@ -844,17 +841,16 @@ Layout/TrailingWhitespace:
- 'spec/lib/open_food_network/option_value_namer_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/serializers/admin/enterprise_serializer_spec.rb'
- 'spec/serializers/variant_serializer_spec.rb'
- 'spec/support/request/menu_helper.rb'
- 'spec/views/json/producers.json.rabl_spec.rb'
# Offense count: 8
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleAlignWith, SupportedStylesAlignWith.
# SupportedStylesAlignWith: either, start_of_block, start_of_line
Lint/BlockAlignment:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'lib/open_food_network/last_used_address.rb'
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
- 'spec/models/enterprise_spec.rb'
- 'spec/models/spree/calculator/flat_percent_item_total_spec.rb'
@@ -1011,7 +1007,7 @@ Lint/UselessAccessModifier:
- 'lib/open_food_network/reports/bulk_coop_report.rb'
- 'spec/lib/open_food_network/reports/report_spec.rb'
# Offense count: 340
# Offense count: 341
Lint/Void:
Exclude:
- 'app/serializers/api/enterprise_serializer.rb'
@@ -1080,7 +1076,7 @@ Lint/Void:
- 'spec/serializers/enterprise_serializer_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 706
# Offense count: 747
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 711
@@ -1165,7 +1161,7 @@ Rails/Delegate:
- 'app/serializers/api/admin/tag_rule_serializer.rb'
- 'app/serializers/api/variant_serializer.rb'
# Offense count: 6
# Offense count: 7
Rails/FilePath:
Exclude:
- 'lib/tasks/karma.rake'
@@ -1203,7 +1199,7 @@ Rails/HasAndBelongsToMany:
- 'app/models/spree/line_item_decorator.rb'
- 'app/models/spree/payment_method_decorator.rb'
# Offense count: 11
# Offense count: 10
Rails/OutputSafety:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
@@ -1211,7 +1207,6 @@ Rails/OutputSafety:
- 'app/helpers/spree/reports_helper.rb'
- 'app/serializers/api/product_serializer.rb'
- 'lib/spree/money_decorator.rb'
- 'lib/tasks/karma.rake'
# Offense count: 6
# Cop supports --auto-correct.
@@ -1302,15 +1297,16 @@ Rails/Validation:
- 'app/models/spree/variant_decorator.rb'
- 'app/models/variant_override.rb'
# Offense count: 6
# Offense count: 7
Style/AccessorMethodName:
Exclude:
- 'app/models/product_importer.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'spec/support/request/shop_workflow.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 35
# Offense count: 34
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals
@@ -1326,7 +1322,6 @@ Style/AndOr:
- 'app/models/product_importer.rb'
- 'app/models/spreadsheet_entry.rb'
- 'app/models/spree/adjustment_decorator.rb'
- 'app/models/spree/order_decorator.rb'
- 'app/models/spree/product_set.rb'
- 'app/views/json/partials/_enterprise.rabl'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
@@ -1340,7 +1335,7 @@ Style/BarePercentLiterals:
- 'spec/features/admin/variants_spec.rb'
- 'spec/support/request/web_helper.rb'
# Offense count: 209
# Offense count: 208
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
@@ -1410,7 +1405,6 @@ Style/BracesAroundHashParameters:
- 'spec/models/spree/product_spec.rb'
- 'spec/models/spree/taxon_spec.rb'
- 'spec/serializers/admin/customer_serializer_spec.rb'
- 'spec/serializers/orders_by_distributor_serializer_spec.rb'
- 'spec/spec_helper.rb'
- 'spec/support/cancan_helper.rb'
- 'spec/support/request/authentication_workflow.rb'
@@ -1422,7 +1416,7 @@ Style/CaseEquality:
- 'app/helpers/angular_form_helper.rb'
- 'spec/models/spree/payment_spec.rb'
# Offense count: 86
# Offense count: 88
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
@@ -1468,7 +1462,9 @@ Style/ClassAndModuleChildren:
- 'app/serializers/api/admin/line_item_serializer.rb'
- 'app/serializers/api/admin/order_cycle_serializer.rb'
- 'app/serializers/api/admin/order_serializer.rb'
- 'app/serializers/api/admin/payment_method_serializer.rb'
- 'app/serializers/api/admin/payment_method/base_serializer.rb'
- 'app/serializers/api/admin/payment_method/payment_method_serializer.rb'
- 'app/serializers/api/admin/payment_method/stripe_serializer.rb'
- 'app/serializers/api/admin/product_serializer.rb'
- 'app/serializers/api/admin/shipping_method_serializer.rb'
- 'app/serializers/api/admin/tag_rule_serializer.rb'
@@ -1601,7 +1597,7 @@ Style/FileName:
Style/FormatStringToken:
EnforcedStyle: template
# Offense count: 88
# Offense count: 89
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Exclude:
@@ -1655,7 +1651,7 @@ Style/GuardClause:
- 'spec/support/request/distribution_helper.rb'
- 'spec/support/request/shop_workflow.rb'
# Offense count: 1241
# Offense count: 1255
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
@@ -1685,11 +1681,10 @@ Style/InverseMethods:
- 'app/controllers/admin/column_preferences_controller.rb'
- 'spec/support/cancan_helper.rb'
# Offense count: 9
# Offense count: 5
# Cop supports --auto-correct.
Style/LineEndConcatenation:
Exclude:
- 'app/controllers/spree/admin/base_controller_decorator.rb'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
- 'spec/controllers/spree/admin/base_controller_spec.rb'
@@ -1736,11 +1731,10 @@ Style/MultilineIfModifier:
- 'lib/open_food_network/enterprise_issue_validator.rb'
- 'lib/spree/core/controller_helpers/respond_with_decorator.rb'
# Offense count: 8
# Offense count: 7
# Cop supports --auto-correct.
Style/MutableConstant:
Exclude:
- 'app/controllers/spree/admin/reports_controller_decorator.rb'
- 'app/models/enterprise.rb'
- 'app/models/enterprise_fee.rb'
- 'app/models/spree/payment_method_decorator.rb'
@@ -1798,7 +1792,7 @@ Style/NumericLiteralPrefix:
Exclude:
- 'spec/features/admin/order_cycles_spec.rb'
# Offense count: 16
# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: Strict.
Style/NumericLiterals:
@@ -2025,7 +2019,7 @@ Style/StructInheritance:
Exclude:
- 'lib/open_food_network/enterprise_fee_applicator.rb'
# Offense count: 182
# Offense count: 183
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinSize, SupportedStyles.
# SupportedStyles: percent, brackets
@@ -2069,7 +2063,7 @@ Style/SymbolArray:
- 'spec/models/exchange_spec.rb'
- 'spec/models/spree/ability_spec.rb'
# Offense count: 97
# Offense count: 96
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
@@ -2101,7 +2095,6 @@ Style/SymbolProc:
- 'spec/features/admin/order_cycles_spec.rb'
- 'spec/lib/open_food_network/group_buy_report_spec.rb'
- 'spec/lib/open_food_network/order_grouper_spec.rb'
- 'spec/models/spree/user_spec.rb'
# Offense count: 6
# Cop supports --auto-correct.

10
Gemfile
View File

@@ -10,7 +10,7 @@ gem 'i18n-js', '~> 3.0.0'
gem 'nokogiri', '>= 1.6.7.1'
gem 'pg'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6-adjustment-state-migration', ref: '48febb2'
gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '5a76d45'
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
gem 'spree_auth_devise', github: 'openfoodfoundation/spree_auth_devise', branch: 'spree-upgrade-intermediate'
@@ -19,6 +19,11 @@ gem 'spree_auth_devise', github: 'openfoodfoundation/spree_auth_devise', branch:
# - Change type of password from string to password to hide it in the form
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "spree-upgrade-intermediate"
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
gem 'stripe', '~> 3.3.1'
gem 'activemerchant', '~> 1.71.0'
gem 'oauth2', '~> 1.2.0' # Used for Stripe Connect
gem 'jwt', '~> 1.5'
gem 'delayed_job_active_record'
gem 'daemons'
@@ -121,7 +126,8 @@ group :test do
end
group :development do
gem 'pry-byebug'
gem 'byebug', '~> 9.0.0' # 9.1 requires ruby 2.2
gem 'pry-byebug', '>= 3.4.3'
gem 'debugger-linecache'
gem 'guard'
gem 'guard-livereload'

View File

@@ -30,9 +30,9 @@ GIT
GIT
remote: git://github.com/openfoodfoundation/spree.git
revision: 48febb250a3b1eb2d42812b27b93457e89cde589
ref: 48febb2
branch: step-6-adjustment-state-migration
revision: 5a76d456ff70aea7aae3d25156558d71eb7febf2
ref: 5a76d45
branch: step-6a
specs:
spree (1.3.99)
spree_api (= 1.3.99)
@@ -57,7 +57,7 @@ GIT
spree_cmd (1.3.99)
thor (>= 0.14.6)
spree_core (1.3.99)
activemerchant (~> 1.50.0)
activemerchant (~> 1.50)
acts_as_list (= 0.1.9)
awesome_nested_set (= 2.1.5)
aws-sdk (~> 1.11.1)
@@ -151,8 +151,8 @@ GEM
sprockets (~> 2.2.1)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activemerchant (1.50.0)
activesupport (>= 3.2.14, < 5.0.0)
activemerchant (1.71.0)
activesupport (>= 3.2.14, < 6.x)
builder (>= 2.1.2, < 4.0.0)
i18n (>= 0.6.9)
nokogiri (~> 1.4)
@@ -198,9 +198,7 @@ GEM
blockenspiel (0.4.5)
bugsnag (4.1.0)
builder (3.0.4)
byebug (2.7.0)
columnize (~> 0.3)
debugger-linecache (~> 1.2)
byebug (9.0.6)
cancan (1.6.8)
capybara (2.7.1)
addressable
@@ -217,7 +215,7 @@ GEM
cliver (0.3.2)
cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0)
coderay (1.0.9)
coderay (1.1.2)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
@@ -226,7 +224,6 @@ GEM
execjs
coffee-script-source (1.10.0)
colorize (0.8.1)
columnize (0.9.0)
compass (1.0.3)
chunky_png (~> 1.2)
compass-core (~> 1.0.2)
@@ -283,6 +280,8 @@ GEM
factory_girl_rails (3.3.0)
factory_girl (~> 3.3.0)
railties (>= 3.0.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
ffaker (1.15.0)
ffi (1.9.3)
figaro (0.7.0)
@@ -450,6 +449,7 @@ GEM
json_spec (1.1.1)
multi_json (~> 1.0)
rspec (~> 2.0)
jwt (1.5.4)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
@@ -471,7 +471,7 @@ GEM
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
method_source (0.8.2)
method_source (0.9.0)
mime-types (1.25.1)
mini_portile2 (2.1.0)
momentjs-rails (2.5.1)
@@ -480,9 +480,16 @@ GEM
i18n (~> 0.6.0)
multi_json (1.12.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
newrelic_rpm (3.12.0.288)
nokogiri (1.6.8.1)
mini_portile2 (~> 2.1.0)
oauth2 (1.2.0)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
oj (2.1.2)
orm_adapter (0.5.0)
paper_trail (3.0.8)
@@ -513,13 +520,12 @@ GEM
activerecord (~> 3.0)
polyglot (0.3.5)
powerpack (0.1.1)
pry (0.9.12.2)
coderay (~> 1.0.5)
method_source (~> 0.8)
slop (~> 3.4)
pry-byebug (1.3.2)
byebug (~> 2.7)
pry (~> 0.9.12)
pry (0.11.1)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.4.3)
byebug (>= 9.0, < 9.1)
pry (~> 0.10)
rabl (0.7.2)
activesupport (>= 2.3.14)
multi_json (~> 1.0)
@@ -619,7 +625,6 @@ GEM
thor (~> 0.14)
shoulda-matchers (1.1.0)
activesupport (>= 3.0.0)
slop (3.4.5)
spinjs-rails (1.3)
rails (>= 3.1)
sprockets (2.2.3)
@@ -629,6 +634,8 @@ GEM
tilt (~> 1.1, != 1.3.0)
state_machine (1.2.0)
stringex (1.3.3)
stripe (3.3.1)
faraday (~> 0.9)
therubyracer (0.12.0)
libv8 (~> 3.16.14.0)
ref
@@ -684,6 +691,7 @@ PLATFORMS
DEPENDENCIES
active_model_serializers
activemerchant (~> 1.71.0)
acts-as-taggable-on (~> 3.4)
andand
angular-rails-templates (~> 0.2.0)
@@ -694,6 +702,7 @@ DEPENDENCIES
aws-sdk
blockenspiel
bugsnag
byebug (~> 9.0.0)
capybara
coffee-rails (~> 3.2.1)
compass-rails
@@ -728,11 +737,13 @@ DEPENDENCIES
jquery-migrate-rails
jquery-rails
json_spec
jwt (~> 1.5)
knapsack
letter_opener
momentjs-rails
newrelic_rpm
nokogiri (>= 1.6.7.1)
oauth2 (~> 1.2.0)
ofn-qz!
oj
paper_trail (~> 3.0.8)
@@ -740,7 +751,7 @@ DEPENDENCIES
parallel_tests
pg
poltergeist
pry-byebug
pry-byebug (>= 3.4.3)
rabl
rack-livereload
rack-ssl
@@ -762,6 +773,7 @@ DEPENDENCIES
spree_auth_devise!
spree_i18n!
spree_paypal_express!
stripe (~> 3.3.1)
therubyracer
timecop
truncate_html

View File

@@ -72,18 +72,22 @@ createuser -s -P ofn
```
Create the development and test databases, using the settings specified in `config/database.yml`, and populate them with a schema and seed data:
rake db:setup
```
bundle exec rake db:setup
```
Load some default data for your environment:
rake openfoodnetwork:dev:load_sample_data
```
bundle exec rake openfoodnetwork:dev:load_sample_data
```
At long last, your dreams of spinning up a development server can be realised:
rails server
```
bundle exec rails server
```
To login as Spree default user, use:
```
email: spree@example.com
password: spree123
```
### Testing
Tests, both unit and integration, are based on RSpec. To run the test suite, first prepare the test database:
@@ -123,7 +127,7 @@ Do not forget to run `rake tmp:cache:clear` after locales are updated to reload
* Maikel Linke (https://github.com/mkllnk)
* Lynne Davis (https://github.com/lin-d-hop)
* Paul Mackay (https://github.com/pmackay)
* Steve Petitt (https://github.com/stveep)
* Steve Pettitt (https://github.com/stveep)
## Licence

View File

@@ -22,7 +22,7 @@ angular.module("admin.enterprises")
{ name: 'users', label: t('users'), icon_class: "icon-user" }
]
$scope.select(0)
SideMenu.init()
$scope.showItem = (item) ->
if item.show?

View File

@@ -0,0 +1,18 @@
angular.module("admin.paymentMethods").controller "StripeController", ($scope, $http, shops) ->
$scope.shops = shops
$scope.stripe_account = {}
$scope.$watch "paymentMethod.preferred_enterprise_id", (newID, oldID) ->
return unless newID?
$scope.stripe_account = {}
$http.get("/admin/stripe_accounts/status.json?enterprise_id=#{newID}").success (data) ->
angular.extend($scope.stripe_account, data)
.error (response) ->
$scope.stripe_account.status = "request_failed"
$scope.current_enterprise_stripe_path = ->
return unless $scope.paymentMethod.preferred_enterprise_id?
permalink = shops.filter((shop) ->
shop.id == $scope.paymentMethod.preferred_enterprise_id
)[0].permalink
"/admin/enterprises/#{permalink}/edit#/payment_methods"

View File

@@ -0,0 +1,33 @@
// Override of Spree's logic in the file of the same name
// Changes made as per https://github.com/spree/spree/commit/8a3a80b08abf80fbed2fcee4b429ba1caf68baf1
// which allows the form partial in admin/payments/new to be switched using radio buttons
// We can remove this file when we reach 2.3.0
$(document).ready(function() {
if ($("#new_payment").is("*")) {
$('.payment_methods_radios').click(
function() {
$('.payment-methods').hide();
if (this.checked) {
$('#payment_method_' + this.value).show();
}
}
);
$('.payment_methods_radios').each(
function() {
if (this.checked) {
$('#payment_method_' + this.value).show();
} else {
$('#payment_method_' + this.value).hide();
}
}
);
$(".card_new").radioControlsVisibilityOfElement('.card_form');
$('select.jump_menu').change(function(){
window.location = this.options[this.selectedIndex].value;
});
}
});

View File

@@ -12,11 +12,10 @@ angular.module("admin.products").factory "VariantUnitManager", ->
@variantUnitOptions: ->
options = for unit_type, scale_with_name of @unitNames
unit_type_cap = unit_type[0].toUpperCase() + unit_type[1..-1]
for scale in @unitScales(unit_type)
name = @getUnitName(scale, unit_type)
["#{unit_type_cap} (#{name})", "#{unit_type}_#{scale}"]
options.push [['Items', 'items']]
["#{I18n.t(unit_type)} (#{name})", "#{unit_type}_#{scale}"]
options.push [[I18n.t('items'), 'items']]
[].concat options...
@getScale: (value, unitType) ->

View File

@@ -1,9 +1,21 @@
angular.module("admin.side_menu")
.factory "SideMenu", ->
.factory "SideMenu", ($location) ->
new class SideMenu
items: []
selected: null
# Checks for path and uses it to set the view
# If no path, loads first view
init: =>
path = $location.path()?.match(/^\/\w+$/)?[0]
index = if path
name = path[1..]
@items.indexOf(@find_by_name(name))
else
0
@select(index)
setItems: (items) =>
@items = items
item.visible = true for item in @items
@@ -13,6 +25,7 @@ angular.module("admin.side_menu")
@selected.selected = false if @selected
@selected = @items[index]
@selected.selected = true
$location.path(@selected.name)
find_by_name: (name) =>
for item in @items when item.name is name

View File

@@ -1,4 +1,4 @@
angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout, $filter) ->
angular.module("admin.utils").directive "ofnSelect2", ($sanitize, $timeout, $filter) ->
require: 'ngModel'
restrict: 'C'
scope:

View File

@@ -22,6 +22,6 @@ Darkswarm.controller "CheckoutCtrl", ($scope, localStorageService, Checkout, Cur
event.preventDefault()
$scope.submitted = true
if form.$valid
$scope.Checkout.submit()
$scope.Checkout.purchase()
else
$scope.$broadcast 'purchaseFormInvalid', form

View File

@@ -1,23 +1,11 @@
Darkswarm.controller "PaymentCtrl", ($scope, $timeout) ->
Darkswarm.controller "PaymentCtrl", ($scope, $timeout, savedCreditCards, Dates) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.savedCreditCards = savedCreditCards
$scope.name = "payment"
$scope.months = Dates.months
$scope.years = Dates.years
$scope.months = [
{key: t("january"), value: "1"},
{key: t("february"), value: "2"},
{key: t("march"), value: "3"},
{key: t("april"), value: "4"},
{key: t("may"), value: "5"},
{key: t("june"), value: "6"},
{key: t("july"), value: "7"},
{key: t("august"), value: "8"},
{key: t("september"), value: "9"},
{key: t("october"), value: "10"},
{key: t("november"), value: "11"},
{key: t("december"), value: "12"},
]
$scope.years = [moment().year()..(moment().year()+15)]
$scope.secrets.card_month = "1"
$scope.secrets.card_year = moment().year()

View File

@@ -0,0 +1,12 @@
Darkswarm.controller "CreditCardsCtrl", ($scope, $timeout, CreditCard, CreditCards, Dates) ->
angular.extend(this, new FieldsetMixin($scope))
$scope.savedCreditCards = CreditCards.saved
$scope.CreditCard = CreditCard
$scope.secrets = CreditCard.secrets
$scope.showForm = CreditCard.show
$scope.storeCard = ->
if $scope.new_card_form.$valid
CreditCard.requestToken()
$scope.allow_name_change = true
$scope.disable_fields = false

View File

@@ -1,9 +0,0 @@
Darkswarm.controller "DistributorNodeCtrl", ($scope, HashNavigation, $anchorScroll) ->
$scope.toggle = ->
HashNavigation.toggle $scope.distributor.hash
$scope.open = ->
HashNavigation.active($scope.distributor.hash)
if $scope.open()
$anchorScroll()

View File

@@ -1,2 +1,2 @@
Darkswarm.controller "OrdersCtrl", ($scope, $rootScope, $timeout, Orders, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) ->
Darkswarm.controller "OrdersCtrl", ($scope, Orders) ->
$scope.Orders = Orders

View File

@@ -1,15 +1,23 @@
Darkswarm.controller "RegistrationFormCtrl", ($scope, RegistrationService, EnterpriseRegistrationService) ->
$scope.submitted = false
$scope.isDisabled = false
$scope.valid = (form) ->
$scope.submitted = !form.$valid
form.$valid
$scope.create = (form) ->
EnterpriseRegistrationService.create() if $scope.valid(form)
$scope.disableButton()
EnterpriseRegistrationService.create($scope.enableButton) if $scope.valid(form)
$scope.update = (nextStep, form) ->
EnterpriseRegistrationService.update(nextStep) if $scope.valid(form)
$scope.selectIfValid = (nextStep, form) ->
RegistrationService.select(nextStep) if $scope.valid(form)
$scope.disableButton = ->
$scope.isDisabled = true
$scope.enableButton = ->
$scope.isDisabled = false

View File

@@ -0,0 +1,9 @@
Darkswarm.controller "ShopNodeCtrl", ($scope, HashNavigation, $anchorScroll) ->
$scope.toggle = ->
HashNavigation.toggle $scope.shop.hash
$scope.open = ->
HashNavigation.active($scope.shop.hash)
if $scope.open()
$anchorScroll()

View File

@@ -0,0 +1,35 @@
Darkswarm.directive "stripeElements", ($injector, StripeElements) ->
restrict: 'E'
template: "<label for='card-element'>\
<div id='card-element'></div>\
<div id='card-errors' class='error'></div>\
</label>"
link: (scope, elem, attr)->
if $injector.has('stripeObject')
stripe = $injector.get('stripeObject')
card = stripe.elements().create 'card',
hidePostalCode: false
style:
base:
fontFamily: "Roboto, Arial, sans-serif"
fontSize: '16px'
color: '#5c5c5c'
'::placeholder':
color: '#6c6c6c'
card.mount('#card-element')
# Elements validates user input as it is typed. To help your customers
# catch mistakes, you should listen to change events on the card Element
# and display any errors:
card.addEventListener 'change', (event) ->
displayError = document.getElementById('card-errors')
if event.error
displayError.textContent = event.error.message
else
displayError.textContent = ''
return
StripeElements.stripe = stripe
StripeElements.card = card

View File

@@ -0,0 +1,12 @@
Darkswarm.directive "tab", ->
restrict: "C"
require: "^^tabsetCtrl"
scope:
name: "@"
link: (scope, element, attrs, ctrl) ->
element.on "click", ->
scope.$apply ->
ctrl.toggle(scope.name)
ctrl.registerSelectionListener (prefix, selection) ->
element.toggleClass('selected', selection == scope.name)

View File

@@ -0,0 +1,15 @@
Darkswarm.directive "tabView", ->
restrict: "C"
require: "^^tabsetCtrl"
template: "<div ng-include='template'></div>"
scope:
templates: "="
link: (scope, element, attrs, ctrl) ->
scope.template = null
ctrl.registerSelectionListener (prefix, selection) ->
if selection?
selection = "#{prefix}/#{selection}" if prefix?
scope.template = "#{selection}.html"
else
scope.template = null

View File

@@ -0,0 +1,28 @@
Darkswarm.directive "tabsetCtrl", (Tabsets, $location) ->
restrict: "C"
scope:
id: "@"
selected: "@"
navigate: "="
prefix: "@?"
controller: ($scope, $element) ->
if $scope.navigate
path = $location.path()?.match(/^\/\w+$/)?[0]
$scope.selected = path[1..] if path
this.toggle = (name) ->
Tabsets.toggle($scope.id, name)
this.select = (selection) ->
$scope.$broadcast("selection:changed", selection)
$element.toggleClass("expanded", selection?)
$location.path(selection) if $scope.navigate
this.registerSelectionListener = (callback) ->
$scope.$on "selection:changed", (event, selection) ->
callback($scope.prefix, selection)
this
link: (scope, element, attrs, ctrl) ->
Tabsets.register(ctrl, scope.id, scope.selected)

View File

@@ -3,13 +3,12 @@ Darkswarm.filter "localizeCurrency", (currencyConfig)->
(amount) ->
# Set country code (eg. "US").
currency_code = if currencyConfig.display_currency then " " + currencyConfig.currency else ""
# Set decimal points, 2 or 0 if hide_cents.
# Set decimal points, 2 or 0 if hide_cents.
decimals = if currencyConfig.hide_cents == "true" then 0 else 2
# We need to use parseFloat before toFixed as the amount should come in as a string.
amount_fixed = parseFloat(amount).toFixed(decimals)
# Set format if the currency symbol should come after the number, otherwise (default) use the locale setting.
format = if currencyConfig.symbol_position == "after" then "%n %u" else undefined
# We need to use parseFloat as the amount should come in as a string.
amount = parseFloat(amount)
# Build the final price string. TODO use spree decimal point and spacer character settings.
if currencyConfig.symbol_position == 'before'
currencyConfig.symbol + amount_fixed + currency_code
else
amount_fixed + " " + currencyConfig.symbol + currency_code
# Build the final price string.
I18n.toCurrency(amount, {precision: decimals, unit: currencyConfig.symbol, format: format}) + currency_code

View File

@@ -1,12 +1,18 @@
Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeElements, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
new class Checkout
errors: {}
secrets: {}
order: CurrentOrder.order
submit: ->
purchase: ->
if @paymentMethod()?.method_type == 'stripe' && !@secrets.selected_card
StripeElements.requestToken(@secrets, @submit)
else
@submit()
submit: =>
Loading.message = t 'submitting_order'
$http.put('/checkout', {order: @preprocess()}).success (data, status)=>
$http.put('/checkout.json', {order: @preprocess()}).success (data, status)=>
Navigation.go data.path
.error (response, status)=>
if response.path
@@ -53,6 +59,23 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
last_name: @order.bill_address.lastname
}
if @paymentMethod()?.method_type == 'stripe'
if @secrets.selected_card
angular.extend munged_order, {
existing_card_id: @secrets.selected_card
}
else
angular.extend munged_order.payments_attributes[0], {
source_attributes:
gateway_payment_profile_id: @secrets.token
cc_type: @secrets.cc_type
last_digits: @secrets.card.last4
month: @secrets.card.exp_month
year: @secrets.card.exp_year
first_name: @order.bill_address.firstname
last_name: @order.bill_address.lastname
save_requested_by_customer: @secrets.save_requested_by_customer
}
munged_order
shippingMethod: ->

View File

@@ -0,0 +1,41 @@
Darkswarm.factory 'CreditCard', ($injector, $rootScope, CreditCards, StripeElements, Navigation, $http, RailsFlashLoader, Loading)->
new class CreditCard
visible: false
errors: {}
secrets: {}
requestToken: =>
@setFullName()
StripeElements.requestToken(@secrets, @submit, t("saving_credit_card"))
submit: =>
params = @process_params()
$http.put('/credit_cards/new_from_token', params )
.success (data, status) =>
Loading.clear()
@reset()
CreditCards.add(data)
.error (response, status) =>
if response.path
Navigation.go response.path
else
Loading.clear()
@errors = response.errors
RailsFlashLoader.loadFlash(response.flash)
setFullName: ->
@secrets.name = "#{@secrets.first_name} #{@secrets.last_name}"
process_params: ->
{"exp_month": @secrets.card.exp_month,
"exp_year": @secrets.card.exp_year,
"last4": @secrets.card.last4,
"token": @secrets.token,
"cc_type": @secrets.cc_type}
show: => @visible = true
reset: =>
@visible = false
delete @secrets[k] for k, v of @secrets
delete @errors[k] for k, v of @errors

View File

@@ -0,0 +1,6 @@
Darkswarm.factory 'CreditCards', (savedCreditCards)->
new class CreditCard
saved: savedCreditCards
add: (card) ->
@saved.push card

View File

@@ -0,0 +1,18 @@
Darkswarm.factory "Dates", ->
new class Dates
months: [
{key: t("january"), value: "1"},
{key: t("february"), value: "2"},
{key: t("march"), value: "3"},
{key: t("april"), value: "4"},
{key: t("may"), value: "5"},
{key: t("june"), value: "6"},
{key: t("july"), value: "7"},
{key: t("august"), value: "8"},
{key: t("september"), value: "9"},
{key: t("october"), value: "10"},
{key: t("november"), value: "11"},
{key: t("december"), value: "12"},
]
years: [moment().year()..(moment().year()+15)]

View File

@@ -11,7 +11,11 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
for key, value of enterpriseAttributes
@enterprise[key] = value
create: =>
# Creates the enterprise and redirects to the about step on success.
#
# @param callback [Function] executed at the end of the operation both in
# case of success or failure.
create: (callback) =>
Loading.message = t('creating') + " " + @enterprise.name
$http(
method: "POST"
@@ -33,6 +37,7 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
else
alert(t('failed_to_create_enterprise_unknown'))
)
callback.call() if callback?
update: (step) =>
Loading.message = t('updating') + " " + @enterprise.name

View File

@@ -21,3 +21,6 @@ Darkswarm.factory 'Navigation', ($location, $window) ->
$window.location.href = path
else
$window.location.pathname = path
reload: ->
$window.location.reload()

View File

@@ -1,22 +1,25 @@
Darkswarm.factory 'Orders', (orders_by_distributor, currencyConfig, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)->
Darkswarm.factory 'Orders', (orders, shops, currencyConfig)->
new class Orders
all: orders
changeable: []
shops: shops
shopsByID: {}
currencySymbol = currencyConfig.symbol
constructor: ->
# Populate Orders.orders from json in page.
@orders_by_distributor = orders_by_distributor
@changeable_orders = []
@currency_symbol = currencyConfig.symbol
for shop in @shops
shop.orders = []
shop.balance = 0.0
@shopsByID[shop.id] = shop
for distributor in @orders_by_distributor
@findChangeableOrders(distributor.distributed_orders)
@updateRunningBalance(distributor.distributed_orders)
for order in @all by -1
shop = @shopsByID[order.shop_id]
shop.orders.unshift order
@changeable.unshift(order) if order.changes_allowed
updateRunningBalance: (orders) ->
for order, i in orders
balances = orders.slice(i,orders.length).map (o) -> parseFloat(o.outstanding_balance)
running_balance = balances.reduce (a,b) -> a+b
order.running_balance = running_balance.toFixed(2)
@updateRunningBalance(shop, order)
findChangeableOrders: (orders) ->
for order in orders when order.changes_allowed
@changeable_orders.push(order)
updateRunningBalance: (shop, order) ->
shop.balance += parseFloat(order.outstanding_balance)
order.runningBalance = shop.balance.toFixed(2)

View File

@@ -0,0 +1,47 @@
Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
new class StripeElements
# TODO: add locale here for translations of error messages etc. from Stripe
# These are both set from the StripeElements directive
stripe: null
card: null
# New Stripe Elements method
requestToken: (secrets, submit, loading_message = t("processing_payment")) ->
return unless @stripe? && @card?
Loading.message = loading_message
cardData = @makeCardData(secrets)
@stripe.createToken(@card, cardData).then (response) =>
if(response.error)
Loading.clear()
RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"})
else
secrets.token = response.token.id
secrets.cc_type = @mapCC(response.token.card.brand)
secrets.card = response.token.card
submit()
# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
if ccType == 'MasterCard'
return 'master'
else if ccType == 'Visa'
return 'visa'
else if ccType == 'American Express'
return 'american_express'
else if ccType == 'Discover'
return 'discover'
else if ccType == 'JCB'
return 'jcb'
else if ccType == 'Diners Club'
return 'diners_club'
return
# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
{'name': secrets.name,
'address1': secrets.address1,
'city': secrets.city,
'zipcode': secrets.zipcode}

View File

@@ -0,0 +1,22 @@
Darkswarm.factory 'Tabsets', ->
new class Tabsets
tabsets: []
register: (ctrl, id, selected=null) ->
if ctrl? && id?
@tabsets.push { ctrl: ctrl, id: id, selected: selected }
ctrl.select(selected) if selected?
toggle: (id, name, state=null) ->
tabset = @findTabsetByObject(id)
if tabset.selected == name
@select(tabset, null) unless state == "open"
else
@select(tabset, name) unless state == "closed"
select: (tabset, name) ->
tabset.selected = name
tabset.ctrl.select(name)
findTabsetByObject: (id) ->
(tabset for tabset in @tabsets when tabset.id == id)[0]

View File

@@ -0,0 +1,80 @@
@import "../../darkswarm/mixins";
.alert-box {
position: relative;
display: block;
background-color: #eff5dc;
border: 1px solid #9fc820;
color: #666;
margin-top: 1em;
margin-bottom: 1em;
@include border-radius(3px);
transition: opacity 300ms ease-out;
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
a.close {
position: absolute;
right: 5px;
top: 5px;
font-size: 1.5em;
}
&.ok {
border: 1px solid #9fc820;
background-color: #fbffee;
color: #9fc820;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #a7c44d;
&:hover {
background-color: #9fc820;
}
}
a.close {
color: #9fc820;
}
}
&.error {
border: 1px solid #c82020;
background-color: #f5dcdc;
color: #c82020;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #c85252;
&:hover {
background-color: #c82020;
}
}
a.close {
color: #c82020;
}
}
&.warning {
border: 1px solid #e6912e;
background-color: #fff4e6;
color: #e6912e;
font-weight: bold;
a.button {
padding: 3px 10px;
background-color: #db9350;
&:hover {
background-color: #e6912e;
}
}
a.close {
color: #e6912e;
}
}
}

View File

@@ -24,8 +24,6 @@ light: #ccc
}
}
/*.ui-dialog .ui-icon-closethick{background:url(/static/assets/dialogCloseButton.png);}*/
.ui-dialog .ui-widget-header{
background-image: none;
background-color: #ffffff;
@@ -42,21 +40,18 @@ light: #ccc
.ui-dialog .ui-corner-all{
border-radius: 8px;
}
.ui-dialog {
.ui-state-hover, .ui-state-focus{
border: none;
background: none;
color: #545454;
}
}
.ui-state-hover, .ui-widget-header .ui-state-hover, .ui-widget-content .ui-state-hover {
background-color: #ffffff;
background: none;
}
.ui-dialog-titlebar-close {
.ui-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close {
float: right;
border: none;
background: none;
&:before {
color: #000000;
font-size: 2em;
@@ -76,9 +71,18 @@ light: #ccc
display: none;
}
}
.ui-button-text {
display: none;
}
}
.ui-widget-overlay {
background: #000000;
opacity: 0.5;
position: fixed;
height: 100vh;
width: 100vw;
left: 0px;
top: 0px;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +1,5 @@
@import "../darkswarm/mixins";
.alert-box {
position: relative;
display: block;
background-color: #eff5dc;
border: 1px solid #9fc820;
color: #666;
margin-top: 1em;
margin-bottom: 1em;
@include border-radius(3px);
transition: opacity 300ms ease-out;
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
a.close {
position: absolute;
right: 5px;
top: 0px;
font-size: 1.5em;
}
}
.dashboard_item.single-ent {
.header {
padding: 0.77778em 1.33333em 0.77778em 0.77778em;

View File

@@ -43,6 +43,13 @@ input.red {
margin-right: 5px;
}
a.button.red {
&:not(:hover) {
color: #fff;
background-color: #DA5354;
}
}
input.orange {
background-color: #FF9848;
margin-right: 5px;

View File

@@ -69,4 +69,10 @@ table#listing_products.bulk {
margin-bottom: 0.5em;
}
}
td.left-actions {
a.view-variants, a.add-variant {
cursor: pointer;
}
}
}

View File

@@ -5,9 +5,32 @@
color: #4a4a4a;
}
.credit_cards {
.saved_cards {
table {
width: 100%;
}
}
.saved_cards, .no_cards {
margin-bottom: 1em;
}
.new_card {
opacity: 0;
-webkit-transition: opacity 0.4s linear;
transition: opacity 0.4s linear;
&.visible {
opacity: 1;
}
input.ng-invalid {
margin-bottom: 0px;
}
}
}
.orders {
margin-top: 50px;
margin-bottom: 100px;
a {
@@ -24,6 +47,10 @@
height: auto;
}
&.active_table {
margin: 0px;
}
.active_table_row {
h3 {
margin-top: 0.5em;

View File

@@ -68,7 +68,11 @@
margin-right: 0;
&, & > a.row {
display: block;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
}
}
@@ -96,7 +100,7 @@
&:hover, &:active, &:focus {
// color: $dark-grey
}
}

View File

@@ -81,3 +81,6 @@ checkout
display: inline
span.accordion-down
display: none
.error
color: #c82020

View File

@@ -0,0 +1,16 @@
stripe-elements {
margin-bottom: 15px;
display: block;
#card-element {
background: white;
box-sizing: border-box;
font-weight: 400;
padding: 0.6rem 0.5rem;
border: 1px solid #cccccc;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
border-radius: 0px;
height: 42px;
width: 100%;
}
}

View File

@@ -0,0 +1,71 @@
@import "typography";
@import "mixins";
@import "branding";
.tabset-ctrl {
.tab-view {
padding-top: 30px;
}
.tab {
text-align: center;
@media all and (max-width: 640px) {
text-align: left;
}
a {
@include headingFont;
background: transparent;
text-transform: uppercase;
font-size: 1.5em;
text-shadow: 0 -1px 1px #ffffff;
padding: 1em;
border: none;
@media all and (max-width: 640px) {
padding: 0.35em 0 0.65em 0;
text-shadow: none;
}
}
border-bottom: 4px solid transparent;
&:hover, &:focus, &:active {
transition: all 0.4s ease-in-out;
border-bottom: 4px solid $clr-brick-bright;
cursor: pointer;
@media all and (max-width: 640px) {
transition: none;
color: white;
background-color: $clr-brick-bright;
}
a {
color: $clr-brick-bright;
@media all and (max-width: 640px) {
color: #ffffff;
}
}
}
&.selected {
border-bottom: 4px solid $clr-brick;
@media all and (max-width: 640px) {
background-color: $clr-brick;
}
a {
color: $clr-brick;
@media all and (max-width: 640px) {
color: #ffffff;
}
}
}
}
}

View File

@@ -408,3 +408,12 @@ ul {
display: inline-block;
margin: 0px;
}
/*
* Fix overlapping table header on second page of long invoices.
* Problem description: https://github.com/openfoodfoundation/openfoodnetwork/issues/1738
* Solution: https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1770#issuecomment-73530576
*/
thead { display: table-header-group }
tfoot { display: table-row-group }
tr { page-break-inside: avoid }

View File

@@ -0,0 +1,49 @@
require 'stripe/account_connector'
module Admin
class StripeAccountsController < Spree::Admin::BaseController
def connect
payload = params.slice(:enterprise_id)
key = Openfoodnetwork::Application.config.secret_token
url_params = { state: JWT.encode(payload, key, 'HS256'), scope: "read_write" }
redirect_to Stripe::OAuth.authorize_url(url_params)
end
def destroy
stripe_account = StripeAccount.find(params[:id])
authorize! :destroy, stripe_account
if stripe_account.deauthorize_and_destroy
flash[:success] = "Stripe account disconnected."
else
flash[:error] = "Failed to disconnect Stripe."
end
redirect_to main_app.edit_admin_enterprise_path(stripe_account.enterprise)
rescue ActiveRecord::RecordNotFound
flash[:error] = "Failed to disconnect Stripe."
redirect_to spree.admin_path
end
def status
return render json: { status: :stripe_disabled } unless Spree::Config.stripe_connect_enabled
stripe_account = StripeAccount.find_by_enterprise_id(params[:enterprise_id])
return render json: { status: :account_missing } unless stripe_account
authorize! :status, stripe_account
begin
status = Stripe::Account.retrieve(stripe_account.stripe_user_id)
attrs = %i[id business_name charges_enabled]
render json: status.to_hash.slice(*attrs).merge( status: :connected)
rescue Stripe::APIError
render json: { status: :access_revoked }
end
end
private
def model_class
StripeAccount
end
end
end

View File

@@ -0,0 +1,40 @@
# This controller is used by super admin users to update the settings the app is using
module Admin
class StripeConnectSettingsController < Spree::Admin::BaseController
StripeConnectSettings = Struct.new(:stripe_connect_enabled)
before_filter :load_settings, only: [:edit]
def edit
return @stripe_account = { status: :empty_api_key_error_html } if Stripe.api_key.blank?
attrs = %i[id business_name charges_enabled]
@obfuscated_secret_key = obfuscated_secret_key
@stripe_account = Stripe::Account.retrieve.to_hash.slice(*attrs).merge(status: :ok)
rescue Stripe::AuthenticationError
@stripe_account = { status: :auth_fail_error }
end
def update
Spree::Config.set(params[:settings])
resource = t('admin.controllers.stripe_connect_settings.resource')
flash[:success] = t(:successfully_updated, :resource => resource)
redirect_to_edit
end
private
def load_settings
@settings = StripeConnectSettings.new(Spree::Config[:stripe_connect_enabled])
end
def redirect_to_edit
redirect_to main_app.edit_admin_stripe_connect_settings_path
end
def obfuscated_secret_key
key = Stripe.api_key
key.first(8) + "****" + key.last(4)
end
end
end

View File

@@ -57,7 +57,7 @@ class ApplicationController < ActionController::Base
def enable_embedded_shopfront
whitelist = Spree::Config[:embedded_shopfronts_whitelist]
return unless Spree::Config[:enable_embedded_shopfronts] && whitelist.present?
return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test?
return if request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development?
response.headers.delete 'X-Frame-Options'
response.headers['Content-Security-Policy'] = "frame-ancestors #{whitelist}"

View File

@@ -15,6 +15,10 @@ class CheckoutController < Spree::CheckoutController
include EnterprisesHelper
def edit
# This is only required because of spree_paypal_express. If we implement
# a version of paypal that uses this controller, and more specifically
# the #update_failed method, then we can remove this call
restart_checkout
end
def update
@@ -48,7 +52,7 @@ class CheckoutController < Spree::CheckoutController
format.html do
respond_with(@order, :location => order_path(@order))
end
format.js do
format.json do
render json: {path: order_path(@order)}, status: 200
end
end
@@ -119,6 +123,9 @@ class CheckoutController < Spree::CheckoutController
if (params[:order][:payments_attributes])
params[:order][:payments_attributes].first[:amount] = @order.total
end
if params[:order][:existing_card_id]
construct_saved_card_attributes
end
params[:order]
end
@@ -134,11 +141,12 @@ class CheckoutController < Spree::CheckoutController
def update_failed
clear_ship_address
restart_checkout
respond_to do |format|
format.html do
render :edit
end
format.js do
format.json do
render json: {errors: @order.errors, flash: flash.to_hash}.to_json, status: 400
end
end
@@ -152,6 +160,15 @@ class CheckoutController < Spree::CheckoutController
end
end
def restart_checkout
return if @order.state == 'cart'
@order.restart_checkout! # resets state to 'cart'
@order.update_attributes!(shipping_method_id: nil)
@order.shipments.with_state(:pending).destroy_all
@order.payments.with_state(:checkout).destroy_all
@order.reload
end
def skip_state_validation?
true
end
@@ -202,4 +219,28 @@ class CheckoutController < Spree::CheckoutController
render json: {path: spree.paypal_express_url(payment_method_id: payment_method.id)}, status: 200
true
end
def construct_saved_card_attributes
existing_card_id = params[:order].delete(:existing_card_id)
return if existing_card_id.blank?
credit_card = Spree::CreditCard.find(existing_card_id)
if credit_card.try(:user_id).blank? || credit_card.user_id != spree_current_user.try(:id)
raise Spree::Core::GatewayError, I18n.t(:invalid_credit_card)
end
# Not currently supported but maybe we should add it...?
credit_card.verification_value = params[:cvc_confirm] if params[:cvc_confirm].present?
params[:order][:payments_attributes].first[:source] = credit_card
params[:order][:payments_attributes].first.delete :source_attributes
end
def rescue_from_spree_gateway_error(error)
flash[:error] = t(:spree_gateway_error_flash_for_checkout, error: error.message)
respond_to do |format|
format.html { render :edit }
format.json { render json: { flash: flash.to_hash }, status: 400 }
end
end
end

View File

@@ -15,10 +15,11 @@ class EnterprisesController < BaseController
respond_to :js, only: :permalink_checker
def relatives
set_enterprise
respond_to do |format|
format.json do
enterprise = Enterprise.find(params[:id])
enterprises = enterprise.andand.relatives.andand.activated
enterprises = @enterprise.andand.relatives.andand.activated
render(json: enterprises,
each_serializer: Api::EnterpriseSerializer,
data: OpenFoodNetwork::EnterpriseInjectionData.new)
@@ -40,6 +41,10 @@ class EnterprisesController < BaseController
private
def set_enterprise
@enterprise = Enterprise.find_by_id(params[:id])
end
def clean_permalink
params[:permalink] = params[:permalink].parameterize
end

View File

@@ -6,6 +6,8 @@ class GroupsController < BaseController
end
def show
enable_embedded_shopfront
@hide_menu = true if @shopfront_layout == 'embedded'
@group = EnterpriseGroup.find_by_permalink(params[:id]) || EnterpriseGroup.find(params[:id])
end
end

View File

@@ -1,6 +1,7 @@
module Spree
module Admin
PaymentMethodsController.class_eval do
before_filter :restrict_stripe_account_change, only: [:update]
before_filter :force_environment, only: [:create, :update]
skip_before_filter :load_resource, only: [:show_provider_preferences]
before_filter :load_hubs, only: [:new, :edit, :update]
@@ -57,12 +58,30 @@ module Spree
else
@providers = Gateway.providers.reject{ |p| p.name.include? "Bogus" }.sort{|p1, p2| p1.name <=> p2.name }
end
@providers.reject!{ |p| p.name.ends_with? "StripeConnect" } unless show_stripe?
@calculators = PaymentMethod.calculators.sort_by(&:name)
end
def load_hubs
@hubs = Enterprise.managed_by(spree_current_user).is_distributor.sort_by!{ |d| [(@payment_method.has_distributor? d) ? 0 : 1, d.name] }
end
# Show Stripe as an option if enabled, or if the
# current payment_method is already a Stripe method
def show_stripe?
Spree::Config.stripe_connect_enabled || @payment_method.try(:type) == "Spree::Gateway::StripeConnect"
end
def restrict_stripe_account_change
return unless @payment_method
return unless @payment_method.type == "Spree::Gateway::StripeConnect"
return unless @payment_method.preferred_enterprise_id.andand > 0
@stripe_account_holder = Enterprise.find(@payment_method.preferred_enterprise_id)
return if spree_current_user.enterprises.include? @stripe_account_holder
params[:payment_method][:preferred_enterprise_id] = @stripe_account_holder.id
end
end
end
end

View File

@@ -0,0 +1,69 @@
module Spree
class CreditCardsController < BaseController
def new_from_token
# A new Customer is created for every credit card (same as via ActiveMerchant)
# Note that default_source is the card represented by the token
@customer = create_customer(params[:token])
@credit_card = build_card_from(stored_card_attributes)
if @credit_card.save
render json: @credit_card, serializer: ::Api::CreditCardSerializer, status: :ok
else
message = t(:card_could_not_be_saved)
render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: message) } }, status: 400
end
rescue Stripe::CardError => e
return render json: { flash: { error: I18n.t(:spree_gateway_error_flash_for_checkout, error: e.message) } }, status: 400
end
def destroy
@credit_card = Spree::CreditCard.find_by_id(params[:id])
if @credit_card
authorize! :destroy, @credit_card
destroy_at_stripe
end
# Using try because we may not have a card here
if @credit_card.try(:destroy)
flash[:success] = I18n.t(:card_has_been_removed, number: "x-#{@credit_card.last_digits}")
else
flash[:error] = I18n.t(:card_could_not_be_removed)
end
redirect_to account_path(anchor: 'cards')
rescue Stripe::CardError
flash[:error] = I18n.t(:card_could_not_be_removed)
redirect_to account_path(anchor: 'cards')
end
private
# Currently can only destroy the whole customer object
def destroy_at_stripe
stripe_customer = Stripe::Customer.retrieve(@credit_card.gateway_customer_profile_id)
stripe_customer.delete if stripe_customer
end
def create_customer(token)
Stripe::Customer.create(email: spree_current_user.email, source: token)
end
def stored_card_attributes
return {} unless @customer.try(:default_source)
{
month: params[:exp_month],
year: params[:exp_year],
last_digits: params[:last4],
gateway_payment_profile_id: @customer.default_source,
gateway_customer_profile_id: @customer.id,
cc_type: params[:cc_type]
}
end
def build_card_from(attrs)
card = Spree::CreditCard.new(attrs)
# Can't mass assign user:
card.user_id = spree_current_user.id
card
end
end
end

View File

@@ -2,4 +2,14 @@ Spree::UsersController.class_eval do
layout 'darkswarm'
before_filter :enable_embedded_shopfront
# Override of spree_auth_devise default
# Ignores invoice orders, only order where state: 'complete'
def show
@orders = @user.orders.where(state: 'complete').order('completed_at desc')
return unless Spree::Config.accounts_distributor_id
@orders = @orders.where('distributor_id != ?', Spree::Config.accounts_distributor_id)
end
end

View File

@@ -0,0 +1,21 @@
require 'stripe/account_connector'
module Stripe
class CallbacksController < BaseController
# GET /stripe/callbacks
def index
connector = Stripe::AccountConnector.new(spree_current_user, params)
if connector.create_account
flash[:success] = t('admin.controllers.enterprises.stripe_connect_success')
elsif connector.connection_cancelled_by_user?
flash[:notice] = t('admin.controllers.enterprises.stripe_connect_cancelled')
else
flash[:error] = t('admin.controllers.enterprises.stripe_connect_fail')
end
redirect_to main_app.edit_admin_enterprise_path(connector.enterprise, anchor: 'payment_methods')
rescue Stripe::StripeError => e
render text: e.message, status: 500
end
end
end

View File

@@ -0,0 +1,38 @@
require 'stripe/webhook_handler'
module Stripe
class WebhooksController < BaseController
protect_from_forgery except: :create
before_filter :verify_webhook
# POST /stripe/webhooks
def create
handler = WebhookHandler.new(@event)
result = handler.handle
render nothing: true, status: status_mappings[result] || 200
end
private
def verify_webhook
payload = request.raw_post
signature = request.headers["HTTP_STRIPE_SIGNATURE"]
@event = Webhook.construct_event(payload, signature, Stripe.endpoint_secret)
rescue JSON::ParserError
render nothing: true, status: 400
rescue Stripe::SignatureVerificationError
render nothing: true, status: 401
end
# Stripe interprets a 4xx or 3xx response as a failure to receive the webhook,
# and will stop sending events if too many of either of these are returned.
def status_mappings
{
success: 200, # The event was handled successfully
unknown: 202, # The event was of an unknown type
ignored: 204 # No action was taken in response to the event
}
end
end
end

View File

@@ -20,4 +20,10 @@ module ApplicationHelper
super
end
end
def body_classes
classes = []
classes << "off-canvas" unless @hide_menu
classes << @shopfront_layout
end
end

View File

@@ -1,3 +1,5 @@
require 'open_food_network/available_payment_method_filter'
module EnterprisesHelper
def current_distributor
@current_distributor ||= current_order(false).andand.distributor
@@ -22,6 +24,9 @@ module EnterprisesHelper
return [] unless current_distributor.present?
payment_methods = current_distributor.payment_methods.available(:front_end).all
filter = OpenFoodNetwork::AvailablePaymentMethodFilter.new
filter.filter!(payment_methods)
applicator = OpenFoodNetwork::TagRuleApplicator.new(current_distributor, "FilterPaymentMethods", current_customer.andand.tag_list)
applicator.filter!(payment_methods)

View File

@@ -64,9 +64,21 @@ module InjectionHelper
render partial: "json/injection_ams", locals: {name: 'enterpriseAttributes', json: "#{@enterprise_attributes.to_json}"}
end
def inject_orders_by_distributor
data_array = spree_current_user.orders_by_distributor
inject_json_ams "orders_by_distributor", data_array, Api::OrdersByDistributorSerializer
def inject_orders
inject_json_ams "orders", @orders.all, Api::OrderSerializer
end
def inject_shops
shops = Enterprise.where(id: @orders.pluck(:distributor_id).uniq)
inject_json_ams "shops", shops.all, Api::ShopForOrdersSerializer
end
def inject_saved_credit_cards
if spree_current_user
data = spree_current_user.credit_cards.with_payment_profile.all
end
inject_json_ams "savedCreditCards", data, Api::CreditCardSerializer
end
def inject_json(name, partial, opts = {})
@@ -89,5 +101,4 @@ module InjectionHelper
@enterprise_injection_data ||= OpenFoodNetwork::EnterpriseInjectionData.new
{data: @enterprise_injection_data}
end
end

View File

@@ -42,6 +42,7 @@ class Enterprise < ActiveRecord::Base
has_many :billable_periods
has_many :inventory_items
has_many :tag_rules
has_one :stripe_account, dependent: :destroy
delegate :latitude, :longitude, :city, :state_name, :to => :address
@@ -66,7 +67,6 @@ class Enterprise < ActiveRecord::Base
supports_s3 :logo
supports_s3 :promo_image
validates :name, presence: true
validate :name_is_unique
validates :sells, presence: true, inclusion: {in: SELLS}
@@ -78,7 +78,6 @@ class Enterprise < ActiveRecord::Base
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
validates_length_of :description, :maximum => 255
before_save :confirmation_check, if: lambda { email_changed? }
before_validation :initialize_permalink, if: lambda { permalink.nil? }
@@ -95,7 +94,6 @@ class Enterprise < ActiveRecord::Base
after_rollback :restore_permalink
scope :by_name, order('name')
scope :visible, where(visible: true)
scope :confirmed, where('confirmed_at IS NOT NULL')

View File

@@ -56,9 +56,14 @@ class AbilityDecorator
user == item.order.user &&
item.order.changes_allowed?
end
can [:cancel], Spree::Order do |order|
order.user == user
end
can [:destroy], Spree::CreditCard do |credit_card|
credit_card.user == user
end
end
# New users can create an enterprise, and gain other permissions from doing this.
@@ -118,12 +123,16 @@ class AbilityDecorator
can [:admin, :bulk_update], ColumnPreference do |column_preference|
column_preference.user == user
end
can [:admin, :connect, :status, :destroy], StripeAccount do |stripe_account|
user.enterprises.include? stripe_account.enterprise
end
end
def add_product_management_abilities(user)
# Enterprise User can only access products that they are a supplier for
can [:create], Spree::Product
can [:admin, :read, :update, :product_distributions, :bulk_edit, :bulk_update, :clone, :delete, :destroy], Spree::Product do |product|
can [:admin, :read, :update, :product_distributions, :seo, :group_buy_options, :bulk_edit, :bulk_update, :clone, :delete, :destroy], Spree::Product do |product|
OpenFoodNetwork::Permissions.new(user).managed_product_enterprises.include? product.supplier
end

View File

@@ -39,4 +39,7 @@ Spree::AppConfiguration.class_eval do
# Invoices & Receipts
preference :invoice_style2?, :boolean, default: false
preference :enable_receipt_printing?, :boolean, default: false
# Stripe Connect
preference :stripe_connect_enabled, :boolean, default: false
end

View File

@@ -0,0 +1,28 @@
Spree::CreditCard.class_eval do
# Allows user to submit these attributes with checkout request
# Required to be able to correctly store details for token-based charges
# Obviously can be removed once we are using strong params
attr_accessible :cc_type, :last_digits
# For holding customer preference in memory
attr_accessible :save_requested_by_customer
attr_writer :save_requested_by_customer
# Should be able to remove once we reach Spree v2.2.0
# https://github.com/spree/spree/commit/411010f3975c919ab298cb63962ee492455b415c
belongs_to :payment_method
belongs_to :user
# Allows us to use a gateway_payment_profile_id to store Stripe Tokens
# Should be able to remove once we reach Spree v2.2.0
# Commit: https://github.com/spree/spree/commit/5a4d690ebc64b264bf12904a70187e7a8735ef3f
# See also: https://github.com/spree/spree_gateway/issues/111
def has_payment_profile? # rubocop:disable Style/PredicateName
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
end
def save_requested_by_customer?
!!@save_requested_by_customer
end
end

View File

@@ -0,0 +1,106 @@
require 'stripe/profile_storer'
module Spree
class Gateway
class StripeConnect < Gateway
preference :enterprise_id, :integer
validate :ensure_enterprise_selected
attr_accessible :preferred_enterprise_id
CARD_TYPE_MAPPING = {
'American Express' => 'american_express',
'Diners Club' => 'diners_club',
'Visa' => 'visa'
}.freeze
def method_type
'stripe'
end
def provider_class
ActiveMerchant::Billing::StripeGateway
end
def payment_profiles_supported?
true
end
def stripe_account_id
StripeAccount.find_by_enterprise_id(preferred_enterprise_id).andand.stripe_user_id
end
def purchase(money, creditcard, gateway_options)
provider.purchase(*options_for_purchase_or_auth(money, creditcard, gateway_options))
rescue Stripe::StripeError => e
# This will be an error caused by generating a stripe token
failed_activemerchant_billing_response(e.message)
end
def void(response_code, _creditcard, gateway_options)
gateway_options[:stripe_account] = stripe_account_id
provider.void(response_code, gateway_options)
end
def create_profile(payment)
return unless payment.source.gateway_customer_profile_id.nil?
profile_storer = Stripe::ProfileStorer.new(payment, provider)
profile_storer.create_customer_from_token
end
private
# In this gateway, what we call 'secret_key' is the 'login'
def options
options = super
options.merge(:login => Stripe.api_key)
end
def options_for_purchase_or_auth(money, creditcard, gateway_options)
options = {}
options[:description] = "Spree Order ID: #{gateway_options[:order_id]}"
options[:currency] = gateway_options[:currency]
options[:stripe_account] = stripe_account_id
creditcard = token_from_card_profile_ids(creditcard)
[money, creditcard, options]
end
def update_source!(source)
source.cc_type = CARD_TYPE_MAPPING[source.cc_type] if CARD_TYPE_MAPPING.include?(source.cc_type)
source
end
def token_from_card_profile_ids(creditcard)
token_or_card_id = creditcard.gateway_payment_profile_id
customer = creditcard.gateway_customer_profile_id
return nil if token_or_card_id.blank?
# Assume the gateway_payment_profile_id is a token generated by StripeJS
return token_or_card_id if customer.blank?
# Assume the gateway_payment_profile_id is a Stripe card_id
# So generate a new token, using the customer_id and card_id
tokenize_instance_customer_card(customer, token_or_card_id)
end
def tokenize_instance_customer_card(customer, card)
token = Stripe::Token.create({card: card, customer: customer}, stripe_account: stripe_account_id)
token.id
end
def failed_activemerchant_billing_response(error_message)
ActiveMerchant::Billing::Response.new(false, error_message)
end
def ensure_enterprise_selected
return if preferred_enterprise_id.andand > 0
errors.add(:stripe_account_owner, I18n.t(:error_required))
end
end
end
end

View File

@@ -37,7 +37,8 @@ Spree::Order.class_eval do
end
order.payment_required?
}
go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
# NOTE: :confirm step was removed because we were not actually using it
# go_to_state :confirm, :if => lambda { |order| order.confirmation_required? }
go_to_state :complete
remove_transition :from => :delivery, :to => :confirm
end
@@ -143,6 +144,8 @@ Spree::Order.class_eval do
end
# After changing line items of a completed order
# TODO: perhaps this should be triggered from a controller
# rather than an after_save callback?
def update_shipping_fees!
shipments.each do |shipment|
next if shipment.shipped?
@@ -152,6 +155,8 @@ Spree::Order.class_eval do
end
# After changing line items of a completed order
# TODO: perhaps this should be triggered from a controller
# rather than an after_save callback?
def update_payment_fees!
payments.each do |payment|
next if payment.completed?
@@ -293,6 +298,24 @@ Spree::Order.class_eval do
complete? && distributor.andand.allow_order_changes? && order_cycle.andand.open?
end
# Override of existing Spree method. Can remove when we reach 2-0-stable
# See commit: https://github.com/spree/spree/commit/5fca58f658273451193d5711081d018c317814ed
# Allows GatewayError to show useful error messages in checkout
def process_payments!
pending_payments.each do |payment|
break if payment_total >= total
payment.process!
if payment.completed?
self.payment_total += payment.amount
end
end
rescue Spree::Core::GatewayError => e # This section changed
result = !!Spree::Config[:allow_checkout_on_gateway_error]
errors.add(:base, e.message) and return result
end
private
def shipping_address_from_distributor
@@ -348,6 +371,7 @@ Spree::Order.class_eval do
end
def update_adjustment!(adjustment)
return if adjustment.finalized?
state = adjustment.state
adjustment.state = 'open'
adjustment.update!(self)
@@ -357,11 +381,14 @@ Spree::Order.class_eval do
# object_params sets the payment amount to the order total, but it does this before
# the shipping method is set. This results in the customer not being charged for their
# order's shipping. To fix this, we refresh the payment amount here.
def charge_shipping!
def charge_shipping_and_payment_fees!
update_totals
return unless payments.any?
payments.first.update_attribute :amount, total
end
end
Spree::Order.state_machine.after_transition to: :payment, do: :charge_shipping!
Spree::Order.state_machine.after_transition to: :payment, do: :charge_shipping_and_payment_fees!
Spree::Order.state_machine.event :restart_checkout do
transition :to => :cart, unless: :completed?
end

View File

@@ -0,0 +1,41 @@
module Spree
OrderUpdater.class_eval do
# TODO: This logic adapted from Spree 2.4, remove when we get there
# Handles state updating in a much more logical way than < 2.4
# Specifically, doesn't depend on payments.last to determine payment state
# Also swapped: == 0 for .zero?, .size == 0 for empty? and .size > 0 for !empty?
# See:
# https://github.com/spree/spree/commit/38b8456183d11fc1e00e395e7c9154c76ef65b85
# https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a
def update_payment_state
last_state = order.payment_state
if payments.present? && payments.valid.empty?
order.payment_state = 'failed'
elsif order.state == 'canceled' && order.payment_total.zero?
order.payment_state = 'void'
else
# This part added so that we don't need to override order.outstanding_balance
balance = order.outstanding_balance
balance = -1 * order.payment_total if canceled_and_paid_for?
order.payment_state = 'balance_due' if balance > 0
order.payment_state = 'credit_owed' if balance < 0
order.payment_state = 'paid' if balance.zero?
# Original logic
# order.payment_state = 'balance_due' if order.outstanding_balance > 0
# order.payment_state = 'credit_owed' if order.outstanding_balance < 0
# order.payment_state = 'paid' if !order.outstanding_balance?
end
order.state_changed('payment') if last_state != order.payment_state
order.payment_state
end
private
# Taken from order.outstanding_balance in Spree 2.4
# See: https://github.com/spree/spree/commit/7b264acff7824f5b3dc6651c106631d8f30b147a
def canceled_and_paid_for?
order.canceled? && order.payments.present? && !order.payments.completed.empty?
end
end
end

View File

@@ -4,13 +4,13 @@ module Spree
after_save :ensure_correct_adjustment, :update_order
attr_accessible :source
def ensure_correct_adjustment
# Don't charge for invalid payments.
# PayPalExpress always creates a payment that is invalidated later.
# Unknown: What about failed payments?
if state == "invalid"
adjustment.andand.destroy
elsif adjustment
revoke_adjustment_eligibility if ['failed', 'invalid'].include?(state)
return if adjustment.try(:finalized?)
if adjustment
adjustment.originator = payment_method
adjustment.label = adjustment_label
adjustment.save
@@ -73,6 +73,15 @@ module Spree
end
end
# Import from future Spree v.2.3.0 d470b31798f37
def build_source
return if source_attributes.nil?
return unless payment_method.andand.payment_source_class
self.source = payment_method.payment_source_class.new(source_attributes)
source.payment_method_id = payment_method.id
source.user_id = order.user_id if order
end
private
@@ -80,5 +89,26 @@ module Spree
refund_amount ||= credit_allowed >= order.outstanding_balance.abs ? order.outstanding_balance.abs : credit_allowed.abs
refund_amount.to_f
end
def create_payment_profile
return unless source.is_a?(CreditCard)
return unless source.try(:save_requested_by_customer?)
return unless source.number || source.gateway_payment_profile_id
return unless source.gateway_customer_profile_id.nil?
payment_method.create_profile(self)
rescue ActiveMerchant::ConnectionError => e
gateway_error e
end
# Don't charge fees for invalid or failed payments.
# This is called twice for failed payments, because the persistence of the 'failed'
# state is acheived through some trickery using an after_rollback callback on the
# payment model. See Spree::Payment#persist_invalid
def revoke_adjustment_eligibility
return unless adjustment.try(:reload)
return if adjustment.finalized?
adjustment.update_attribute(:eligible, false)
adjustment.finalize!
end
end
end

View File

@@ -6,6 +6,7 @@ Spree::PaymentMethod.class_eval do
acts_as_taggable
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', :class_name => 'Enterprise', association_foreign_key: 'distributor_id'
has_many :credit_cards, class_name: "Spree::CreditCard" # from Spree v.2.3.0 d470b31798f37
attr_accessible :distributor_ids, :tag_list
@@ -58,6 +59,8 @@ Spree::PaymentMethod.class_eval do
"MasterCard Internet Gateway Service (MIGS)"
when "Spree::Gateway::Pin"
"Pin Payments"
when "Spree::Gateway::StripeConnect"
"Stripe"
when "Spree::Gateway::PayPalExpress"
"PayPal Express"
else

View File

@@ -11,6 +11,7 @@ Spree.user_class.class_eval do
has_many :billable_periods, foreign_key: :owner_id, inverse_of: :owner
has_one :cart
has_many :customers
has_many :credit_cards
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
@@ -53,32 +54,6 @@ Spree.user_class.class_eval do
owned_enterprises(:reload).size < enterprise_limit
end
# Returns Enterprise IDs for distributors that the user has shopped at
def enterprises_ordered_from
enterprise_ids = orders.where(state: :complete).map(&:distributor_id).uniq
# Exclude the accounts distributor
if Spree::Config.accounts_distributor_id
enterprise_ids = enterprise_ids.keep_if { |a| a != Spree::Config.accounts_distributor_id }
end
enterprise_ids
end
# Returns orders and their associated payments for all distributors that have been ordered from
def complete_orders_by_distributor
Enterprise
.includes(distributed_orders: { payments: :payment_method })
.where(enterprises: { id: enterprises_ordered_from },
spree_orders: { state: 'complete', user_id: id })
.order('spree_orders.completed_at DESC')
end
def orders_by_distributor
# Remove uncompleted payments as these will not be reflected in order balance
data_array = complete_orders_by_distributor.to_a
remove_payments_in_checkout(data_array)
data_array.sort! { |a, b| b.distributed_orders.length <=> a.distributed_orders.length }
end
private
def limit_owned_enterprises

View File

@@ -0,0 +1,21 @@
class StripeAccount < ActiveRecord::Base
belongs_to :enterprise
validates :stripe_user_id, :stripe_publishable_key, presence: true
validates :enterprise_id, uniqueness: true
def deauthorize_and_destroy
accounts = StripeAccount.where(stripe_user_id: stripe_user_id)
# Only deauthorize the user if it is not linked to multiple accounts
return destroy if accounts.count > 1
destroy && Stripe::OAuth.deauthorize(stripe_user_id: stripe_user_id)
rescue Stripe::OAuth::OAuthError
Bugsnag.notify(
RuntimeError.new("StripeDeauthorizeFailure"),
stripe_account: stripe_user_id,
enterprise_id: enterprise_id
)
true
end
end

View File

@@ -1,5 +0,0 @@
Deface::Override.new(:virtual_path => "spree/admin/products/_form",
:insert_top => "[data-hook='admin_product_form_right']",
:partial => "spree/admin/products/group_buy_form",
:name => "add_group_buy_to_admin_product_edit",
:original => '0c0e8d714989e48ee246a8253fb2b362f108621a')

View File

@@ -1,6 +1,7 @@
/ replace "div[data-hook='admin_payment_method_form_fields']"
= admin_inject_payment_method
= admin_inject_json_ams_array "admin.paymentMethods", "shops", @hubs, Api::Admin::BasicEnterpriseSerializer
%div.alpha.eleven.columns{ "ng-app" => "admin.paymentMethods", "ng-controller" => "paymentMethodCtrl" }
.row
.alpha.three.columns

View File

@@ -1,6 +0,0 @@
/ insert_bottom "[data-hook='admin_product_form_additional_fields']"
= f.field_container :notes do
= f.label :notes, t(:notes)
= f.text_area :notes, { :class => 'fullwidth', rows: 5 }
= f.error_message_on :notes

View File

@@ -1,3 +1,3 @@
/ insert_top "[data-hook='admin_product_form_right']"
/ insert_after "div[class='variant_units_form']"
= render 'spree/admin/products/primary_taxon_form', f: f

View File

@@ -1,7 +1,6 @@
/ insert_top "[data-hook='admin_product_form_right']"
/ insert_before "code[erb-loud]:contains('f.field_container :price')"
= f.field_container :supplier do
= f.label :supplier, t(:spree_admin_supplier)
%br
= f.collection_select(:supplier_id, @producers, :id, :name, {:include_blank => true}, {:class => "select2"})
= f.error_message_on :supplier
= f.error_message_on :supplier

View File

@@ -0,0 +1,2 @@
remove "code[erb-loud]:contains('f.label :available_on')"
closing_selector("code[erb-loud]:contains('f.text_field :available_on')")

View File

@@ -0,0 +1,2 @@
remove "code[erb-loud]:contains('f.field_container :cost_currency')"
closing_selector("code[erb-silent]:contains('end')")

View File

@@ -0,0 +1,2 @@
remove "code[erb-loud]:contains('f.field_container :cost_price')"
closing_selector("code[erb-silent]:contains('end')")

View File

@@ -0,0 +1 @@
remove "div[data-hook='admin_product_form_meta']"

View File

@@ -0,0 +1 @@
remove "div[class='twelve columns alpha omega']"

View File

@@ -0,0 +1,2 @@
/ replace "[data-hook=admin_product_form_right] code[erb-loud]:contains('f.label :price')"
= f.label :price, raw(t(:price) + content_tag(:span, ' *', :class => 'required'))

View File

@@ -0,0 +1,5 @@
/ insert_bottom "[data-hook=admin_product_form_left]"
= f.field_container :taxons do
= f.label :taxon_ids, t(:taxons)
%br
= f.hidden_field :taxon_ids, :value => @product.taxon_ids.join(',')

View File

@@ -0,0 +1,4 @@
// insert_bottom "[data-hook='admin_configurations_sidebar_menu']"
%li
= link_to t('.stripe_connect'), main_app.edit_admin_stripe_connect_settings_path

View File

@@ -0,0 +1,5 @@
/ insert_bottom "[data-hook='admin_product_tabs']"
- klass = current == 'Group Buy Options' ? 'active' : ''
%li{:class => klass}
= link_to_with_icon 'icon-tasks', 'Group Buy Options', group_buy_options_admin_product_url(@product)

View File

@@ -0,0 +1,5 @@
/ insert_bottom "[data-hook='admin_product_tabs']"
- klass = current == 'SEO' ? 'active' : ''
%li{:class => klass}
= link_to_with_icon 'icon-tasks', 'SEO', seo_admin_product_url(@product)

View File

@@ -1,4 +1,4 @@
class Api::Admin::BasicEnterpriseSerializer < ActiveModel::Serializer
attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids
attributes :producer_profile_only
attributes :producer_profile_only, :permalink
end

View File

@@ -0,0 +1,13 @@
module Api::Admin::PaymentMethod
class BaseSerializer < ActiveModel::Serializer
attributes :id, :name, :type, :tag_list, :tags
def tag_list
object.tag_list.join(",")
end
def tags
object.tag_list.map{ |t| { text: t } }
end
end
end

View File

@@ -0,0 +1,5 @@
module Api::Admin::PaymentMethod
class StripeSerializer < BaseSerializer
attributes :preferred_enterprise_id
end
end

View File

@@ -1,11 +1,15 @@
class Api::Admin::PaymentMethodSerializer < ActiveModel::Serializer
attributes :id, :name, :type, :tag_list, :tags
module Api
module Admin
class PaymentMethodSerializer < ActiveModel::Serializer
delegate :serializable_hash, to: :method_serializer
def tag_list
object.tag_list.join(",")
end
def tags
object.tag_list.map{ |t| { text: t } }
def method_serializer
if object.type == 'Spree::Gateway::StripeConnect'
Api::Admin::PaymentMethod::StripeSerializer.new(object)
else
Api::Admin::PaymentMethod::BaseSerializer.new(object)
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
module Api
class CreditCardSerializer < ActiveModel::Serializer
attributes :id, :brand, :number, :expiry, :formatted, :delete_link
def brand
object.cc_type.capitalize
end
def number
"x-#{object.last_digits}"
end
def expiry
m = object.month.to_i
m = m < 10 ? "0#{m}" : m.to_s
"#{m}/#{object.year}"
end
def formatted
"#{brand} #{number} #{I18n.t(:card_expiry_abbreviation)}:#{expiry}"
end
def delete_link
Spree::Core::Engine.routes.url_helpers.credit_card_path(object.id)
end
end
end

View File

@@ -1,13 +1,18 @@
module Api
class OrderSerializer < ActiveModel::Serializer
attributes :number, :completed_at, :total, :state, :shipment_state, :payment_state
attributes :outstanding_balance, :payments, :path, :cancel_path, :changes_allowed, :changes_allowed_until
attributes :shop_name, :item_count
attributes :outstanding_balance, :payments, :path, :cancel_path
attributes :changes_allowed, :changes_allowed_until, :item_count
attributes :shop_id
has_many :payments, serializer: Api::PaymentSerializer
def shop_name
object.distributor.andand.name
def payments
object.payments.joins(:payment_method).completed
end
def shop_id
object.distributor_id
end
def item_count
@@ -23,10 +28,6 @@ module Api
I18n.l(object.order_cycle.andand.orders_close_at, format: "%b %d, %Y %H:%M")
end
def total
object.total.to_money.to_s
end
def shipment_state
object.shipment_state ? object.shipment_state : nil
end

View File

@@ -4,7 +4,7 @@ module Api
has_many :distributed_orders, serializer: Api::OrderSerializer
def balance
object.distributed_orders.map(&:outstanding_balance).reduce(:+).to_money.to_s
object.distributed_orders.map(&:outstanding_balance).reduce(:+)
end
def hash

View File

@@ -2,15 +2,11 @@ module Api
class PaymentSerializer < ActiveModel::Serializer
attributes :amount, :updated_at, :payment_method, :state
def payment_method
object.payment_method.name
end
def amount
object.amount.to_money.to_s
object.payment_method.try(:name)
end
def updated_at
I18n.l(object.updated_at, format: :long)
I18n.l(object.updated_at, format: "%b %d, %Y %H:%M")
end
end
end

View File

@@ -0,0 +1,13 @@
module Api
class ShopForOrdersSerializer < ActiveModel::Serializer
attributes :id, :name, :hash, :logo
def hash
object.to_param
end
def logo
object.logo(:small) if object.logo?
end
end
end

View File

@@ -4,7 +4,7 @@
= form_for [main_app, :admin, @enterprise], html: { name: "enterprise_form",
"ng-controller" => 'enterpriseCtrl',
'onchange' => 'angular.element(enterprise_form).scope().setFormDirty()',
} do |f|
"ng-cloak" => true } do |f|
%save-bar{ dirty: "enterprise_form.$dirty", persist: "true" }
%input.red{ type: "button", value: t(:update), ng: { click: "submit()", disabled: "!enterprise_form.$dirty" } }

View File

@@ -1,3 +1,6 @@
- if Spree::Config.stripe_connect_enabled || @enterprise.stripe_account
= render 'admin/enterprises/form/stripe_connect'
- if @payment_methods.count > 0
%table
%thead

View File

@@ -0,0 +1,15 @@
= render 'admin/enterprises/form/stripe_connect/confirm_modal'
- if @stripe_account = @enterprise.stripe_account
.stripe-info
.row
= t('.stripe_account_connected')
.row
=link_to t('.disconnect'), main_app.admin_stripe_account_path(@stripe_account), method: :delete, class: 'button'
- else
.row.stripe-info
.six.columns.alpha
=t('.stripe_connect_intro')
.five.columns.omega.text-right
%a.stripe-connect.help-modal{ template: 'admin/modals/stripe_connect_confirm.html' }
%span= t('.connect_with_stripe')

View File

@@ -0,0 +1,27 @@
%script{ type: "text/ng-template", id: "admin/modals/stripe_connect_confirm.html" }
-# Recommended info to impart (from Stripe Connect docs):
-# indicate to the user what youre responsible for and what theyll be expected to do. Its particularly important to communicate:
-# That theyll need to create and maintain their Stripe account.
-# That theyll need to handle chargebacks and all customer service issues.
-# Who is responsible for paying the Stripe fees.
-# What, if any, fees the platform charges.
#stripe-connect-confirm
.margin-bottom-30.text-center
.text-big
= t('.title')
.margin-bottom-30
%p= t('.part1')
.margin-bottom-30
%p= t('.part2')
.margin-bottom-30
%p= t('.part3')
.text-center
%a.button.icon-ok{ href: main_app.connect_admin_stripe_accounts_path(enterprise_id: @enterprise) }
= t('.i_agree')
%a.button.red.icon-remove{ href: 'javascript:void(0)', ng: { click: 'close()' } }
= t('.cancel')

View File

@@ -0,0 +1,51 @@
= render :partial => 'spree/admin/shared/configuration_menu'
- content_for :page_title do
= t('.title')
%fieldset.no-border-bottom
%legend
= t('.settings')
= form_for @settings, as: :settings, url: main_app.admin_stripe_connect_settings_path, :method => :put do |f|
.row
.twelve.columns.alpha.omega
.field
- disabled = !@settings.stripe_connect_enabled && @stripe_account[:status] != :ok
= f.label :stripe_connect_enabled, t('.stripe_connect_enabled')
= f.check_box :stripe_connect_enabled, disabled: disabled
.row
.twelve.columns.alpha.omega.form-buttons{"data-hook" => "buttons"}
= button t(:update), 'icon-refresh', value: "update"
%fieldset.no-border-bottom
%legend= t('.status')
%strong= t('.configuration_explanation_html')
- if @stripe_account[:status] == :ok
.alert-box.ok
.status
%strong= t(".status") + ":"
= t(".ok")
%i.icon-ok
.business_name
%strong= t(".business_name") + ":"
= @stripe_account[:business_name]
.charges_enabled
%strong
- enabled_text = t(@stripe_account[:charges_enabled] ? :say_yes : :say_no)
= t(".charges_enabled") + ":"
= enabled_text
.account_id
%strong= t(".account_id") + ":"
= @stripe_account[:id]
.secret_key
%strong= t('.instance_secret_key') + ":"
= @obfuscated_secret_key
.publishable_key
%strong= t('.instance_publishable_key') + ":"
= Stripe.publishable_key
- if !@stripe_account[:charges_enabled]
.alert-box.warning
= t(".charges_enabled_warning")
- else
.alert-box.error
= t(".#{@stripe_account[:status]}")

Some files were not shown because too many files have changed in this diff Show More