feat: add referral_code

This commit is contained in:
2026-06-06 13:10:25 +03:30
parent 0f5f7835e7
commit 6c602af9eb
5 changed files with 120 additions and 0 deletions
+79
View File
@@ -140,6 +140,85 @@ public function subscribeUser(Request $request, $identifier)
]);
}
/**
* List users who reached the referral invite target (کد معرف) and have
* not yet been granted their free-month subscription.
*/
public function pendingReferralRewards(Request $request)
{
$target = User::REFERRAL_SUBSCRIPTION_TARGET;
$users = User::withCount('referrals')
->whereNull('referral_subscription_granted_at')
->having('referrals_count', '>=', $target)
->orderByDesc('referrals_count')
->get(['id', 'uuid', 'first_name', 'last_name', 'email', 'mobile', 'referral_code']);
return response()->json([
'subscription_target' => $target,
'data' => $users->map(fn ($u) => [
'id' => $u->id,
'uuid' => $u->uuid,
'name' => trim($u->first_name . ' ' . $u->last_name),
'email' => $u->email,
'mobile' => $u->mobile,
'referral_code' => $u->referral_code,
'successful_invites' => $u->referrals_count,
]),
]);
}
/**
* Grant the free-month subscription to a user who reached the referral
* invite target. Defaults to the meditation package's monthly product,
* overridable via product_id. Marks the grant so it happens only once.
*/
public function fulfillReferralReward(Request $request, $userId)
{
$data = $request->validate([
'product_id' => 'integer|nullable',
]);
if (!$user = User::find($userId)) {
return response()->json(['message' => 'user not found'], 404);
}
if ($user->referral_subscription_granted_at) {
return response()->json(['message' => 'referral subscription already granted'], 400);
}
if ($user->referrals()->count() < User::REFERRAL_SUBSCRIPTION_TARGET) {
return response()->json(['message' => 'user has not reached the referral target yet'], 400);
}
// Resolve which monthly product to grant
if (!empty($data['product_id'])) {
$product = Product::where('id', $data['product_id'])->first();
} else {
$package = PackageName::where('name', User::REFERRAL_PACKAGE_NAME)->first();
$product = $package
? Product::where('package_name_id', $package->id)
->where('type', Product::TYPES['monthly'])
->first()
: null;
}
if (!$product) {
return response()->json(['message' => 'monthly product not found'], 404);
}
$product->buy($user);
$user->referral_subscription_granted_at = now();
$user->save();
return response()->json([
'message' => 'referral subscription granted',
'user_id' => $user->id,
'product_id' => $product->id,
]);
}
public function unsubscribeUser(Request $request, $identifier)
{
$data = $request->validate([
+4
View File
@@ -638,6 +638,10 @@ public function status(Request $request)
->first();
}
// Expose the referrer's uuid so downstream apps can resolve the
// referral relationship (کد معرف) against their own local user.
$user['referrer_uuid'] = $user->referred_by ? optional($user->referrer)->uuid : null;
return $user;
}
+7
View File
@@ -20,9 +20,16 @@ class User extends Authenticatable
'male' => 1,
'female' => 2,
];
// Referral program (کد معرف): successful invites needed for a free month,
// and the app whose monthly product is granted as the reward.
const REFERRAL_SUBSCRIPTION_TARGET = 10;
const REFERRAL_PACKAGE_NAME = 'com.approagency.meditation';
protected $guarded = [];
protected $casts = [
'mobile_verified_at' => 'datetime',
'referral_subscription_granted_at' => 'datetime',
];
protected $hidden = [
'password',