Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use parent collective slug in manual donation instructions #1571

Merged
merged 4 commits into from
Dec 6, 2018
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
18 changes: 11 additions & 7 deletions server/graphql/v1/mutations/orders.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import moment from 'moment';
import uuidv4 from 'uuid/v4';
import debug from 'debug';
import debugLib from 'debug';
import md5 from 'md5';
import Promise from 'bluebird';
import { pick, omit, get } from 'lodash';
Expand All @@ -22,7 +22,7 @@ import { executeOrder } from '../../../lib/payments';

const oneHourInSeconds = 60 * 60;

const debugOrder = debug('order');
const debug = debugLib('orders');

function checkOrdersLimit(order, remoteUser, reqIp) {
if (['circleci', 'test'].includes(process.env.NODE_ENV)) {
Expand Down Expand Up @@ -70,11 +70,11 @@ function checkOrdersLimit(order, remoteUser, reqIp) {

for (const limit of limits) {
const count = cache.get(limit.key) || 0;
debugOrder(`${count} orders for limit '${limit.key}'`);
debug(`${count} orders for limit '${limit.key}'`);
const limitReached = count >= limit.value;
cache.set(limit.key, count + 1, oneHourInSeconds);
if (limitReached) {
debugOrder(`Order limit reached for limit '${limit.key}'`);
debug(`Order limit reached for limit '${limit.key}'`);
const errorMessage =
'Error while processing your request, please try again or contact support@opencollective.com';
// Show a developer-friendly message in DEV
Expand Down Expand Up @@ -111,7 +111,7 @@ async function checkRecaptcha(order, remoteUser, reqIp) {
}

export async function createOrder(order, loaders, remoteUser, reqIp) {
debugOrder('Beginning creation of order', order);
debug('Beginning creation of order', order);
checkOrdersLimit(order, remoteUser, reqIp);
const recaptchaResponse = await checkRecaptcha(order, remoteUser, reqIp);
try {
Expand Down Expand Up @@ -165,6 +165,7 @@ export async function createOrder(order, loaders, remoteUser, reqIp) {
}

const paymentRequired = (order.totalAmount > 0 || (tier && tier.amount > 0)) && collective.isActive;
debug('paymentRequired', paymentRequired, 'total amount:', order.totalAmount, 'isActive', collective.isActive);
if (
paymentRequired &&
(!order.paymentMethod ||
Expand Down Expand Up @@ -282,8 +283,11 @@ export async function createOrder(order, loaders, remoteUser, reqIp) {
if (order.interval) {
defaultDescription = `${capitalize(order.interval)}ly donation to ${collective.name}${tierNameInfo}`;
} else {
defaultDescription = `${totalAmount > 0 ? 'Donation' : 'Registration'} to ${collective.name}${tierNameInfo}`;
defaultDescription = `${totalAmount === 0 || collective.type === types.EVENT ? 'Registration' : 'Donation'} to ${
collective.name
}${tierNameInfo}`;
}
debug('defaultDescription', defaultDescription, 'collective.type', collective.type);

const orderData = {
CreatedByUserId: remoteUser ? remoteUser.id : user.id,
Expand Down Expand Up @@ -366,7 +370,7 @@ export async function createOrder(order, loaders, remoteUser, reqIp) {

return order;
} catch (error) {
debugOrder('createOrder mutation error: ', error);
debug('createOrder mutation error: ', error);
if (orderCreated && !orderCreated.processedAt) {
// TODO: Order should be updated with data JSON field to store the error to review later
orderCreated.update({ status: status.ERROR });
Expand Down
7 changes: 6 additions & 1 deletion server/lib/payments.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import * as libsubscription from './subscriptions';
import * as libtransactions from './transactions';
import { getRecommendedCollectives } from './data';
import { formatCurrency } from '../lib/utils';
import debugLib from 'debug';
const debug = debugLib('payments');

/** Check if paymentMethod has a given fully qualified name
*
Expand Down Expand Up @@ -225,6 +227,7 @@ export async function associateTransactionRefundId(transaction, refund, data) {
}

export const sendEmailNotifications = (order, transaction) => {
debug('sendEmailNotifications');
// for gift cards and manual payment methods
if (!transaction) {
sendOrderProcessingEmail(order);
Expand Down Expand Up @@ -316,6 +319,7 @@ export const executeOrder = async (user, order, options) => {
if (order.processedAt) {
return Promise.reject(new Error(`This order (#${order.id}) has already been processed at ${order.processedAt}`));
}
debug('executeOrder', user.email, order.description, order.totalAmount, options);

const payment = {
amount: order.totalAmount,
Expand Down Expand Up @@ -444,6 +448,7 @@ const sendOrderProcessingEmail = async order => {
const { collective, fromCollective } = order;
const user = order.createdByUser;
const host = await collective.getHostCollective();
const parentCollective = await collective.getParentCollective();
const data = {
order: order.info,
user: user.info,
Expand All @@ -457,7 +462,7 @@ const sendOrderProcessingEmail = async order => {
const formatValues = {
orderid: order.id,
amount: formatCurrency(order.totalAmount, order.currency),
collective: order.collective.slug,
collective: parentCollective ? `${parentCollective.slug} event` : order.collective.slug,
tier: get(order, 'tier.slug') || get(order, 'tier.name'),
};
data.instructions = instructions.replace(/{([\s\S]+?)}/g, (match, p1) => {
Expand Down
3 changes: 2 additions & 1 deletion server/models/Order.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { TransactionTypes } from '../constants/transactions';
import Promise from 'bluebird';
import CustomDataTypes from './DataTypes';
import Temporal from 'sequelize-temporal';
import { get } from 'lodash';

import debugLib from 'debug';
const debug = debugLib('order');
Expand Down Expand Up @@ -161,8 +162,8 @@ export default function(Sequelize, DataTypes) {

info() {
return {
type: TransactionTypes.CREDIT,
id: this.id,
type: get(this, 'collective.type') === 'EVENT' ? 'registration' : 'donation',
CreatedByUserId: this.CreatedByUserId,
TierId: this.TierId,
FromCollectiveId: this.FromCollectiveId,
Expand Down
2 changes: 1 addition & 1 deletion templates/emails/order.processing.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Subject: {{#if instructions}}ACTION REQUIRED:{{/if}} your {{{currency order.totalAmount
currency=order.currency}}} donation to {{collective.name}} is pending
currency=order.currency}}} {{order.type}} to {{collective.name}} is pending

{{> header}}

Expand Down
23 changes: 19 additions & 4 deletions test/graphql.createOrder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ describe('createOrder', () => {
const host = await models.Collective.create({
slug: 'host',
name: 'Open Collective 501c3',
currency: 'USD',
settings: {
paymentMethods: {
manual: {
Expand All @@ -197,26 +198,38 @@ describe('createOrder', () => {
const collective = await models.Collective.create({
slug: 'webpack',
name: 'test',
currency: 'USD',
isActive: true,
});
const event = await models.Collective.create({
slug: 'meetup-ev1',
name: 'meetup',
type: 'EVENT',
ParentCollectiveId: collective.id,
isActive: true,
});
const tier = await models.Tier.create({
slug: 'backer',
name: 'best backer',
CollectiveId: collective.id,
amount: 1000,
currency: collective.currency,
CollectiveId: event.id,
});
await collective.addHost(host);
await collective.update({ isActive: true });
const thisOrder = cloneDeep(baseOrder);
delete thisOrder.paymentMethod;
thisOrder.paymentMethod = { type: 'manual' };
thisOrder.collective.id = collective.id;
thisOrder.collective.id = event.id;
thisOrder.user = {
firstName: 'John',
lastName: 'Smith',
email: 'jsmith@email.com',
twitterHandle: 'johnsmith',
};
thisOrder.tier = { id: tier.id };
thisOrder.quantity = 2;
thisOrder.totalAmount = 2000;
const res = await utils.graphqlQuery(createOrderQuery, {
order: thisOrder,
});
Expand All @@ -231,9 +244,11 @@ describe('createOrder', () => {
expect(emailSendMessageSpy.callCount).to.equal(2);
expect(emailSendMessageSpy.secondCall.args[0]).to.equal(thisOrder.user.email);
expect(emailSendMessageSpy.secondCall.args[2]).to.match(
/Please send a wire to XXXX for the amount of \$1,543 with the mention: webpack backer order: [0-9]+/,
/Please send a wire to XXXX for the amount of \$20 with the mention: webpack event backer order: [0-9]+/,
);
expect(emailSendMessageSpy.secondCall.args[1]).to.equal(
'ACTION REQUIRED: your $20 registration to meetup is pending',
);
expect(emailSendMessageSpy.secondCall.args[1]).to.equal('ACTION REQUIRED: your $1,543 donation to test is pending');
});

it('creates an order as new user and sends a tweet', async () => {
Expand Down