/**
  * 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);
     }
 }
 /**
  * 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
         }
     }
 }
 /**
  * A Bill has been created, these will always start within the system except for subscription payments
  *
  * @param array $bills
  */
 private function processNewBills(array $bills)
 {
     //We have new bills/payment
     foreach ($bills as $bill) {
         //Ignore non subscription payment creations
         if ($bill['source_type'] != 'subscription') {
             continue;
         }
         try {
             //Locate the user through their subscription id
             $user = User::where('payment_method', 'gocardless')->where('subscription_id', $bill['source_id'])->first();
             if (!$user) {
                 \Log::warning("GoCardless new sub payment notification for unmatched user. Bill ID: " . $bill['id']);
                 continue;
             }
             $ref = null;
             $this->paymentRepository->recordSubscriptionPayment($user->id, 'gocardless', $bill['id'], $bill['amount'], $bill['status'], $bill['amount'] - $bill['amount_minus_fees'], $ref);
         } catch (\Exception $e) {
             \Log::error($e);
         }
     }
 }
 /**
  * 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);
         }
     }
 }