Skip to content
This repository has been archived by the owner on Aug 11, 2024. It is now read-only.

Commit

Permalink
Start moving contribution info from Contact into ContactContribution
Browse files Browse the repository at this point in the history
  • Loading branch information
wpf500 committed May 15, 2024
1 parent 2bf55d1 commit 9d08ddd
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 83 deletions.
6 changes: 3 additions & 3 deletions src/api/transformers/ContactExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class ContactExporter extends BaseContactTransformer<
Joined: contact.joined.toISOString(),
Tags: contact.profile.tags.join(", "),
ContributionType: contact.contributionType,
ContributionMonthlyAmount: contact.contributionMonthlyAmount,
ContributionPeriod: contact.contributionPeriod,
ContributionDescription: contact.contributionDescription,
ContributionMonthlyAmount: contact.contribution.monthlyAmount,
ContributionPeriod: contact.contribution.period,
ContributionDescription: contact.contribution.description,
ContributionCancelled:
contact.contribution.cancelledAt?.toISOString() || "",
MembershipStarts: contact.membership?.dateAdded.toISOString() || "",
Expand Down
10 changes: 6 additions & 4 deletions src/api/transformers/ContactTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ class ContactTransformer extends BaseContactTransformer<
...(contact.lastSeen && {
lastSeen: contact.lastSeen
}),
...(contact.contributionAmount && {
contributionAmount: contact.contributionAmount
...(contact.contribution.amount !== null && {
contributionAmount: contact.contribution.amount
}),
...(contact.contributionPeriod && {
contributionPeriod: contact.contributionPeriod
...(contact.contribution.period && {
contributionPeriod: contact.contribution.period
}),
...(opts?.with?.includes(GetContactWith.Profile) &&
contact.profile && {
Expand Down Expand Up @@ -86,6 +86,8 @@ class ContactTransformer extends BaseContactTransformer<
query: ListContactsDto
): void {
{
qb.innerJoinAndSelect(`${fieldPrefix}contribution`, "contribution");

if (query.with?.includes(GetContactWith.Profile)) {
qb.innerJoinAndSelect(`${fieldPrefix}profile`, "profile");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ block contents
value: member.contributionMonthlyAmount
})
if !!contribution.subscriptionId
input(type='hidden' name='period' value=member.contributionPeriod)
input(type='hidden' name='period' value=contribution.period)
.form-group
label.col-md-3.control-label Period
.col-md-4.form-control-static= member.contributionPeriod
.col-md-4.form-control-static= contribution.period
else
+input( 'radio', 'Period', 'period', {
left: 3, right: 4,
options: {'monthly': 'Monthly', 'annually': 'Annually'},
value: member.contributionPeriod
value: contribution.period
})
+input( 'checkbox', 'Paying fee', 'payFee', {
left: 3, right: 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
.js-reveal-type(data-type='Manual')
+input( 'number', 'Amount', 'amount', {
left: 3, right: 4, before: currencySymbol,
value: member.contributionAmount
value: contribution.amount
})
+input( 'radio', 'Period', 'period', {
left: 3, right: 4,
options: {'monthly': 'Monthly', 'annually': 'Annually'},
value: member.contributionPeriod
value: contribution.period
})

.form-group
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dl.dl-horizontal
if member.contributionType
dt Amount
dd
= member.contributionDescription
= contribution.description
case member.contributionType
when 'Automatic'
include automatic.pug
Expand Down
4 changes: 2 additions & 2 deletions src/apps/members/views/partials/table.pug
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ mixin contactsTable
+membersTableBasicInfo(contact)
span(style='flex: 0 1 120px')
= currencySymbol
= contact.contributionAmount
= contact.contribution.amount
| /
= contact.contributionPeriod
= contact.contribution.period

if addToProject
form(method='POST' action='/projects/' + addToProject.id)
Expand Down
4 changes: 2 additions & 2 deletions src/apps/tools/apps/exports/exports/ActiveMembersExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ export default class ActiveMembersExport extends BaseExport<Contact> {
PollsCode: contact.pollsCode,
ContributionType: contact.contributionType,
ContributionMonthlyAmount: contact.contributionMonthlyAmount,
ContributionPeriod: contact.contributionPeriod,
ContributionDescription: contact.contributionDescription
ContributionPeriod: contact.contribution.period,
ContributionDescription: contact.contribution.description
}));
}
}
23 changes: 12 additions & 11 deletions src/core/providers/payment/GCProvider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { PaymentMethod, PaymentSource } from "@beabee/beabee-common";
import {
ContributionPeriod,
PaymentMethod,
PaymentSource
} from "@beabee/beabee-common";
import { Subscription } from "gocardless-nodejs";
import moment from "moment";

Expand Down Expand Up @@ -79,8 +83,8 @@ export default class GCProvider extends PaymentProvider {
// result in double charging
return (
(useExistingMandate &&
this.contact.contributionPeriod === "monthly" &&
paymentForm.period === "monthly") ||
this.data.period === ContributionPeriod.Monthly &&
paymentForm.period === ContributionPeriod.Monthly) ||
!(this.data.mandateId && (await hasPendingPayment(this.data.mandateId)))
);
}
Expand All @@ -102,7 +106,7 @@ export default class GCProvider extends PaymentProvider {
if (this.data.subscriptionId) {
if (
this.contact.membership?.isActive &&
this.contact.contributionPeriod === paymentForm.period
this.data.period === paymentForm.period
) {
subscription = await updateSubscription(
this.data.subscriptionId,
Expand Down Expand Up @@ -206,14 +210,11 @@ export default class GCProvider extends PaymentProvider {
await gocardless.mandates.cancel(mandateId);
}

if (
hadSubscription &&
this.contact.contributionPeriod &&
this.contact.contributionMonthlyAmount
) {
// Recreate the subscription if the user had one
if (hadSubscription && this.data.period && this.data.monthlyAmount) {
await this.updateContribution({
monthlyAmount: this.contact.contributionMonthlyAmount,
period: this.contact.contributionPeriod,
monthlyAmount: this.data.monthlyAmount,
period: this.data.period,
payFee: !!this.data.payFee,
prorate: false
});
Expand Down
16 changes: 13 additions & 3 deletions src/core/services/NewsletterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MailchimpProvider from "@core/providers/newsletter/MailchimpProvider";
import NoneProvider from "@core/providers/newsletter/NoneProvider";

import Contact from "@models/Contact";
import ContactContribution from "@models/ContactContribution";
import ContactProfile from "@models/ContactProfile";

import config from "@config";
Expand Down Expand Up @@ -40,6 +41,15 @@ async function contactToNlUpdate(
});
}

// TODO: Fix that it relies on contact.contribution being loaded
if (!contact.contribution) {
contact.contribution = await getRepository(
ContactContribution
).findOneByOrFail({
contactId: contact.id
});
}

if (contact.profile.newsletterStatus !== NewsletterStatus.None) {
return {
email: contact.email,
Expand All @@ -50,9 +60,9 @@ async function contactToNlUpdate(
fields: {
REFCODE: contact.referralCode || "",
POLLSCODE: contact.pollsCode || "",
C_DESC: contact.contributionDescription,
C_MNTHAMT: contact.contributionMonthlyAmount?.toFixed(2) || "",
C_PERIOD: contact.contributionPeriod || ""
C_DESC: contact.contribution.description,
C_MNTHAMT: contact.contribution.monthlyAmount?.toFixed(2) || "",
C_PERIOD: contact.contribution.period || ""
}
};
}
Expand Down
78 changes: 42 additions & 36 deletions src/core/services/PaymentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class PaymentService {
).findOneByOrFail({
contactId: contact.id
});
// No need to refetch contact, just add it in
return { ...contribution, contact };
contribution.contact = contact; // No need to refetch contact, just add it in
return contribution;
}

async getContributionBy(
Expand Down Expand Up @@ -101,40 +101,46 @@ class PaymentService {
}

async getContributionInfo(contact: Contact): Promise<ContributionInfo> {
return await this.provider<ContributionInfo>(contact, async (p, d) => {
// Store payment data in contact for getMembershipStatus
// TODO: fix this!
contact.contribution = d;

const renewalDate = !d.cancelledAt && calcRenewalDate(contact);

return {
type: contact.contributionType,
...(contact.contributionAmount !== null && {
amount: contact.contributionAmount
}),
...(contact.contributionPeriod !== null && {
period: contact.contributionPeriod
}),
...(d.payFee !== null && {
payFee: d.payFee
}),
...(d.nextAmount &&
contact.contributionPeriod && {
nextAmount: getActualAmount(
d.nextAmount.monthly,
contact.contributionPeriod
)
return await this.provider<ContributionInfo>(
contact,
async (provider, contribution) => {
// Store contribution in contact for getMembershipStatus
// TODO: fix this!
contact.contribution = contribution;

const renewalDate =
!contribution.cancelledAt && calcRenewalDate(contact);

return {
type: contact.contributionType,
...(contribution.amount !== null && {
amount: contribution.amount
}),
...(contact.membership?.dateExpires && {
membershipExpiryDate: contact.membership.dateExpires
}),
membershipStatus: getMembershipStatus(contact),
...(await p.getContributionInfo()),
...(d.cancelledAt && { cancellationDate: d.cancelledAt }),
...(renewalDate && { renewalDate })
};
});
...(contribution.period !== null && {
period: contribution.period
}),
...(contribution.payFee !== null && {
payFee: contribution.payFee
}),
...(contribution.nextAmount &&
contribution.period && {
nextAmount: getActualAmount(
contribution.nextAmount.monthly,
contribution.period
)
}),
...(contribution.cancelledAt && {
cancellationDate: contribution.cancelledAt
}),
...(contact.membership?.dateExpires && {
membershipExpiryDate: contact.membership.dateExpires
}),
membershipStatus: getMembershipStatus(contact),
...(await provider.getContributionInfo()),
...(renewalDate && { renewalDate })
};
}
);
}

async getPayments(contact: Contact): Promise<Payment[]> {
Expand Down Expand Up @@ -190,7 +196,7 @@ class PaymentService {

// Clear the old payment data, set the new method
Object.assign(contribution, {
...ContactContribution.empty,
...ContactContribution.none,
method: newMethod
});
await getRepository(ContactContribution).save(contribution);
Expand Down
43 changes: 40 additions & 3 deletions src/models/ContactContribution.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { PaymentMethod } from "@beabee/beabee-common";
import { ContributionPeriod, PaymentMethod } from "@beabee/beabee-common";
import { Column, Entity, JoinColumn, OneToOne, PrimaryColumn } from "typeorm";

import { getActualAmount } from "@core/utils";

import type Contact from "./Contact";

import config from "@config";

@Entity()
export default class ContactContribution {
@PrimaryColumn()
Expand All @@ -14,6 +18,12 @@ export default class ContactContribution {
@Column({ type: String, nullable: true })
method!: PaymentMethod | null;

@Column({ type: Number, nullable: true })
monthlyAmount!: number | null;

@Column({ type: String, nullable: true })
period!: ContributionPeriod | null;

@Column({ type: String, nullable: true })
customerId!: string | null;

Expand All @@ -32,15 +42,42 @@ export default class ContactContribution {
@Column({ type: Date, nullable: true })
cancelledAt!: Date | null;

static get empty(): Omit<ContactContribution, "contact" | "contactId"> {
get amount(): number | null {
return this.monthlyAmount === null || this.period === null
? null
: getActualAmount(this.monthlyAmount, this.period);
}

get description(): string {
/*if (this.contributionType === "Gift") {
return "Gift";
} else */ if (
this.method === null ||
this.period === null ||
this.amount === null
) {
return "None";
} else {
return `${config.currencySymbol}${this.amount}/${
this.period === "monthly" ? "month" : "year"
}`;
}
}

static get none(): Omit<ContactContribution, "contact" | "contactId"> {
return {
method: null,
monthlyAmount: null,
amount: null,
customerId: null,
mandateId: null,
subscriptionId: null,
payFee: null,
nextAmount: null,
cancelledAt: null
cancelledAt: null,

period: null, // TODO
description: "None"
};
}
}
9 changes: 3 additions & 6 deletions src/tools/gocardless/migrate-to-stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,7 @@ runApp(async () => {
contact.email,
contactPayments.length
);
} else if (
!contact.contributionPeriod ||
!contact.contributionMonthlyAmount
) {
} else if (!contribution.period || !contribution.monthlyAmount) {
console.error(
"ERROR: Contact doesn't have a contribution amount or period"
);
Expand Down Expand Up @@ -161,8 +158,8 @@ runApp(async () => {

// Recreate the contribution
await PaymentService.updateContribution(contact, {
monthlyAmount: contact.contributionMonthlyAmount,
period: contact.contributionPeriod,
monthlyAmount: contribution.monthlyAmount,
period: contribution.period,
payFee: false,
prorate: false
});
Expand Down
Loading

0 comments on commit 9d08ddd

Please sign in to comment.