Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/components/payments/account-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Ember from 'ember';

const {
Component
} = Ember;

export default Component.extend({
classNames: ['account-setup'],

// set by binding
email: null,

// Preset values for testing
fundsRecipient: {
recipientType: 'company',
firstName: 'John',
lastName: 'Doe',

businessType: 'sole_prop',
businessName: 'Managed LLC',
businessEin: '1234-managed',

dob: '06-12-1986',

dobDay: '06',
dobMonth: '12',
dobYear: '1986',

address1: 'Some street 22',
address2: 'PO 23',
city: 'Los Angeles',
state: 'CA',
country: 'US',
zip: '10000',
ssnLast4: '1234'
}
});
9 changes: 9 additions & 0 deletions app/components/payments/bank-account.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Ember from 'ember';

const {
Component
} = Ember;

export default Component.extend({
classNames: ['bank-account']
});
9 changes: 9 additions & 0 deletions app/components/payments/contact-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Ember from 'ember';

const {
Component
} = Ember;

export default Component.extend({
classNames: ['contact-info']
});
45 changes: 45 additions & 0 deletions app/components/payments/funds-recipient.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Ember from 'ember';

const {
Component, get, set
} = Ember;

export default Component.extend({
tagName: 'form',
classNames: ['funds-recipient'],

init() {
this.setProperties(get(this, 'fundsRecipient'));
this._super(...arguments);
},

actions: {
setBusinessType(value) {
set(this, 'businessType', value);
},

setDob(value) {
let dobDay = value.getDay() + 1;
let dobMonth = value.getMonth() + 1;
let dobYear = value.getFullYear();

this.setProperties({ dobDay, dobMonth, dobYear });
},

setRecipientType(value) {
set(this, 'recipientType', value);
},

submit() {
let fundsRecipient = this.getProperties(
'recipientType',
'businessType', 'businessName', 'businessEin',
'firstName', 'lastName', 'ssnLast4',
'dobDay', 'dobMonth', 'dobYear',
'address1', 'address2', 'city', 'state', 'country', 'zip'
);

this.sendAction('recipientInformationSubmitted', fundsRecipient);
}
}
});
27 changes: 27 additions & 0 deletions app/controllers/project/settings/donations/payments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Ember from 'ember';
const {
computed: { alias },
Controller,
get,
inject: { service },
merge
} = Ember;

export default Controller.extend({
currentUser: service(),
store: service(),

user: alias('currentUser.user'),

actions: {
onRecipientInformationSubmitted(organization, email, recipientInformation) {
let accountParams = merge(recipientInformation, { organization, email });
get(this, 'store').createRecord('stripe-connect-account', accountParams)
.save();
},

onBankAccountInformationSubmitted(/* bankAccountInformation */) {
// TODO: Handle receiving bank account information
}
}
});
30 changes: 25 additions & 5 deletions app/models/stripe-connect-account.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,38 @@ import attr from 'ember-data/attr';
import { belongsTo } from 'ember-data/relationships';

export default Model.extend({
email: attr(),

recipientType: attr(),

firstName: attr(),
lastName: attr(),

dobDay: attr(),
dobMonth: attr(),
dobYear: attr(),

address1: attr(),
address2: attr(),
city: attr(),
country: attr(),
state: attr(),
zip: attr(),

ssnLast4: attr(),

businessEin: attr(),
businessName: attr(),
businessUrl: attr(),
businessType: attr(),

canAcceptDonations: attr(),
chargesEnabled: attr(),

displayName: attr(),
email: attr(),
idFromStripe: attr(),

insertedAt: attr(),
updatedAt: attr(),

// Virtual attribute; write-only
accessCode: attr(),

organization: belongsTo('organization', { async: true })
});
5 changes: 4 additions & 1 deletion app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ AppRouter.map(function() {
this.route('project', { path: '/:slugged_route_slug/:project_slug' }, function() {
this.route('settings', function() {
this.route('contributors');
this.route('donations');
this.route('donations', function() {
this.route('goals');
this.route('payments');
});
this.route('profile');
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import Ember from 'ember';
import { CanMixin } from 'ember-can';

const {
get,
Route,
RSVP
Route
} = Ember;

/**
Expand Down Expand Up @@ -41,38 +39,31 @@ export default Route.extend(CanMixin, {
/**
* An Ember.Route hook
*
* Returns a promise hash, meaning hooks that follow the model hook will wait until
* all promises in the hash resolve
* Returns a promise, meaning hooks that follow the model hook will wait until
* it resolves
*
* @return {RSVP.hash} A promise hash consisting of a project, once resolved
* @return {RSVP.Promise} A promise for reloading the project route model
*/
model() {
let project = this.modelFor('project');
// need to try and fetch an existing account
return get(project, 'organization.stripeConnectAccount').then((stripeConnectAccount) => {
if (stripeConnectAccount) {
return RSVP.hash({ project, stripeConnectAccount });
}
});
return this.modelFor('project');
},

/**
* An Ember.Route hook
*
* Assigns the project and stripeConnectAccount models as
* controller properties.
* Assingns the project property as model
*
* If the project has no donation goals, initializes a new record.
*
* @method setupController
* @param {Ember.Controller} controller
* @param {DS.Model} modelHash.project The currently loaded project
* @param {DS.Model} project The currently loaded project
*/
setupController(controller, { project, stripeConnectAccount = null }) {
setupController(controller, project) {
if (project.get('donationGoals.length') == 0) {
controller.send('addDonationGoal', project);
}

controller.setProperties({ project, stripeConnectAccount });
controller.setProperties({ project });
}
});
60 changes: 60 additions & 0 deletions app/routes/project/settings/donations/payments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Ember from 'ember';
import { CanMixin } from 'ember-can';

const {
Route
} = Ember;

/**
* `project.settings.donations.payments`
*
* Route used by organization owners to manage
* stripe account information
*
* @module Route
* @extends Ember.Route
*/
export default Route.extend(CanMixin, {
/**
* An Ember.Route hook
*
* Managing account information is for owners only, unlike managing
* organizations generally, which is also allowed for admins.
*
* The hook ensures the user is able to manage organization goals.
*
* @method beforeModel
*/
beforeModel() {
if (this.cannot('manage donation goals in project')) {
return this.transitionTo('project');
} else {
return this._super(...arguments);
}
},

/**
* An Ember.Route hook
*
* Returns a promise, meaning hooks that follow the model hook will wait until
* it resolves
*
* @return {RSVP.Promise} A promise for reloading the project route model
*/
model() {
return this.modelFor('project').reload();
},

/**
* An Ember.Route hook
*
* Assingns the project property as model
*
* @method setupController
* @param {Ember.Controller} controller
* @param {DS.Model} project The currently loaded project
*/
setupController(controller, project) {
controller.setProperties({ project });
}
});
18 changes: 18 additions & 0 deletions app/templates/components/payments/account-setup.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<h3>Create a Stripe account for {{organizationName}}</h3>

{{!
TODO:
Account setup should decide if it should render the "form"
for each section, or just a generic "section-done" component.

Possibly, even, the payments controller should decide and then
pass in flags to the account setup, but that might be overkill.
}}
{{payments/contact-info email=email}}

{{payments/funds-recipient
fundsRecipient=fundsRecipient
recipientInformationSubmitted=(action onRecipientInformationSubmitted email)}}

{{payments/bank-account
bankAccountInformationSubmitted=(action onBankAccountInformationSubmitted)}}
12 changes: 12 additions & 0 deletions app/templates/components/payments/bank-account.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="input-group">
<label for="routing-number">Routing Number</label>
{{input type="text" name="routing-number" value=routingNumber}}
</div>
<div class="input-group">
<label for="account-number">Account Number</label>
{{input type="text" name="account-number" value=accountNumber}}
</div>

<button {{action (action bankAccountInformationSubmitted (hash accountNumber=accountNumber routingNumber=routingNumber))}}>
Submit
</button>
4 changes: 4 additions & 0 deletions app/templates/components/payments/contact-info.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="input-group">
<label for="email">Email</label>
{{input type="email" name="email" value=email}}
</div>
Loading