/** * Handle the event. * * @param UnknownPayPalPaymentReceived $event */ public function handle(UnknownPayPalPaymentReceived $event) { $email = $event->emailAddress; $payment = $this->paymentRepository->getById($event->paymentId); $this->mailer->send('emails.paypal-donation', ['email' => $email, 'payment' => $payment], function ($m) use($email) { $m->to($email); $m->cc('*****@*****.**'); $m->subject('Unknown PayPal Payment Received'); }); }
/** * Start the creation of a new gocardless payment * Details get posted into this method and the redirected to gocardless * @param $userId * @throws \BB\Exceptions\AuthenticationException * @throws \BB\Exceptions\FormValidationException * @throws \BB\Exceptions\NotImplementedException */ public function store($userId) { User::findWithPermission($userId); $requestData = \Request::only(['reason', 'amount', 'return_path', 'stripeToken', 'ref']); $stripeToken = $requestData['stripeToken']; $amount = $requestData['amount']; $reason = $requestData['reason']; $returnPath = $requestData['return_path']; $ref = $requestData['ref']; try { $charge = Stripe_Charge::create(array("amount" => $amount, "currency" => "gbp", "card" => $stripeToken, "description" => $reason)); } catch (\Exception $e) { \Log::error($e); if (\Request::wantsJson()) { return \Response::json(['error' => 'There was an error confirming your payment'], 400); } \Notification::error("There was an error confirming your payment"); return \Redirect::to($returnPath); } //Replace the amount with the one from the charge, this prevents issues with variable tempering $amount = $charge->amount / 100; //Stripe don't provide us with the fee so this should be OK $fee = $amount * 0.024 + 0.2; $this->paymentRepository->recordPayment($reason, $userId, 'stripe', $charge->id, $amount, 'paid', $fee, $ref); if (\Request::wantsJson()) { return \Response::json(['message' => 'Payment made']); } \Notification::success("Payment made"); return \Redirect::to($returnPath); }
public function update($logEntryId) { $reason = \Request::get('reason'); if (!in_array($reason, ['training', 'testing'])) { throw new \BB\Exceptions\ValidationException("Not a valid reason"); } $equipmentLog = $this->equipmentLogRepository->getById($logEntryId); /* if ($equipmentLog->user_id == \Auth::user()->id) { throw new \BB\Exceptions\ValidationException("You can't update your own record"); } */ if (!\Auth::user()->hasRole($equipmentLog->device) && !\Auth::user()->isAdmin()) { throw new \BB\Exceptions\ValidationException("You don't have permission to alter this record"); } if (!empty($equipmentLog->reason)) { throw new \BB\Exceptions\ValidationException("Reason already set"); } $billedStatus = $equipmentLog->billed; if ($equipmentLog->billed) { //the user has been billed, we need to undo this. $payments = $this->paymentRepository->getPaymentsByReference($equipmentLog->id . ':' . $equipmentLog->device); if ($payments->count() == 1) { $this->paymentRepository->delete($payments->first()->id); $billedStatus = false; } else { throw new \BB\Exceptions\ValidationException("Unable to locate related payment, please contact an admin"); } } $this->equipmentLogRepository->update($logEntryId, ['reason' => $reason, 'billed' => $billedStatus]); \Notification::success("Record Updated"); return \Redirect::back(); }
/** * Start the creation of a new balance payment * Details get posted into this method * @param $userId * @throws \BB\Exceptions\AuthenticationException * @throws \BB\Exceptions\FormValidationException * @throws \BB\Exceptions\NotImplementedException */ public function store($userId) { $user = User::findWithPermission($userId); $this->bbCredit->setUserId($user->id); $requestData = \Request::only(['reason', 'amount', 'return_path', 'ref']); $amount = $requestData['amount'] * 1 / 100; $reason = $requestData['reason']; $returnPath = $requestData['return_path']; $ref = $requestData['ref']; //Can the users balance go below 0 $minimumBalance = $this->bbCredit->acceptableNegativeBalance($reason); //What is the users balance $userBalance = $this->bbCredit->getBalance(); //With this payment will the users balance go to low? if ($userBalance - $amount < $minimumBalance) { if (\Request::wantsJson()) { return \Response::json(['error' => 'You don\'t have the money for this'], 400); } \Notification::error("You don't have the money for this"); return \Redirect::to($returnPath); } //Everything looks gooc, create the payment $this->paymentRepository->recordPayment($reason, $userId, 'balance', '', $amount, 'paid', 0, $ref); //Update the users cached balance $this->bbCredit->recalculate(); if (\Request::wantsJson()) { return \Response::json(['message' => 'Payment made']); } \Notification::success("Payment made"); return \Redirect::to($returnPath); }
/** * Create a charge and immediately bill it through the direct debit process * * @param integer $userId * @param \DateTime $date * @param integer $amount * @param string $status * @param string $DDAuthId * @return SubscriptionCharge */ public function createChargeAndBillDD($userId, $date, $amount, $status, $DDAuthId) { $charge = $this->createCharge($userId, $date, $amount, $status); $bill = $this->goCardless->newBill($DDAuthId, $amount, $this->goCardless->getNameFromReason('subscription')); if ($bill) { $this->paymentRepository->recordSubscriptionPayment($userId, 'gocardless-variable', $bill->id, $bill->amount, $bill->status, $bill->gocardless_fees, $charge->id); } }
public function handle() { $data = \Request::only(['device', 'tag', 'service']); try { $keyFob = $this->keyFobAccess->lookupKeyFob($data['tag']); } catch (\Exception $e) { \Log::debug(json_encode($data)); return \Response::make('Not found', 404); } $user = $keyFob->user()->first(); $this->paymentRepository->recordPayment($data['service'], $user->id, 'balance', null, 0.05, 'paid', 0, $data['device']); event(new MemberActivity($keyFob, $data['service'])); return \Response::make('OK', 201); }
/** * @param string $action */ private function processBills($action, array $bills) { foreach ($bills as $bill) { $existingPayment = $this->paymentRepository->getPaymentBySourceId($bill['id']); if ($existingPayment) { if ($bill['status'] == 'failed' || $bill['status'] == 'cancelled') { //Payment failed or cancelled - either way we don't have the money! //We need to retrieve the payment from the user somehow but don't want to cancel the subscription. //$this->handleFailedCancelledBill($existingPayment); $this->paymentRepository->recordPaymentFailure($existingPayment->id, $bill['status']); } elseif ($bill['status'] == 'pending' && $action == 'retried') { //Failed payment is being retried $subCharge = $this->subscriptionChargeRepository->getById($existingPayment->reference); if ($subCharge) { if ($subCharge->amount == $bill['amount']) { $this->subscriptionChargeRepository->markChargeAsProcessing($subCharge->id); } else { //@TODO: Handle partial payments \Log::warning("Sub charge handling - gocardless partial payment"); } } } elseif ($bill['status'] == 'refunded') { //Payment refunded //Update the payment record and possible the user record } elseif ($bill['status'] == 'withdrawn') { //Money taken out - not our concern } } else { \Log::info("GoCardless Webhook received for unknown payment: " . $bill['id']); } } }
private function updateSubPayment($paymentId, $userId, $status) { $payment = $this->paymentRepository->getById($paymentId); $subCharge = $this->subscriptionChargeRepository->findCharge($userId); if (!$subCharge) { \Log::warning('Subscription payment without a sub charge. Payment ID:' . $paymentId); return; } //The sub charge record id gets saved onto the payment if (empty($payment->reference)) { $payment->reference = $subCharge->id; $payment->save(); } else { if ($payment->reference != $subCharge->id) { throw new PaymentException('Attempting to update sub charge (' . $subCharge->id . ') but payment (' . $payment->id . ') doesn\'t match. Sub charge has an existing reference on it.'); } } if ($status == 'paid') { $this->subscriptionChargeRepository->markChargeAsPaid($subCharge->id); } else { if ($status == 'pending') { $this->subscriptionChargeRepository->markChargeAsProcessing($subCharge->id); } } //The amount isn't stored on the sub charge record until its paid or processing if ($payment->amount != $subCharge->amount) { $this->subscriptionChargeRepository->updateAmount($subCharge->id, $payment->amount); } }
/** * Remove cash from the users balance * * @param $userId * @return mixed * @throws \BB\Exceptions\AuthenticationException * @throws \BB\Exceptions\InvalidDataException */ public function destroy($userId) { $user = User::findWithPermission($userId); $this->bbCredit->setUserId($userId); $amount = \Request::get('amount'); $returnPath = \Request::get('return_path'); $ref = \Request::get('ref'); $minimumBalance = $this->bbCredit->acceptableNegativeBalance('withdrawal'); if ($user->cash_balance + $minimumBalance * 100 < $amount * 100) { \Notification::error("Not enough money"); return \Redirect::to($returnPath); } $this->paymentRepository->recordPayment('withdrawal', $userId, 'balance', '', $amount, 'paid', 0, $ref); $this->bbCredit->recalculate(); \Notification::success("Payment recorded"); return \Redirect::to($returnPath); }
/** * Bill members based on the sub charges that are due */ public function billMembers() { $subCharges = $this->subscriptionChargeRepository->getDue(); foreach ($subCharges as $charge) { if ($charge->user->payment_method == 'gocardless-variable') { //Look the the previous attempts - there may be multiple failures $existingPayments = $this->paymentRepository->getPaymentsByReference($charge->id); if ($existingPayments->count() > 0) { //We will let the user retry the payment if it fails continue; } $bill = $this->goCardless->newBill($charge->user->subscription_id, $charge->user->monthly_subscription, $this->goCardless->getNameFromReason('subscription')); if ($bill) { $this->paymentRepository->recordSubscriptionPayment($charge->user->id, 'gocardless-variable', $bill->id, $bill->amount, $bill->status, $bill->gocardless_fees, $charge->id); } } } }
public function receiveNotification() { $ipnMessage = new \PayPal\IPN\PPIPNMessage('', PayPalConfig::getConfig()); if (!$ipnMessage->validate()) { \Log::error("Invalid IPN"); } $ipnData = $ipnMessage->getRawData(); if (isset($ipnData['txn_type']) && $ipnData['txn_type'] == 'subscr_payment') { if ($ipnData['payment_status'] != 'Completed') { \Log::error("PayPal IPN: Received unknown payment status for sub payment: \"" . $ipnData['payment_status'] . "\" Email: " . $ipnData['payer_email']); return; } $user = User::where('email', $ipnData['payer_email'])->first(); if (!$user) { $user = User::where('secondary_email', $ipnData['payer_email'])->first(); } if (!$user) { //\Log::error("PayPal IPN Received for unknown email " . $ipnData['payer_email']); $paymentId = $this->paymentRepository->recordPayment('donation', 0, 'paypal', $ipnData['txn_id'], $ipnData['mc_gross'], 'paid', $ipnData['mc_fee'], $ipnData['payer_email']); event(new \BB\Events\UnknownPayPalPaymentReceived($paymentId, $ipnData['payer_email'])); return; } //It looks like the user might be joining again if ($user->status == 'left') { $user->rejoin(); } //If its a new user set them up by creating the first sub charge record and setting the payment day if ($user->status == 'setting-up') { $this->setupNewMember($user, $ipnData['mc_gross']); } //Record the subscription payment, this will automatically deal with locating the sub charge and updating that $this->paymentRepository->recordSubscriptionPayment($user->id, 'paypal', $ipnData['txn_id'], $ipnData['mc_gross'], 'paid', $ipnData['mc_fee']); } elseif (isset($ipnData['txn_type']) && $ipnData['txn_type'] == 'subscr_cancel') { $user = User::where('email', $ipnData['payer_email'])->first(); if ($user) { //The user may have already changed to another method, only cancel if its still paypal if ($user->payment_method == 'paypal') { $user->cancelSubscription(); } //@TODO: Deal with any open sub payment records } } }
/** * This is a basic method for recording a payment transfer between two people * This should not exist and the normal balance payment controller should be used * If any more work is needed here please take the time and move it over! * * @param Request $request * @param integer $userId * * @return mixed * @throws ValidationException * @throws AuthenticationException */ public function recordTransfer(Request $request, $userId) { $user = User::findWithPermission($userId); $this->bbCredit->setUserId($user->id); $amount = $request->get('amount'); $targetUserId = $request->get('target_user_id'); $targetUser = $this->userRepository->getById($targetUserId); if ($targetUserId === $userId) { throw new ValidationException('Your\'e trying to send money to yourself, no!'); } //What is the users balance $userBalance = $this->bbCredit->getBalance(); //With this payment will the users balance go to low? if ($userBalance - $amount < 0) { \Notification::error("You don't have the money for this"); return \Redirect::route('account.balance.index', $user->id); } $this->paymentRepository->recordBalanceTransfer($user->id, $targetUser->id, $amount); \Notification::success("Transfer made"); return \Redirect::route('account.balance.index', $user->id); }
/** * Bill members based on the sub charges that are due */ public function billMembers() { $subCharges = $this->subscriptionChargeRepository->getDue(); //Check each of the due charges, if they have previous attempted payments ignore them // we don't want to retry failed payments as for DD's this will generate bank charges $subCharges->reject(function ($charge) { return $this->paymentRepository->getPaymentsByReference($charge->id)->count() > 0; }); //Filter the list into two gocardless and balance subscriptions $goCardlessUsers = $subCharges->filter(function ($charge) { return $charge->user->payment_method == 'gocardless-variable'; }); $balanceUsers = $subCharges->filter(function ($charge) { return $charge->user->payment_method == 'balance'; }); //Charge the balance users foreach ($balanceUsers as $charge) { if ($charge->user->monthly_subscription * 100 > $charge->user->cash_balance) { //user doesn't have enough money //If they have a secondary payment method of gocardless try that if ($charge->user->secondary_payment_method == 'gocardless-variable') { //Add the charge to the gocardless list for processing $goCardlessUsers->push($charge); event(new SubscriptionPayment\InsufficientFundsTryingDirectDebit($charge->user->id, $charge->id)); } else { event(new SubscriptionPayment\FailedInsufficientFunds($charge->user->id, $charge->id)); } continue; } $this->paymentRepository->recordSubscriptionPayment($charge->user->id, 'balance', '', $charge->user->monthly_subscription, 'paid', 0, $charge->id); event(new MemberBalanceChanged($charge->user->id)); } //Charge the gocardless users foreach ($goCardlessUsers as $charge) { $bill = $this->goCardless->newBill($charge->user->subscription_id, $charge->user->monthly_subscription, $this->goCardless->getNameFromReason('subscription')); if ($bill) { $this->paymentRepository->recordSubscriptionPayment($charge->user->id, 'gocardless-variable', $bill->id, $bill->amount, $bill->status, $bill->gocardless_fees, $charge->id); } } }
public function calculatePendingFees() { $records = $this->equipmentLogRepository->getFinishedUnbilledRecords(); foreach ($records as $record) { $equipment = $this->equipmentRepository->findBySlug($record->device); if ($equipment->hasUsageCharge()) { $feePerSecond = $this->costPerSecond($equipment->usageCost); //How may seconds was the device in use $secondsActive = $record->finished->diffInSeconds($record->started); //Charges are for a minimum of 15 minutes $secondsActive = $this->roundUpSecondsActive($secondsActive); $incurredFee = $this->sessionFee($feePerSecond, $secondsActive); //If the reason is empty then its not a special case and should be billed if (empty($record->reason)) { //Create a payment against the user $this->paymentRepository->recordPayment('equipment-fee', $record->user_id, 'balance', '', $incurredFee, 'paid', 0, $record->id . ':' . $record->device); } } //Mark this log as being billed and complete $record->billed = true; $record->save(); } }
/** * Remove the specified payment * * @param int $id * @return Illuminate\Http\RedirectResponse * @throws \BB\Exceptions\ValidationException */ public function destroy($id) { $payment = $this->paymentRepository->getById($id); //we can only allow some records to get deleted, only cash payments can be removed, everything else must be refunded off if ($payment->source != 'cash') { throw new \BB\Exceptions\ValidationException('Only cash payments can be deleted'); } if ($payment->reason != 'balance') { throw new \BB\Exceptions\ValidationException('Currently only payments to the members balance can be deleted'); } //The delete event will broadcast an event and allow related actions to occur $this->paymentRepository->delete($id); \Notification::success('Payment deleted'); return \Redirect::back(); }
/** * Process a direct debit payment when we have a preauth * * @param $amount * @param $reason * @param User $user * @param $ref * @param $returnPath * @return mixed */ private function handleBill($amount, $reason, $user, $ref, $returnPath) { $bill = $this->goCardless->newBill($user->subscription_id, $amount, $this->goCardless->getNameFromReason($reason)); if ($bill) { //Store the payment $fee = $bill->amount - $bill->amount_minus_fees; $paymentSourceId = $bill->id; $amount = $bill->amount; $status = $bill->status; //The record payment process will make the necessary record updates $this->paymentRepository->recordPayment($reason, $user->id, 'gocardless-variable', $paymentSourceId, $amount, $status, $fee, $ref); if (\Request::wantsJson()) { return \Response::json(['message' => 'The payment was submitted successfully']); } \Notification::success("The payment was submitted successfully"); } else { //something went wrong - we still have the pre auth though if (\Request::wantsJson()) { return \Response::json(['error' => 'There was a problem charging your account'], 400); } \Notification::error("There was a problem charging your account"); } return \Redirect::to($returnPath); }
public function getBalancePaymentsPaginated() { return $this->paymentRepository->getBalancePaymentsPaginated($this->user->id); }
public function index() { $this->paymentRepository->reasonFilter('balance'); $balancePaidIn = $this->paymentRepository->getTotalAmount(); $this->paymentRepository->resetFilters(); $this->paymentRepository->sourceFilter('balance'); $balancePaidOut = $this->paymentRepository->getTotalAmount(); $balanceLiability = $balancePaidIn - $balancePaidOut; $this->paymentRepository->resetFilters(); $this->paymentRepository->reasonFilter('storage-box'); $storageBoxLiability = $this->paymentRepository->getTotalAmount(); $this->paymentRepository->resetFilters(); $this->paymentRepository->reasonFilter('door-key'); $doorKeyLiability = $this->paymentRepository->getTotalAmount(); $laserCutterInvestment = $this->paymentRepository->getPaymentsByReference('laser-cutter')->sum('amount'); $laserCutterMoneySpent = $this->paymentRepository->getEquipmentFeePayments('laser')->sum('amount'); return \View::make('payment_overview.index')->with(compact('balancePaidIn', 'balancePaidOut', 'balanceLiability', 'storageBoxLiability', 'doorKeyLiability', 'laserCutterInvestment', 'laserCutterMoneySpent')); }
/** * Handle the event. * * @param ExpenseWasApproved $event * @return void */ public function handle(ExpenseWasApproved $event) { $this->paymentRepository->recordPayment('balance', $event->expense->user_id, 'reimbursement', $event->expense->id, $event->expense->amount / 100); }
/** * @param int $memberId */ public function setMember($memberId) { $this->memberId = $memberId; $this->memberBoxes = $this->storageBoxRepository->getMemberBoxes($this->memberId); $this->boxPayments = $this->paymentRepository->getStorageBoxPayments($this->memberId); }