2023-09-13 01:42:00 +02:00
< ? php
/**
* Invoice Ninja ( https :// invoiceninja . com ) .
*
* @ link https :// github . com / invoiceninja / invoiceninja source repository
*
2024-04-12 06:15:41 +02:00
* @ copyright Copyright ( c ) 2024. Invoice Ninja LLC ( https :// invoiceninja . com )
2023-09-13 01:42:00 +02:00
*
* @ license https :// www . elastic . co / licensing / elastic - license
*/
namespace App\PaymentDrivers\Stripe\Jobs ;
use App\Models\Company ;
use App\Models\Payment ;
2024-07-24 04:27:09 +02:00
use App\Libraries\MultiDB ;
2023-09-13 01:42:00 +02:00
use App\Models\PaymentHash ;
2024-07-24 04:27:09 +02:00
use App\Services\Email\Email ;
2023-10-26 04:57:44 +02:00
use Illuminate\Bus\Queueable ;
2024-07-24 04:27:09 +02:00
use App\Models\CompanyGateway ;
use App\Services\Email\EmailObject ;
use Illuminate\Support\Facades\App ;
use Illuminate\Mail\Mailables\Address ;
use Illuminate\Queue\SerializesModels ;
use App\PaymentDrivers\Stripe\Utilities ;
use Illuminate\Queue\InteractsWithQueue ;
2023-09-13 01:42:00 +02:00
use Illuminate\Contracts\Queue\ShouldQueue ;
use Illuminate\Foundation\Bus\Dispatchable ;
use Illuminate\Queue\Middleware\WithoutOverlapping ;
class ChargeRefunded implements ShouldQueue
{
2024-01-14 05:05:00 +01:00
use Dispatchable ;
use InteractsWithQueue ;
use Queueable ;
use SerializesModels ;
use Utilities ;
2023-09-13 01:42:00 +02:00
public $tries = 1 ; //number of retries
public $deleteWhenMissingModels = true ;
public $payment_completed = false ;
2024-07-24 04:27:09 +02:00
public function __construct ( public array $stripe_request , private string $company_key )
2023-09-13 01:42:00 +02:00
{
}
public function handle ()
{
MultiDB :: findAndSetDbByCompanyKey ( $this -> company_key );
nlog ( $this -> stripe_request );
$company = Company :: query () -> where ( 'company_key' , $this -> company_key ) -> first ();
$source = $this -> stripe_request [ 'object' ];
$charge_id = $source [ 'id' ];
$amount_refunded = $source [ 'amount_refunded' ] ? ? 0 ;
2024-01-14 05:05:00 +01:00
2023-09-13 01:42:00 +02:00
$payment_hash_key = $source [ 'metadata' ][ 'payment_hash' ] ? ? null ;
2024-08-06 10:21:03 +02:00
if ( is_null ( $payment_hash_key )){
nlog ( " charge.refunded not found " );
return ;
}
2023-09-13 01:42:00 +02:00
$payment_hash = PaymentHash :: query () -> where ( 'hash' , $payment_hash_key ) -> first ();
2024-07-24 04:27:09 +02:00
$company_gateway = $payment_hash -> payment -> company_gateway ;
2023-09-13 01:42:00 +02:00
$stripe_driver = $company_gateway -> driver () -> init ();
$stripe_driver -> payment_hash = $payment_hash ;
/** @var \App\Models\Payment $payment **/
$payment = Payment :: query ()
-> withTrashed ()
-> where ( 'company_id' , $company -> id )
-> where ( 'transaction_reference' , $charge_id )
-> first ();
//don't touch if already refunded
2024-07-24 04:27:09 +02:00
if ( ! $payment || $payment -> status_id == Payment :: STATUS_REFUNDED || $payment -> is_deleted ){
2023-09-13 01:42:00 +02:00
return ;
}
$stripe_driver -> client = $payment -> client ;
$amount_refunded = $stripe_driver -> convertFromStripeAmount ( $amount_refunded , $payment -> client -> currency () -> precision , $payment -> client -> currency ());
if ( $payment -> status_id == Payment :: STATUS_PENDING ) {
$payment -> service () -> deletePayment ();
$payment -> status_id = Payment :: STATUS_FAILED ;
$payment -> save ();
return ;
}
2024-07-24 04:27:09 +02:00
usleep ( rand ( 200000 , 300000 ));
$payment = $payment -> fresh ();
2023-09-13 01:42:00 +02:00
2024-07-24 04:27:09 +02:00
if ( $payment -> status_id == Payment :: STATUS_PARTIALLY_REFUNDED ){
//determine the delta in the refunded amount - how much has already been refunded and only apply the delta.
if ( floatval ( $payment -> refunded ) >= floatval ( $amount_refunded ))
return ;
$amount_refunded -= $payment -> refunded ;
}
2023-09-13 01:42:00 +02:00
$invoice_collection = $payment -> paymentables
2023-10-26 04:57:44 +02:00
-> where ( 'paymentable_type' , 'invoices' )
-> map ( function ( $pivot ) {
2023-09-13 01:42:00 +02:00
return [
2023-10-26 04:57:44 +02:00
'invoice_id' => $pivot -> paymentable_id ,
2023-09-13 01:42:00 +02:00
'amount' => $pivot -> amount - $pivot -> refunded
];
});
if ( $invoice_collection -> count () == 1 && $invoice_collection -> first ()[ 'amount' ] >= $amount_refunded ) {
//If there is only one invoice- and we are refunding _less_ than the amount of the invoice, we can just refund the payment
$invoice_collection = $payment -> paymentables
-> where ( 'paymentable_type' , 'invoices' )
2023-10-26 04:57:44 +02:00
-> map ( function ( $pivot ) use ( $amount_refunded ) {
2023-09-13 01:42:00 +02:00
return [
'invoice_id' => $pivot -> paymentable_id ,
'amount' => $amount_refunded
];
});
2024-07-24 04:27:09 +02:00
}
elseif ( $invoice_collection -> sum ( 'amount' ) != $amount_refunded ) {
$refund_text = " A partial refund was processed for Payment # { $payment_hash -> payment -> number } . <br><br> This payment is associated with multiple invoices, so you will need to manually apply the refund to the correct invoice/s. " ;
App :: setLocale ( $payment_hash -> payment -> company -> getLocale ());
$mo = new EmailObject ();
$mo -> subject = " Refund processed in Stripe for multiple invoices, action required. " ;
$mo -> body = $refund_text ;
$mo -> text_body = $refund_text ;
$mo -> company_key = $payment_hash -> payment -> company -> company_key ;
$mo -> html_template = 'email.template.generic' ;
$mo -> to = [ new Address ( $payment_hash -> payment -> company -> owner () -> email , $payment_hash -> payment -> company -> owner () -> present () -> name ())];
Email :: dispatch ( $mo , $payment_hash -> payment -> company );
2023-09-13 01:42:00 +02:00
return ;
2024-07-24 04:27:09 +02:00
2023-09-13 01:42:00 +02:00
}
2024-01-14 05:05:00 +01:00
2023-09-13 01:42:00 +02:00
$invoices = $invoice_collection -> toArray ();
$data = [
'id' => $payment -> id ,
'amount' => $amount_refunded ,
'invoices' => $invoices ,
'date' => now () -> format ( 'Y-m-d' ),
'gateway_refund' => false ,
'email_receipt' => false ,
2024-07-24 04:27:09 +02:00
'via_webhook' => true ,
2023-09-13 01:42:00 +02:00
];
nlog ( $data );
2024-01-14 05:05:00 +01:00
2023-09-13 01:42:00 +02:00
$payment -> refund ( $data );
2024-07-24 04:27:09 +02:00
$payment -> private_notes .= 'Refunded via Stripe ' ;
$payment -> saveQuietly ();
2023-09-13 01:42:00 +02:00
}
public function middleware ()
{
2024-07-24 04:27:09 +02:00
return [ new WithoutOverlapping ( $this -> company_key )];
2023-09-13 01:42:00 +02:00
}
}