mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Working on invoice payments with gateway fees
This commit is contained in:
parent
ac08a146a1
commit
eb867522df
@ -136,7 +136,21 @@ class PaymentController extends Controller
|
||||
$payment_method_id = request()->input('payment_method_id');
|
||||
|
||||
$invoice_totals = array_sum(array_column($payable_invoices,'amount'));
|
||||
$fee_totals = round($gateway->calcGatewayFee($invoice_totals), $invoices->first()->client->currency()->precision);
|
||||
|
||||
$first_invoice = $invoices->first();
|
||||
$fee_totals = round($gateway->calcGatewayFee($invoice_totals, true), $first_invoice->client->currency()->precision);
|
||||
|
||||
if(!$first_invoice->uses_inclusive_taxes) {
|
||||
|
||||
$fee_tax = 0;
|
||||
$fee_tax += round(($first_invoice->tax_rate1/100)*$fee_totals, $first_invoice->client->currency()->precision);
|
||||
$fee_tax += round(($first_invoice->tax_rate2/100)*$fee_totals, $first_invoice->client->currency()->precision);
|
||||
$fee_tax += round(($first_invoice->tax_rate3/100)*$fee_totals, $first_invoice->client->currency()->precision);
|
||||
|
||||
$fee_totals += $fee_tax;
|
||||
}
|
||||
|
||||
$first_invoice->service()->addGatewayFee($gateway, $invoice_totals)->save();
|
||||
|
||||
$payment_hash = new PaymentHash;
|
||||
$payment_hash->hash = Str::random(128);
|
||||
|
@ -267,7 +267,7 @@ class CompanyGateway extends BaseModel
|
||||
return $label;
|
||||
}
|
||||
|
||||
public function calcGatewayFee($amount)
|
||||
public function calcGatewayFee($amount, $include_taxes = false)
|
||||
{
|
||||
|
||||
$fees_and_limits = $this->getFeesAndLimits();
|
||||
@ -286,29 +286,32 @@ class CompanyGateway extends BaseModel
|
||||
$fee += $amount * $fees_and_limits->fee_percent / 100;
|
||||
info("fee after adding fee percent = {$fee}");
|
||||
}
|
||||
|
||||
$pre_tax_fee = $fee;
|
||||
|
||||
//we shouldn't calculate the taxes - they'll be done when we re-process the invoice
|
||||
|
||||
// if ($fees_and_limits->fee_tax_rate1) {
|
||||
// $fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate1 / 100;
|
||||
// info("fee after adding fee tax 1 = {$fee}");
|
||||
// }
|
||||
|
||||
// if ($fees_and_limits->fee_tax_rate2) {
|
||||
// $fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate2 / 100;
|
||||
// info("fee after adding fee tax 2 = {$fee}");
|
||||
// }
|
||||
|
||||
// if ($fees_and_limits->fee_tax_rate3) {
|
||||
// $fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate3 / 100;
|
||||
// info("fee after adding fee tax 3 = {$fee}");
|
||||
// }
|
||||
|
||||
/* Cap fee if we have to here. */
|
||||
if($fees_and_limits->fee_cap > 0 && ($fee > $fees_and_limits->fee_cap))
|
||||
$fee = $fees_and_limits->fee_cap;
|
||||
|
||||
$pre_tax_fee = $fee;
|
||||
|
||||
/**/
|
||||
if($include_taxes)
|
||||
{
|
||||
if ($fees_and_limits->fee_tax_rate1) {
|
||||
$fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate1 / 100;
|
||||
info("fee after adding fee tax 1 = {$fee}");
|
||||
}
|
||||
|
||||
if ($fees_and_limits->fee_tax_rate2) {
|
||||
$fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate2 / 100;
|
||||
info("fee after adding fee tax 2 = {$fee}");
|
||||
}
|
||||
|
||||
if ($fees_and_limits->fee_tax_rate3) {
|
||||
$fee += $pre_tax_fee * $fees_and_limits->fee_tax_rate3 / 100;
|
||||
info("fee after adding fee tax 3 = {$fee}");
|
||||
}
|
||||
}
|
||||
|
||||
return $fee;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
* @param PaymentResponseRequest $request The incoming payment request
|
||||
* @return void Success/Failure
|
||||
*/
|
||||
public function appendGatewayFeeToInvoice(PaymentResponseRequest $request) :void
|
||||
public function confirmGatewayFee(PaymentResponseRequest $request) :void
|
||||
{
|
||||
/*Payment meta data*/
|
||||
$payment_hash = $request->getPaymentHash();
|
||||
@ -175,22 +175,24 @@ class BaseDriver extends AbstractPaymentDriver
|
||||
/*Payment invoices*/
|
||||
$payment_invoices = $payment_hash->invoices();
|
||||
|
||||
/*Fee charged at gateway*/
|
||||
// /*Fee charged at gateway*/
|
||||
$fee_total = $payment_hash->fee_total;
|
||||
|
||||
/*Sum of invoice amounts*/
|
||||
$invoice_totals = array_sum(array_column($payment_invoices,'amount'));
|
||||
// Sum of invoice amounts
|
||||
// $invoice_totals = array_sum(array_column($payment_invoices,'amount'));
|
||||
|
||||
/*Hydrate invoices*/
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))->get();
|
||||
|
||||
/*Append gateway fee to invoice line item of first invoice*/
|
||||
if($fee_total != 0){
|
||||
$invoices->first()->service()->addGatewayFee($this->company_gateway, $invoice_totals)->save();
|
||||
$invoices->each(function($invoice) use($fee_total){
|
||||
|
||||
//We need to update invoice balance / client balance at this point so
|
||||
//that payment record sanity is preserved //todo
|
||||
}
|
||||
if(collect($invoice->line_items)->contains('type_id', '3')){
|
||||
$invoice->service()->toggleFeesPaid()->save();
|
||||
$invoice->client->service()->updateBalance($fee_total)->save();
|
||||
$invoice->ledger()->updateInvoiceBalance($fee_total, $notes = 'Gateway fee adjustment');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ class BasePaymentDriver
|
||||
* @param PaymentResponseRequest $request The incoming payment request
|
||||
* @return void Success/Failure
|
||||
*/
|
||||
public function appendGatewayFeeToInvoice(PaymentResponseRequest $request) :void
|
||||
public function confirmGatewayFee(PaymentResponseRequest $request) :void
|
||||
{
|
||||
/*Payment meta data*/
|
||||
$payment_hash = $request->getPaymentHash();
|
||||
@ -303,22 +303,24 @@ class BasePaymentDriver
|
||||
/*Payment invoices*/
|
||||
$payment_invoices = $payment_hash->invoices();
|
||||
|
||||
/*Fee charged at gateway*/
|
||||
// /*Fee charged at gateway*/
|
||||
$fee_total = $payment_hash->fee_total;
|
||||
|
||||
/*Sum of invoice amounts*/
|
||||
$invoice_totals = array_sum(array_column($payment_invoices,'amount'));
|
||||
// Sum of invoice amounts
|
||||
// $invoice_totals = array_sum(array_column($payment_invoices,'amount'));
|
||||
|
||||
/*Hydrate invoices*/
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))->get();
|
||||
|
||||
/*Append gateway fee to invoice line item of first invoice*/
|
||||
if($fee_total != 0){
|
||||
$invoices->first()->service()->addGatewayFee($this->company_gateway, $invoice_totals)->save();
|
||||
$invoices->each(function($invoice) use($fee_total){
|
||||
|
||||
//We need to update invoice balance / client balance at this point so
|
||||
//that payment record sanity is preserved //todo
|
||||
}
|
||||
if(collect($invoice->line_items)->contains('type_id', '3')){
|
||||
$invoice->service()->toggleFeesPaid()->save();
|
||||
$invoice->client->service()->updateBalance($fee_total)->save();
|
||||
$invoice->ledger()->updateInvoiceBalance($fee_total, $notes = 'Gateway fee adjustment');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ class CreditCard
|
||||
'gateway_type_id' => $request->payment_method_id,
|
||||
'hashed_ids' => $request->hashed_ids,
|
||||
'server_response' => $server_response,
|
||||
'payment_hash' => $payment_hash,
|
||||
];
|
||||
|
||||
$invoices = Invoice::whereIn('id', $this->stripe->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))
|
||||
@ -143,7 +144,7 @@ class CreditCard
|
||||
if ($state['payment_status'] == 'succeeded') {
|
||||
|
||||
/* Add gateway fees if needed! */
|
||||
$this->stripe->appendGatewayFeeToInvoice($request);
|
||||
$this->stripe->confirmGatewayFee($request);
|
||||
|
||||
return $this->processSuccessfulPayment($state);
|
||||
}
|
||||
@ -190,7 +191,7 @@ class CreditCard
|
||||
|
||||
$this->stripe->attachInvoices($payment, $state['hashed_ids']);
|
||||
|
||||
$payment->service()->updateInvoicePayment();
|
||||
$payment->service()->updateInvoicePayment($state['payment_hash']);
|
||||
|
||||
event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
|
||||
|
||||
|
@ -60,7 +60,7 @@ class AddGatewayFee extends AbstractService
|
||||
$invoice_items = $this->invoice->line_items;
|
||||
|
||||
$invoice_items = collect($invoice_items)->filter(function ($item){
|
||||
return $item->type_id != 3;
|
||||
return $item->type_id != '3';
|
||||
});
|
||||
|
||||
$this->invoice->line_items = $invoice_items;
|
||||
@ -71,7 +71,7 @@ class AddGatewayFee extends AbstractService
|
||||
private function processGatewayFee($gateway_fee)
|
||||
{
|
||||
$invoice_item = new InvoiceItem;
|
||||
$invoice_item->type_id = '4';
|
||||
$invoice_item->type_id = '3';
|
||||
$invoice_item->product_key = ctrans('texts.surcharge');
|
||||
$invoice_item->notes = ctrans('texts.online_payment_surcharge');
|
||||
$invoice_item->quantity = 1;
|
||||
@ -92,10 +92,9 @@ class AddGatewayFee extends AbstractService
|
||||
/**Refresh Invoice values*/
|
||||
$this->invoice = $this->invoice->calc()->getInvoice();
|
||||
|
||||
/*Update client balance*/
|
||||
$this->invoice->client->service()->updateBalance($gateway_fee)->save();
|
||||
|
||||
$this->invoice->ledger()->updateInvoiceBalance($gateway_fee, $notes = 'Gateway fee adjustment');
|
||||
/*Update client balance*/ // don't increment until we have process the payment!
|
||||
//$this->invoice->client->service()->updateBalance($gateway_fee)->save();
|
||||
//$this->invoice->ledger()->updateInvoiceBalance($gateway_fee, $notes = 'Gateway fee adjustment');
|
||||
|
||||
return $this->invoice;
|
||||
|
||||
@ -104,7 +103,7 @@ class AddGatewayFee extends AbstractService
|
||||
private function processGatewayDiscount($gateway_fee)
|
||||
{
|
||||
$invoice_item = new InvoiceItem;
|
||||
$invoice_item->type_id = 3;
|
||||
$invoice_item->type_id = '3';
|
||||
$invoice_item->product_key = ctrans('texts.discount');
|
||||
$invoice_item->notes = ctrans('texts.online_payment_discount');
|
||||
$invoice_item->quantity = 1;
|
||||
@ -124,9 +123,9 @@ class AddGatewayFee extends AbstractService
|
||||
|
||||
$this->invoice = $this->invoice->calc()->getInvoice();
|
||||
|
||||
$this->invoice->client->service()->updateBalance($gateway_fee)->save();
|
||||
// $this->invoice->client->service()->updateBalance($gateway_fee)->save();
|
||||
|
||||
$this->invoice->ledger()->updateInvoiceBalance($gateway_fee, $notes = 'Discount fee adjustment');
|
||||
// $this->invoice->ledger()->updateInvoiceBalance($gateway_fee, $notes = 'Discount fee adjustment');
|
||||
|
||||
return $this->invoice;
|
||||
}
|
||||
|
@ -84,9 +84,9 @@ class PaymentService
|
||||
return (new DeletePayment($this->payment))->run();
|
||||
}
|
||||
|
||||
public function updateInvoicePayment() :?Payment
|
||||
public function updateInvoicePayment($payment_hash = null) :?Payment
|
||||
{
|
||||
return ((new UpdateInvoicePayment($this->payment)))->run();
|
||||
return ((new UpdateInvoicePayment($this->payment, $payment_hash)))->run();
|
||||
}
|
||||
|
||||
public function applyNumber()
|
||||
|
@ -17,119 +17,82 @@ use App\Jobs\Payment\EmailPayment;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\SystemLog;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class UpdateInvoicePayment
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/**
|
||||
* @deprecated This is bad logic, assumes too much.
|
||||
*/
|
||||
public $payment;
|
||||
|
||||
public function __construct($payment)
|
||||
public $payment_hash;
|
||||
|
||||
public function __construct($payment, $payment_hash)
|
||||
{
|
||||
$this->payment = $payment;
|
||||
$this->payment_hash = $payment_hash;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$invoices = $this->payment->invoices()->get();
|
||||
// $invoices = $this->payment->invoices()->get();
|
||||
// $invoices_total = $invoices->sum('balance');
|
||||
|
||||
$invoices_total = $invoices->sum('balance');
|
||||
$paid_invoices = $this->payment_hash->invoices();
|
||||
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($paid_invoices, 'invoice_id')))->get();
|
||||
|
||||
/* Simplest scenario - All invoices are paid in full*/
|
||||
if (strval($invoices_total) === strval($this->payment->amount)) {
|
||||
$invoices->each(function ($invoice) {
|
||||
$this->payment
|
||||
->ledger()
|
||||
->updatePaymentBalance($invoice->balance*-1);
|
||||
|
||||
$this->payment->client
|
||||
->service()
|
||||
->updateBalance($invoice->balance*-1)
|
||||
->updatePaidToDate($invoice->balance)
|
||||
->save();
|
||||
|
||||
$invoice->pivot->amount = $invoice->balance;
|
||||
collect($paid_invoices)->each(function ($paid_invoice) use($invoices) {
|
||||
|
||||
$invoice = $invoices->first(function ($inv) use($paid_invoice) {
|
||||
return $paid_invoice['invoice_id'] == $inv->hashed_id;
|
||||
});
|
||||
|
||||
$this->payment
|
||||
->ledger()
|
||||
->updatePaymentBalance($paid_invoice->amount*-1);
|
||||
|
||||
$this->payment
|
||||
->client
|
||||
->service()
|
||||
->updateBalance($paid_invoice->amount*-1)
|
||||
->updatePaidToDate($paid_invoice->amount)
|
||||
->save();
|
||||
|
||||
$invoice->pivot->amount = $paid_invoice->amount;
|
||||
$invoice->pivot->save();
|
||||
|
||||
$invoice->service()
|
||||
$invoice->service() //caution what if we amount paid was less than partial - we wipe it!
|
||||
->clearPartial()
|
||||
->updateBalance($invoice->balance*-1)
|
||||
->updateBalance($paid_invoice->amount*-1)
|
||||
->save();
|
||||
});
|
||||
}
|
||||
/*Combination of partials and full invoices are being paid*/
|
||||
else {
|
||||
$total = 0;
|
||||
|
||||
/* Calculate the grand total of the invoices*/
|
||||
foreach ($invoices as $invoice) {
|
||||
if ($invoice->hasPartial()) {
|
||||
$total += $invoice->partial;
|
||||
} else {
|
||||
$total += $invoice->balance;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*Test if there is a batch of partial invoices that have been paid */
|
||||
if ($this->payment->amount == $total) {
|
||||
$invoices->each(function ($invoice) {
|
||||
if ($invoice->hasPartial()) {
|
||||
$this->payment
|
||||
->ledger()
|
||||
->updatePaymentBalance($invoice->partial*-1);
|
||||
// } else {
|
||||
// SystemLogger::dispatch(
|
||||
// [
|
||||
// 'payment' => $this->payment,
|
||||
// 'invoices' => $invoices,
|
||||
// 'invoices_total' => $invoices_total,
|
||||
// 'payment_amount' => $this->payment->amount,
|
||||
// 'partial_check_amount' => $total,
|
||||
// ],
|
||||
// SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
// SystemLog::EVENT_PAYMENT_RECONCILIATION_FAILURE,
|
||||
// SystemLog::TYPE_LEDGER,
|
||||
// $this->payment->client
|
||||
// );
|
||||
|
||||
$this->payment->client->service()
|
||||
->updateBalance($invoice->partial*-1)
|
||||
->updatePaidToDate($invoice->partial)
|
||||
->save();
|
||||
// throw new \Exception("payment amount {$this->payment->amount} does not match invoice totals {$invoices_total} reversing payment");
|
||||
|
||||
$invoice->pivot->amount = $invoice->partial;
|
||||
$invoice->pivot->save();
|
||||
|
||||
$invoice->service()->updateBalance($invoice->partial*-1)
|
||||
->clearPartial()
|
||||
->setDueDate()
|
||||
->setStatus(Invoice::STATUS_PARTIAL)
|
||||
->save();
|
||||
} else {
|
||||
$this->payment
|
||||
->ledger()
|
||||
->updatePaymentBalance($invoice->balance*-1);
|
||||
|
||||
$this->payment->client->service()
|
||||
->updateBalance($invoice->balance*-1)
|
||||
->updatePaidToDate($invoice->balance)
|
||||
->save();
|
||||
|
||||
$invoice->pivot->amount = $invoice->balance;
|
||||
$invoice->pivot->save();
|
||||
|
||||
$invoice->service()->clearPartial()->updateBalance($invoice->balance*-1)->save();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
SystemLogger::dispatch(
|
||||
[
|
||||
'payment' => $this->payment,
|
||||
'invoices' => $invoices,
|
||||
'invoices_total' => $invoices_total,
|
||||
'payment_amount' => $this->payment->amount,
|
||||
'partial_check_amount' => $total,
|
||||
],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_PAYMENT_RECONCILIATION_FAILURE,
|
||||
SystemLog::TYPE_LEDGER,
|
||||
$this->payment->client
|
||||
);
|
||||
|
||||
throw new \Exception("payment amount {$this->payment->amount} does not match invoice totals {$invoices_total} reversing payment");
|
||||
|
||||
$this->payment->invoice()->delete();
|
||||
$this->payment->is_deleted=true;
|
||||
$this->payment->save();
|
||||
$this->payment->delete();
|
||||
}
|
||||
// $this->payment->invoice()->delete();
|
||||
// $this->payment->is_deleted=true;
|
||||
// $this->payment->save();
|
||||
// $this->payment->delete();
|
||||
// }
|
||||
}
|
||||
|
||||
return $this->payment;
|
||||
|
Loading…
x
Reference in New Issue
Block a user