diff --git a/app/Jobs/Company/UpdateCompanyLedgerWithInvoice.php b/app/Jobs/Company/UpdateCompanyLedgerWithInvoice.php index eb9f117bd768..df19f208ff8d 100644 --- a/app/Jobs/Company/UpdateCompanyLedgerWithInvoice.php +++ b/app/Jobs/Company/UpdateCompanyLedgerWithInvoice.php @@ -46,8 +46,7 @@ class UpdateCompanyLedgerWithInvoice */ public function handle() { - \Log::error('in update company ledger with invoice'); - + $balance = 0; $ledger = CompanyLedger::whereClientId($this->invoice->client_id) @@ -60,7 +59,6 @@ class UpdateCompanyLedgerWithInvoice $adjustment = $balance + $this->adjustment; - \Log::error("adjusting balance {$balance} to {$adjustment}"); $company_ledger = CompanyLedgerFactory::create($this->invoice->company_id, $this->invoice->user_id); $company_ledger->client_id = $this->invoice->client_id; diff --git a/app/Listeners/Invoice/UpdateInvoiceInvitations.php b/app/Listeners/Invoice/UpdateInvoiceInvitations.php new file mode 100644 index 000000000000..77ee926c71f5 --- /dev/null +++ b/app/Listeners/Invoice/UpdateInvoiceInvitations.php @@ -0,0 +1,54 @@ +payment; + $invoices = $payment->invoices; + + + /** + * Move this into an event + */ + $invoices->each(function ($invoice) use($payment) { + + $invoice->status_id = Invoice::STATUS_PAID; + $invoice->save(); + $invoice->invitations()->update(['transaction_reference' => $payment->transaction_reference]); + + }); + + } +} diff --git a/app/Listeners/Invoice/UpdateInvoicePayment.php b/app/Listeners/Invoice/UpdateInvoicePayment.php index 2d315bdf6fdf..7bfcb37a7ab1 100644 --- a/app/Listeners/Invoice/UpdateInvoicePayment.php +++ b/app/Listeners/Invoice/UpdateInvoicePayment.php @@ -14,11 +14,14 @@ namespace App\Listeners\Invoice; use App\Jobs\Company\UpdateCompanyLedgerWithInvoice; use App\Jobs\Company\UpdateCompanyLedgerWithPayment; use App\Models\SystemLog; +use App\Utils\Traits\SystemLogTrait; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; class UpdateInvoicePayment implements ShouldQueue { + use SystemLogTrait; + /** * Create the event listener. * @@ -44,17 +47,17 @@ class UpdateInvoicePayment implements ShouldQueue /* Simplest scenario*/ if($invoices_total == $payment->amount) { - \Log::error("invoice totals match payment amount"); $invoices->each(function ($invoice) use($payment){ - //$invoice->updateBalance($invoice->balance*-1); - //UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, ($invoice->balance*-1)); + UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($invoice->balance*-1)); + $invoice->clearPartial(); $invoice->updateBalance($invoice->balance*-1); + }); } else { - \Log::error("invoice totals don't match, search for partials"); + $total = 0; foreach($invoice as $invoice) @@ -71,12 +74,29 @@ class UpdateInvoicePayment implements ShouldQueue /* test if there is a batch of partial invoices that have been paid */ if($payment->amount == $total) { - //process invoices and update balance depending on - //whether the invoice balance or partial amount was - //paid + + $invoices->each(function ($invoice) use($payment){ + + if($invoice->isPartial()) { + + UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($invoice->partial*-1)); + $invoice->updateBalance($invoice->partial*-1); + $invoice->clearPartial(); + $invoice->setDueDate(); + //todo do we need to mark it as a partial? + } + else + { + UpdateCompanyLedgerWithPayment::dispatchNow($payment, ($invoice->balance*-1)); + $invoice->clearPartial(); + $invoice->updateBalance($invoice->balance*-1); + } + + }); + } else { - \Log::error("no matches, fail"); + $data = [ 'payment' => $payment, 'invoices' => $invoices, @@ -85,16 +105,8 @@ class UpdateInvoicePayment implements ShouldQueue 'partial_check_amount' => $total, ]; - $sl = [ - 'client_id' => $payment->client_id, - 'user_id' => $payment->user_id, - 'company_id' => $payment->company_id, - 'log' => $data, - 'category_id' => SystemLog::PAYMENT_RESPONSE, - 'event_id' => SystemLog::PAYMENT_RECONCILIATION_FAILURE, - ]; - SystemLog::create($sl); + $this->sysLog($data, SystemLog::GATEWAY_RESPONSE, SystemLog::PAYMENT_RECONCILIATION_FAILURE); throw new Exception('payment amount does not match invoice totals'); } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 57e081518e02..041b26054a72 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -15,6 +15,7 @@ use App\Events\Invoice\InvoiceWasUpdated; use App\Helpers\Invoice\InvoiceCalc; use App\Models\Currency; use App\Models\Filterable; +use App\Models\PaymentTerm; use App\Utils\Number; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesInvoiceValues; @@ -302,6 +303,17 @@ class Invoice extends BaseModel //return $this->status_id >= self::STATUS_PARTIAL; } + /** + * Clear partial fields + * @return void + */ + public function clearPartial() : void + { + $this->partial = null; + $this->partial_due_date = null; + $this->save(); + } + /** * @param float $balance_adjustment */ @@ -322,4 +334,11 @@ class Invoice extends BaseModel $this->save(); \Log::error('finished updatingoice balance'); } + + public function setDueDate() + { + + $this->due_date = Carbon::now()->addDays(PaymentTerm::find($this->company->settings->payment_terms_id)->num_days); + $this->save(); + } } \ No newline at end of file diff --git a/app/Models/SystemLog.php b/app/Models/SystemLog.php index 1e0c1a3e22ac..78c01399b9a8 100644 --- a/app/Models/SystemLog.php +++ b/app/Models/SystemLog.php @@ -16,8 +16,7 @@ use Illuminate\Database\Eloquent\Model; class SystemLog extends Model { /* Category IDs */ - const PAYMENT_RESPONSE = 1; - const GATEWAY_RESPONSE = 2; + const GATEWAY_RESPONSE = 1; /* Event IDs*/ const PAYMENT_RECONCILIATION_FAILURE = 10; diff --git a/app/PaymentDrivers/BasePaymentDriver.php b/app/PaymentDrivers/BasePaymentDriver.php index 4c95dc199fa5..1b3e554e4026 100644 --- a/app/PaymentDrivers/BasePaymentDriver.php +++ b/app/PaymentDrivers/BasePaymentDriver.php @@ -64,9 +64,13 @@ class BasePaymentDriver public function __construct(CompanyGateway $company_gateway, Client $client, $invitation = false) { + $this->company_gateway = $company_gateway; + $this->invitation = $invitation; + $this->client = $client; + } /** @@ -175,27 +179,16 @@ class BasePaymentDriver acceptNotification() - convert an incoming request from an off-site gateway to a generic notification object for further processing */ - protected function paymentDetails($input) + protected function paymentDetails($input) : array { - // $gatewayTypeAlias = $this->gatewayType == GatewayType::TOKEN ? $this->gatewayType : GatewayType::getAliasFromId($this->gatewayType); $data = [ 'currency' => $this->client->getCurrencyCode(), 'transactionType' => 'Purchase', 'clientIp' => request()->getClientIp(), ]; -/* - if ($paymentMethod) { - if ($this->customerReferenceParam) { - $data[$this->customerReferenceParam] = $paymentMethod->account_gateway_token->token; - } - $data[$this->sourceReferenceParam] = $paymentMethod->source_reference; - } elseif ($this->input) { - $data['card'] = new CreditCard($this->paymentDetailsFromInput($this->input)); - } else { - $data['card'] = new CreditCard($this->paymentDetailsFromClient()); - } -*/ + + return $data; } @@ -208,17 +201,7 @@ class BasePaymentDriver ->setItems($items) ->send(); - - if ($response->isRedirect()) { - // redirect to offsite payment gateway - $response->redirect(); - } elseif ($response->isSuccessful()) { - // payment was successful: update database - print_r($response); - } else { - // payment failed: display message to customer - echo $response->getMessage(); - } + return $response; /* $this->purchaseResponse = (array)$response->getData();*/ } @@ -232,7 +215,7 @@ class BasePaymentDriver ->send(); } - public function createPayment($data) + public function createPayment($data) : Payment { $payment = PaymentFactory::create($this->client->company->id, $this->client->user->id); @@ -246,7 +229,7 @@ class BasePaymentDriver } - public function attachInvoices(Payment $payment, $hashed_ids) + public function attachInvoices(Payment $payment, $hashed_ids) : Payment { $invoices = Invoice::whereIn('id', $this->transformKeys(explode(",",$hashed_ids))) ->whereClientId($this->client->id) diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php index 27dee0cf635a..b95944ac94d4 100644 --- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php +++ b/app/PaymentDrivers/PayPalExpressPaymentDriver.php @@ -14,6 +14,7 @@ namespace App\PaymentDrivers; use App\Events\Payment\PaymentWasCreated; use App\Models\ClientGatewayToken; use App\Models\GatewayType; +use App\Models\Payment; use App\Models\PaymentType; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; @@ -90,7 +91,28 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver */ public function processPaymentView(array $data) { - $this->purchase($this->paymentDetails($data), $this->paymentItems($data)); + $response = $this->purchase($this->paymentDetails($data), $this->paymentItems($data)); + + + if ($response->isRedirect()) { + // redirect to offsite payment gateway + $response->redirect(); + } elseif ($response->isSuccessful()) { + // payment was successful: update database + /* for this driver this method wont be hit*/ + } else { + // payment failed: display message to customer + + $log = [ + 'server_response' => $response->getData(), + 'data' => $data + ]; + + $this->sysLog($log); + + throw new Exception("Error Processing Payment", 1); + + } } public function processPaymentResponse($request) @@ -103,6 +125,14 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver if ($response->isCancelled()) { return redirect()->route('client.invoices.index')->with('warning',ctrans('texts.status_voided')); } elseif (! $response->isSuccessful()) { + + $data = [ + 'request' => $request->all(), + 'server_response' => $response->getData() + ]; + + $this->sysLog($data); + throw new Exception($response->getMessage()); } @@ -211,7 +241,7 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver return $items; } - public function createPayment($data) + public function createPayment($data) : Payment { $payment = parent::createPayment($data); diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index ee0520894247..427309d512cf 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -18,7 +18,6 @@ use App\Models\GatewayType; use App\Models\Invoice; use App\Models\Payment; use App\Models\PaymentType; -use App\Models\SystemLog; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; use Illuminate\Support\Carbon; @@ -231,6 +230,7 @@ class StripePaymentDriver extends BasePaymentDriver $data['intent'] = $this->createPaymentIntent($payment_intent_data); + $data['gateway'] = $this; return view($this->viewForType($data['payment_method_id']), $data); @@ -362,17 +362,6 @@ class StripePaymentDriver extends BasePaymentDriver event(new PaymentWasCreated($payment)); - /** - * Move this into an event - */ - $invoices->each(function ($invoice) use($payment) { - - $invoice->status_id = Invoice::STATUS_PAID; - $invoice->save(); - $invoice->invitations()->update(['transaction_reference' => $payment->transaction_reference]); - - }); - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); @@ -386,16 +375,7 @@ class StripePaymentDriver extends BasePaymentDriver 'invoices' => $invoices, ]; - $sl = [ - 'company_id' => $this->client->company->id, - 'client_id' => $this->client->id, - 'user_id' => $this->client->user_id, - 'log' => $log, - 'category_id' => SystemLog::GATEWAY_RESPONSE, - 'event_id' => SystemLog::GATEWAY_FAILURE, - ]; - - SystemLog::create($sl); + $this->sysLog($log); throw new Exception("Failed to process payment", 1); diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index c674a9ba103e..4660214e0ac9 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -26,6 +26,7 @@ use App\Listeners\Invoice\CreateInvoiceActivity; use App\Listeners\Invoice\CreateInvoiceInvitation; use App\Listeners\Invoice\CreateInvoicePdf; use App\Listeners\Invoice\UpdateInvoiceActivity; +use App\Listeners\Invoice\UpdateInvoiceInvitations; use App\Listeners\Invoice\UpdateInvoicePayment; use App\Listeners\SendVerificationNotification; use App\Listeners\User\UpdateUserLastLogin; @@ -56,6 +57,7 @@ class EventServiceProvider extends ServiceProvider PaymentWasCreated::class => [ PaymentCreatedActivity::class, UpdateInvoicePayment::class, + UpdateInvoiceInvitations::class, ], 'App\Events\ClientWasArchived' => [ 'App\Listeners\ActivityListener@archivedClient', diff --git a/app/Utils/Traits/SystemLogTrait.php b/app/Utils/Traits/SystemLogTrait.php new file mode 100644 index 000000000000..5b3fd65707db --- /dev/null +++ b/app/Utils/Traits/SystemLogTrait.php @@ -0,0 +1,39 @@ + $this->client->id, + 'company_id' => $this->client->company->id, + 'user_id' => $this->client->user_id, + 'log' => $log, + 'category_id' => $category_id, + 'event_id' => $event_id, + ]; + + SystemLog::create($sl); + + } + +} \ No newline at end of file