Disables payment for group plans.

This commit is contained in:
Adrian Winterstein 2025-06-19 07:39:03 +02:00
parent 799ff58903
commit c5e5e3bb71
No known key found for this signature in database
GPG key ID: EDBA4B9F8D8E37AE
5 changed files with 61 additions and 69 deletions

View file

@ -20,11 +20,11 @@
</span>
<button
class="btn btn-primary next-button"
:value="$t('next')"
:value="$t('create')"
:disabled="!newGroupIsReady"
@click="stripeGroup({ group: newGroup })"
@click="createGroup(newGroup)"
>
{{ $t('next') }}
{{ $t('create') }}
</button>
</div>
<h2>{{ $t('createGroup') }}</h2>
@ -75,32 +75,13 @@
>{{ $t('leaderOnlyChallenges') }}</label>
</div>
</div>
<div class="form-group">
<lockable-label
:text="$t('groupUse')"
/>
<select-translated-array
:items="[
'groupParentChildren',
'groupCouple',
'groupFriends',
'groupCoworkers',
'groupManager',
'groupTeacher'
]"
class="group-input"
:placeholder="'groupUseDefault'"
:value="newGroup.demographics"
@select="newGroup.demographics = $event"
/>
</div>
<div class="form-group">
<button
class="btn btn-primary btn-lg btn-block btn-payment"
:disabled="!newGroupIsReady"
@click="stripeGroup({ group: newGroup })"
@click="createGroup(newGroup)"
>
{{ $t('nextPaymentMethod') }}
{{ $t('create') }}
</button>
</div>
</div>
@ -227,14 +208,15 @@
</style>
<script>
import axios from 'axios';
import pick from 'lodash/pick';
import { CONSTANTS, setLocalSetting } from '@/libs/userlocalManager';
import paymentsMixin from '../../mixins/payments';
import { mapState } from '@/libs/store';
import selectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
import lockableLabel from '@/components/tasks/modal-controls/lockableLabel';
export default {
components: {
selectTranslatedArray,
lockableLabel,
},
mixins: [paymentsMixin],
@ -257,7 +239,7 @@ export default {
computed: {
...mapState({ user: 'user.data' }),
newGroupIsReady () {
return Boolean(this.newGroup.name) && Boolean(this.newGroup.demographics);
return Boolean(this.newGroup.name);
},
charactersRemaining () {
const currentLength = this.newGroup.description ? this.newGroup.description.length : 0;
@ -271,6 +253,35 @@ export default {
onHide () {
this.sendingInProgress = false;
},
async createGroup (group) {
this.$root.$emit('bv::hide::modal', 'create-group');
try {
const response = await axios.post('/api/v4/groups/create-plan', {
groupToCreate: group,
paymentType: '',
});
const newGroup = response.data.data;
if (newGroup && newGroup._id) {
this.user.guilds.push(newGroup._id);
const appState = {
newGroup: true,
paymentCompleted: true,
group: pick(newGroup, ['_id', 'memberCount', 'name']),
};
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
this.$router.push(`/group-plans/${newGroup._id}/task-information`);
return;
}
window.location.reload(true);
} catch (e) {
console.log(e); // eslint-disable-line no-console
}
},
},
};
</script>

View file

@ -31,6 +31,7 @@
>
</span>
</template>
<!--
<b-dropdown-item
v-if="isLeader && !group.purchased.active && group.privacy === 'private'"
class="selectListItem custom-hover--upgrade"
@ -47,6 +48,7 @@
</span>
</span>
</b-dropdown-item>
-->
<b-dropdown-item
v-if="!isMember"
class="selectListItem"

View file

@ -27,13 +27,6 @@
<p class="mb-0">
{{ $t('groupPlanDesc') }}
</p>
<div class="pricing mt-5">
<span>Just</span>
<span class="number">$9</span>
<span class="bold">per month +</span>
<span class="number">$3</span>
<span class="bold">per additional member*</span>
</div>
<div class="text-center">
<button
class="btn btn-primary cta-button white mt-4 mb-3"
@ -42,9 +35,6 @@
{{ $t('getStarted') }}
</button>
</div>
<p class="gray-200">
{{ $t('billedMonthly') }}
</p>
</div>
<div class="top-right"></div>
<div class="d-flex justify-content-between align-items-middle w-100 gap-72 mb-100">
@ -69,18 +59,6 @@
<p>{{ $t('groupManagementControlsDesc') }}</p>
</div>
</div>
<div class="d-flex flex-column justify-content-center">
<img
class="big-gem mb-3 mx-auto"
src="../../assets/images/group-plans-static/big-gem@3x.png"
>
<h2 class="mt-3">
{{ $t('inGameBenefits') }}
</h2>
<p class="final-paragraph mx-auto">
{{ $t('inGameBenefitsDesc') }}
</p>
</div>
<div class="text-center mb-128">
<div class="bot-left"></div>
<div class="col-6 offset-3">
@ -96,13 +74,6 @@
>
{{ $t('createGroupToday') }}
</h2>
<div class="pricing mb-4">
<span>Just</span>
<span class="number">$9</span>
<span class="bold">per month +</span>
<span class="number">$3</span>
<span class="bold">per member*</span>
</div>
<div class="text-center mb-3">
<button
class="btn btn-primary cta-button white"
@ -111,9 +82,6 @@
{{ $t('getStarted') }}
</button>
</div>
<p class="gray-200">
{{ $t('billedMonthly') }}
</p>
</div>
<div class="bot-right"></div>
</div>

View file

@ -197,8 +197,6 @@ api.createGroupPlan = {
const { user } = res.locals;
const group = new Group(Group.sanitize(req.body.groupToCreate));
req.checkBody('paymentType', res.t('paymentTypeRequired')).notEmpty();
req.checkBody('summary', apiError('summaryLengthExceedsMax')).isLength({ max: MAX_SUMMARY_SIZE_FOR_GUILDS });
const validationErrors = req.validationErrors();
if (validationErrors) throw validationErrors;
@ -208,6 +206,18 @@ api.createGroupPlan = {
user.guilds.push(group._id);
const results = await Promise.all([user.save(), group.save()]);
await payments.createSubscription({
user,
customerId: 'habitrpg',
paymentMethod: '',
sub: {
key: 'group_monthly',
quantity: 100000,
},
groupId: group._id,
});
const savedGroup = results[1];
res.analytics.track('join group', {
@ -264,6 +274,8 @@ api.createGroupPlan = {
headers,
});
res.respond(201, groupResponse);
} else {
res.respond(201, groupResponse);
}
},
@ -492,9 +504,11 @@ api.updateGroup = {
if (group.leader !== user._id && group.type === 'party') throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
else if (group.leader !== user._id && !user.hasPermission('moderator')) throw new NotAuthorized(res.t('messageGroupOnlyLeaderCanUpdate'));
/*
if (req.body.leader && req.body.leader !== user._id && group.hasNotCancelled()) {
throw new NotAuthorized(res.t('cannotChangeLeaderWithActiveGroupPlan'));
}
*/
const handleArrays = (currentValue, updatedValue) => {
if (!_.isArray(currentValue)) {

View file

@ -1,4 +1,3 @@
import moment from 'moment';
import mongoose from 'mongoose';
import _ from 'lodash';
import validator from 'validator';
@ -1354,6 +1353,7 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all', keepC
const group = this;
const update = {};
/*
if (group.memberCount <= 1 && group.privacy === 'private' && group.hasNotCancelled()) {
throw new NotAuthorized(shared.i18n.t('cannotDeleteActiveGroup'));
}
@ -1361,6 +1361,7 @@ schema.methods.leave = async function leaveGroup (user, keep = 'keep-all', keepC
if (group.leader === user._id && group.hasNotCancelled()) {
throw new NotAuthorized(shared.i18n.t('leaderCannotLeaveGroupWithActiveGroup'));
}
*/
if (group.purchased.plan.customerId) {
await payments.cancelGroupSubscriptionForUser(user, this);
@ -1635,20 +1636,16 @@ schema.methods.checkChatSpam = function groupCheckChatSpam (user) {
};
schema.methods.hasActiveGroupPlan = function hasActiveGroupPlan () {
const now = new Date();
const { plan } = this.purchased;
return plan && plan.customerId
&& (!plan.dateTerminated || moment(plan.dateTerminated).isAfter(now));
return plan && plan.customerId;
};
schema.methods.hasNotCancelled = function hasNotCancelled () {
const { plan } = this.purchased;
return Boolean(this.hasActiveGroupPlan() && !plan.dateTerminated);
return this.hasActiveGroupPlan();
};
schema.methods.hasCancelled = function hasCancelled () {
const { plan } = this.purchased;
return Boolean(this.hasActiveGroupPlan() && plan.dateTerminated);
return !this.hasActiveGroupPlan();
};
schema.methods.updateGroupPlan = async function updateGroupPlan (removingMember) {