mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 13:47:32 -04:00 
			
		
		
		
	
						commit
						2fe5d6feba
					
				| @ -1 +1 @@ | ||||
| 5.3.49 | ||||
| 5.3.51 | ||||
| @ -76,7 +76,24 @@ class GmailTransport extends Transport | ||||
| 
 | ||||
|         }  | ||||
| 
 | ||||
|         $this->gmail->send(); | ||||
|         /** | ||||
|          * Google is very strict with their | ||||
|          * sending limits, if we hit 429s, sleep and | ||||
|          * retry again later. | ||||
|          */ | ||||
|         try{ | ||||
| 
 | ||||
|             $this->gmail->send(); | ||||
| 
 | ||||
|         } | ||||
|         catch(\Google\Service\Exception $e) | ||||
|         { | ||||
|             nlog("gmail exception"); | ||||
|             nlog($e->getErrors()); | ||||
| 
 | ||||
|             sleep(5); | ||||
|             $this->gmail->send(); | ||||
|         } | ||||
| 
 | ||||
|         $this->sendPerformed($message); | ||||
| 
 | ||||
|  | ||||
| @ -152,6 +152,7 @@ class ContactLoginController extends Controller | ||||
|     public function logout() | ||||
|     { | ||||
|         Auth::guard('contact')->logout(); | ||||
|         request()->session()->invalidate(); | ||||
| 
 | ||||
|         return redirect('/client/login'); | ||||
|     } | ||||
|  | ||||
| @ -98,6 +98,7 @@ class InvitationController extends Controller | ||||
|             $client_contact->email = Str::random(15) . "@example.com"; $client_contact->save(); | ||||
| 
 | ||||
|         if (request()->has('client_hash') && request()->input('client_hash') == $invitation->contact->client->client_hash) { | ||||
|             request()->session()->invalidate(); | ||||
|             auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||
| 
 | ||||
|         } elseif ((bool) $invitation->contact->client->getSetting('enable_client_portal_password') !== false) { | ||||
| @ -106,6 +107,7 @@ class InvitationController extends Controller | ||||
| 
 | ||||
|         } else { | ||||
|             nlog("else - default - login contact"); | ||||
|             request()->session()->invalidate(); | ||||
|             auth()->guard('contact')->loginUsingId($client_contact->id, true); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -90,12 +90,15 @@ class PaymentController extends Controller | ||||
| 
 | ||||
|     public function response(PaymentResponseRequest $request) | ||||
|     { | ||||
|          | ||||
|         $gateway = CompanyGateway::findOrFail($request->input('company_gateway_id')); | ||||
| 
 | ||||
|         $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->payment_hash])->first(); | ||||
|         $payment_hash = PaymentHash::where('hash', $request->payment_hash)->first(); | ||||
|         $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id); | ||||
|         $client = $invoice ? $invoice->client : auth()->user()->client; | ||||
| 
 | ||||
|             return $gateway | ||||
|                 ->driver(auth()->user()->client) | ||||
|                 // ->driver(auth()->user()->client)
 | ||||
|                 ->driver($client) | ||||
|                 ->setPaymentMethod($request->input('payment_method_id')) | ||||
|                 ->setPaymentHash($payment_hash) | ||||
|                 ->checkRequirements() | ||||
|  | ||||
| @ -401,7 +401,7 @@ class DesignController extends BaseController | ||||
|         } | ||||
| 
 | ||||
|         $design->design = $d; | ||||
|         $design->save(); | ||||
|        // $design->save();
 | ||||
| 
 | ||||
| /* | ||||
|  This is required as the base template does not know to inject the table elements  | ||||
|  | ||||
| @ -18,6 +18,7 @@ use App\Factory\CloneQuoteToInvoiceFactory; | ||||
| use App\Factory\QuoteFactory; | ||||
| use App\Filters\QuoteFilters; | ||||
| use App\Http\Requests\Quote\ActionQuoteRequest; | ||||
| use App\Http\Requests\Quote\BulkActionQuoteRequest; | ||||
| use App\Http\Requests\Quote\CreateQuoteRequest; | ||||
| use App\Http\Requests\Quote\DestroyQuoteRequest; | ||||
| use App\Http\Requests\Quote\EditQuoteRequest; | ||||
| @ -510,7 +511,7 @@ class QuoteController extends BaseController | ||||
|      *       ), | ||||
|      *     ) | ||||
|      */ | ||||
|     public function bulk() | ||||
|     public function bulk(BulkActionQuoteRequest $request) | ||||
|     { | ||||
|         $action = request()->input('action'); | ||||
| 
 | ||||
|  | ||||
| @ -454,6 +454,7 @@ class BillingPortalPurchase extends Component | ||||
| 
 | ||||
|         $contact = ClientContact::query() | ||||
|             ->where('email', $this->email) | ||||
|             ->where('company_id', $this->subscription->company_id) | ||||
|             ->first(); | ||||
| 
 | ||||
|         $mailer = new NinjaMailerObject(); | ||||
|  | ||||
| @ -37,6 +37,7 @@ class ContactKeyLogin | ||||
|     { | ||||
|         if (Auth::guard('contact')->check()) { | ||||
|             Auth::guard('contact')->logout(); | ||||
|             $request->session()->invalidate(); | ||||
|         } | ||||
| 
 | ||||
|         if ($request->segment(2) && $request->segment(2) == 'magic_link' && $request->segment(3)) { | ||||
|  | ||||
| @ -35,7 +35,7 @@ class SessionDomains | ||||
| 
 | ||||
|         if (strpos($domain_name, 'invoicing.co') !== false)  | ||||
|         { | ||||
|             config(['session.domain' => '.invoicing.co']); | ||||
|             // config(['session.domain' => '.invoicing.co']);
 | ||||
|         }             | ||||
|         else{ | ||||
| 
 | ||||
|  | ||||
| @ -34,10 +34,10 @@ class UpdateExpenseRequest extends Request | ||||
|     public function rules() | ||||
|     { | ||||
|         /* Ensure we have a client name, and that all emails are unique*/ | ||||
|         $rules = []; | ||||
|         // $rules['country_id'] = 'integer|nullable';
 | ||||
| 
 | ||||
|         $rules['country_id'] = 'integer|nullable'; | ||||
| 
 | ||||
|         $rules['contacts.*.email'] = 'nullable|distinct'; | ||||
|         // $rules['contacts.*.email'] = 'nullable|distinct';
 | ||||
| 
 | ||||
|         if (isset($this->number)) { | ||||
|             $rules['number'] = Rule::unique('expenses')->where('company_id', auth()->user()->company()->id)->ignore($this->expense->id); | ||||
|  | ||||
							
								
								
									
										41
									
								
								app/Http/Requests/Quote/BulkActionQuoteRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/Http/Requests/Quote/BulkActionQuoteRequest.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com). | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://www.elastic.co/licensing/elastic-license | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Http\Requests\Quote; | ||||
| 
 | ||||
| use App\Http\Requests\Request; | ||||
| use App\Http\ValidationRules\Quote\ConvertableQuoteRule; | ||||
| 
 | ||||
| class BulkActionQuoteRequest extends Request | ||||
| { | ||||
|     /** | ||||
|      * Determine if the user is authorized to make this request. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function authorize() : bool | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     public function rules() | ||||
|     { | ||||
|         $input = $this->all(); | ||||
| 
 | ||||
|         $rules = []; | ||||
| 
 | ||||
|         if($input['action'] == 'convert_to_invoice') | ||||
|             $rules['action'] = [new ConvertableQuoteRule()];  | ||||
| 
 | ||||
|         return $rules; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -74,6 +74,7 @@ class PaymentAppliedValidAmount implements Rule | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return  $payment_amounts >= $invoice_amounts; | ||||
|         // nlog("{round($payment_amounts,3)} >= {round($invoice_amounts,3)}");
 | ||||
|         return  round($payment_amounts,3) >= round($invoice_amounts,3); | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										67
									
								
								app/Http/ValidationRules/Quote/ConvertableQuoteRule.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								app/Http/ValidationRules/Quote/ConvertableQuoteRule.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Quote Ninja (https://quoteninja.com). | ||||
|  * | ||||
|  * @link https://github.com/quoteninja/quoteninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2021. Quote Ninja LLC (https://quoteninja.com) | ||||
|  * | ||||
|  * @license https://www.elastic.co/licensing/elastic-license | ||||
|  */ | ||||
| 
 | ||||
| namespace App\Http\ValidationRules\Quote; | ||||
| 
 | ||||
| use App\Models\Quote; | ||||
| use App\Utils\Traits\MakesHash; | ||||
| use Illuminate\Contracts\Validation\Rule; | ||||
| 
 | ||||
| /** | ||||
|  * Class ConvertableQuoteRule. | ||||
|  */ | ||||
| class ConvertableQuoteRule implements Rule | ||||
| { | ||||
|     use MakesHash; | ||||
| 
 | ||||
|     public function __construct() | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param string $attribute | ||||
|      * @param mixed $value | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function passes($attribute, $value) | ||||
|     { | ||||
|         return $this->checkQuoteIsConvertable(); //if it exists, return false!
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return string | ||||
|      */ | ||||
|     public function message() | ||||
|     { | ||||
|         return ctrans('texts.quote_has_expired'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return bool | ||||
|      */ | ||||
|     private function checkQuoteIsConvertable() : bool | ||||
|     { | ||||
|         $ids = request()->input('ids'); | ||||
| 
 | ||||
|         $quotes = Quote::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get(); | ||||
| 
 | ||||
|         foreach($quotes as $quote){ | ||||
| 
 | ||||
|             if(!$quote->service()->isConvertable()) | ||||
|                 return false; | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| @ -45,7 +45,7 @@ class InvoiceTransformer extends BaseTransformer { | ||||
| 			'client_id'         => $this->getClient( $this->getString( $invoice_data, 'client.name' ), $this->getString( $invoice_data, 'client.email' ) ), | ||||
| 			'discount'          => $this->getFloat( $invoice_data, 'invoice.discount' ), | ||||
| 			'po_number'         => $this->getString( $invoice_data, 'invoice.po_number' ), | ||||
| 			'date'              => isset( $invoice_data['invoice.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.date'] ) ) : null, | ||||
| 			'date'              => isset( $invoice_data['invoice.date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.date'] ) ) : now()->format('Y-m-d'), | ||||
| 			'due_date'          => isset( $invoice_data['invoice.due_date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['invoice.due_date'] ) ) : null, | ||||
| 			'terms'             => $this->getString( $invoice_data, 'invoice.terms' ), | ||||
| 			'public_notes'      => $this->getString( $invoice_data, 'invoice.public_notes' ), | ||||
| @ -72,7 +72,7 @@ class InvoiceTransformer extends BaseTransformer { | ||||
| 			'status_id'         => $invoiceStatusMap[ $status = | ||||
| 					strtolower( $this->getString( $invoice_data, 'invoice.status' ) ) ] ?? | ||||
| 				Invoice::STATUS_SENT, | ||||
| 			'viewed'            => $status === 'viewed', | ||||
| 			// 'viewed'            => $status === 'viewed',
 | ||||
| 			'archived'          => $status === 'archived', | ||||
| 		]; | ||||
| 
 | ||||
|  | ||||
| @ -35,7 +35,8 @@ class InvoiceTransformer extends BaseTransformer { | ||||
| 			'company_id'  => $this->maps['company']->id, | ||||
| 			'client_id'   => $this->getClient( $customer_name = $this->getString( $invoice_data, 'Customer' ), null ), | ||||
| 			'number'      => $invoice_number = $this->getString( $invoice_data, 'Invoice Number' ), | ||||
| 			'date'        => isset( $invoice_data['Invoice Date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['Transaction Date'] ) ) : null, | ||||
| 			'date'        => date( 'Y-m-d', strtotime( $invoice_data['Transaction Date'] ) ) ?: now()->format('Y-m-d'), //27-01-2022
 | ||||
| 			// 'date'        => isset( $invoice_data['Invoice Date'] ) ? date( 'Y-m-d', strtotime( $invoice_data['Transaction Date'] ) ) : null,
 | ||||
| 			'currency_id' => $this->getCurrencyByCode( $invoice_data, 'Currency' ), | ||||
| 			'status_id'   => Invoice::STATUS_SENT, | ||||
| 		]; | ||||
|  | ||||
| @ -1381,7 +1381,13 @@ class CompanyImport implements ShouldQueue | ||||
|                 $new_obj->company_id = $this->company->id; | ||||
|                 $new_obj->fill($obj_array); | ||||
|                 $new_obj->save(['timestamps' => false]); | ||||
|                 $new_obj->number = $this->getNextRecurringExpenseNumber($client = Client::find($obj_array['client_id']), $new_obj);    | ||||
|                 $new_obj->number = $this->getNextRecurringExpenseNumber($new_obj);    | ||||
|             } | ||||
|             elseif($class == 'App\Models\CompanyLedger'){ | ||||
|                 $new_obj = $class::firstOrNew( | ||||
|                         [$match_key => $obj->{$match_key}, 'company_id' => $this->company->id], | ||||
|                         $obj_array, | ||||
|                     ); | ||||
|             } | ||||
|             else{ | ||||
|                 $new_obj = $class::withTrashed()->firstOrNew( | ||||
|  | ||||
| @ -211,15 +211,15 @@ class NinjaMailerJob implements ShouldQueue | ||||
|             } | ||||
| 
 | ||||
|                 //17-01-2022 - ensure we have a token otherwise we fail gracefully to default sending engine
 | ||||
|                 if(strlen($user->oauth_user_token) == 0){ | ||||
|                     $this->nmo->settings->email_sending_method = 'default'; | ||||
|                     return $this->setMailDriver(); | ||||
|                 } | ||||
|                 // if(strlen($user->oauth_user_token) == 0){
 | ||||
|                 //     $this->nmo->settings->email_sending_method = 'default';
 | ||||
|                 //     return $this->setMailDriver();
 | ||||
|                 // }
 | ||||
| 
 | ||||
|             $google->getClient()->setAccessToken(json_encode($user->oauth_user_token)); | ||||
| 
 | ||||
|             //need to slow down gmail requests otherwise we hit 429's
 | ||||
|             sleep(rand(1,3)); | ||||
|             sleep(rand(2,6)); | ||||
|         } | ||||
|         catch(\Exception $e) { | ||||
|             $this->logMailError('Gmail Token Invalid', $this->company->clients()->first()); | ||||
|  | ||||
| @ -97,7 +97,7 @@ class Gateway extends StaticModel | ||||
|                 ]; | ||||
|             case 15: | ||||
|                 return [ | ||||
|                     GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false] | ||||
|                     GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false] | ||||
|                 ]; //Paypal
 | ||||
|                 break; | ||||
|             case 20: | ||||
| @ -140,15 +140,15 @@ class Gateway extends StaticModel | ||||
|                     GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable','charge.succeeded']], | ||||
|                     GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], | ||||
|                     GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false], | ||||
|                     GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], //Stripe
 | ||||
|                     GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::PRZELEWY24 => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']], | ||||
|                     GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], //Stripe
 | ||||
|                     GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::PRZELEWY24 => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::GIROPAY => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                     GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded','payment_intent.succeeded']], | ||||
|                 ]; | ||||
|                 break; | ||||
|             case 57: | ||||
|  | ||||
| @ -13,6 +13,7 @@ namespace App\Models; | ||||
| 
 | ||||
| use App\Events\Payment\PaymentWasRefunded; | ||||
| use App\Events\Payment\PaymentWasVoided; | ||||
| use App\Models\GatewayType; | ||||
| use App\Services\Ledger\LedgerService; | ||||
| use App\Services\Payment\PaymentService; | ||||
| use App\Utils\Ninja; | ||||
| @ -148,6 +149,11 @@ class Payment extends BaseModel | ||||
|         return $this->belongsTo(PaymentType::class); | ||||
|     } | ||||
| 
 | ||||
|     public function gateway_type() | ||||
|     { | ||||
|         return $this->belongsTo(GatewayType::class); | ||||
|     } | ||||
| 
 | ||||
|     public function paymentables() | ||||
|     { | ||||
|         return $this->hasMany(Paymentable::class); | ||||
|  | ||||
| @ -156,7 +156,8 @@ class AuthorizePaymentMethod | ||||
|         $paymentOne = new PaymentType(); | ||||
|         $paymentOne->setOpaqueData($op); | ||||
| 
 | ||||
|         $contact = $this->authorize->client->primary_contact()->first(); | ||||
|         $contact = $this->authorize->client->primary_contact()->first() ?: $this->authorize->client->contacts()->first(); | ||||
| 
 | ||||
|         $billto = false; | ||||
|          | ||||
|         if ($contact) { | ||||
|  | ||||
| @ -418,12 +418,15 @@ class BaseDriver extends AbstractPaymentDriver | ||||
|         throw new PaymentFailed($error, $e->getCode()); | ||||
|     } | ||||
| 
 | ||||
|     public function sendFailureMail($error = '') | ||||
|     public function sendFailureMail($error) | ||||
|     { | ||||
| 
 | ||||
|         if (!is_null($this->payment_hash)) { | ||||
|             $this->unWindGatewayFees($this->payment_hash); | ||||
|         } | ||||
| 
 | ||||
|         if(!$error) | ||||
|             $error = ''; | ||||
|          | ||||
|         PaymentFailedMailer::dispatch( | ||||
|             $this->payment_hash, | ||||
|  | ||||
| @ -143,6 +143,10 @@ class ACSS | ||||
|             'payment_method_types' => ['acss_debit'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::ACSS, | ||||
|             ], | ||||
|             'payment_method_options' => [ | ||||
|                 'acss_debit' => [ | ||||
|                     'mandate_options' => [ | ||||
| @ -150,7 +154,6 @@ class ACSS | ||||
|                         'interval_description' => 'when any invoice becomes due', | ||||
|                         'transaction_type' => 'personal' // TODO: check if is company or personal https://stripe.com/docs/payments/acss-debit
 | ||||
|                     ], | ||||
|                     'currency' => $this->stripe->client->currency()->code, | ||||
|                 ] | ||||
|             ] | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
|  | ||||
| @ -48,6 +48,10 @@ class ApplePay | ||||
|         $data['intent'] =  \Stripe\PaymentIntent::create([ | ||||
|                               'amount' => $data['stripe_amount'], | ||||
|                               'currency' => $this->stripe_driver->client->getCurrencyCode(), | ||||
|                               'metadata' => [ | ||||
|                                     'payment_hash' => $this->stripe_driver->payment_hash->hash, | ||||
|                                     'gateway_type_id' => GatewayType::APPLE_PAY, | ||||
|                                 ], | ||||
|                             ], $this->stripe_driver->stripe_connect_auth); | ||||
| 
 | ||||
|         $this->stripe_driver->payment_hash->data = array_merge((array) $this->stripe_driver->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]); | ||||
|  | ||||
| @ -56,7 +56,10 @@ class BECS | ||||
|             'setup_future_usage' => 'off_session', | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::BECS, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -52,6 +52,10 @@ class Bancontact | ||||
|             'payment_method_types' => ['bancontact'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::BANCONTACT, | ||||
|             ], | ||||
| 
 | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|  | ||||
| @ -71,6 +71,10 @@ class BrowserPay implements MethodInterface | ||||
|             'currency' => $this->stripe->client->getCurrencyCode(), | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::APPLE_PAY, | ||||
|             ], | ||||
|         ]; | ||||
| 
 | ||||
|         $data['gateway'] = $this->stripe; | ||||
|  | ||||
| @ -78,6 +78,10 @@ class Charge | ||||
|               'customer' => $cgt->gateway_customer_reference, | ||||
|               'confirm' => true, | ||||
|               'description' => $description, | ||||
|               'metadata' => [ | ||||
|                 'payment_hash' => $payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::CREDIT_CARD, | ||||
|                 ], | ||||
|             ]; | ||||
| 
 | ||||
|             $response = $this->stripe->createPaymentIntent($data, $this->stripe->stripe_connect_auth); | ||||
|  | ||||
| @ -63,10 +63,13 @@ class CreditCard | ||||
|             'currency' => $this->stripe->client->getCurrencyCode(), | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::CREDIT_CARD, | ||||
|             ], | ||||
|             'setup_future_usage' => 'off_session', | ||||
|         ]; | ||||
| 
 | ||||
|         $payment_intent_data['setup_future_usage'] = 'off_session'; | ||||
| 
 | ||||
|         $data['intent'] = $this->stripe->createPaymentIntent($payment_intent_data); | ||||
|         $data['gateway'] = $this->stripe; | ||||
| 
 | ||||
|  | ||||
| @ -52,7 +52,10 @@ class EPS | ||||
|             'payment_method_types' => ['eps'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::EPS, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -53,7 +53,10 @@ class FPX | ||||
|             'payment_method_types' => ['fpx'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::FPX, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -52,7 +52,10 @@ class GIROPAY | ||||
|             'payment_method_types' => ['giropay'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::GIROPAY, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
							
								
								
									
										201
									
								
								app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								app/PaymentDrivers/Stripe/Jobs/PaymentIntentWebhook.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
| <?php | ||||
| /** | ||||
|  * Invoice Ninja (https://invoiceninja.com). | ||||
|  * | ||||
|  * @link https://github.com/invoiceninja/invoiceninja source repository | ||||
|  * | ||||
|  * @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com) | ||||
|  * | ||||
|  * @license https://www.elastic.co/licensing/elastic-license | ||||
|  */ | ||||
| 
 | ||||
| namespace App\PaymentDrivers\Stripe\Jobs; | ||||
| 
 | ||||
| use App\Jobs\Util\SystemLogger; | ||||
| use App\Libraries\MultiDB; | ||||
| use App\Models\Company; | ||||
| use App\Models\CompanyGateway; | ||||
| use App\Models\GatewayType; | ||||
| use App\Models\Invoice; | ||||
| use App\Models\Payment; | ||||
| use App\Models\PaymentHash; | ||||
| use App\Models\PaymentType; | ||||
| use App\Models\SystemLog; | ||||
| use App\PaymentDrivers\Stripe\Utilities; | ||||
| use Illuminate\Bus\Queueable; | ||||
| use Illuminate\Contracts\Queue\ShouldQueue; | ||||
| use Illuminate\Foundation\Bus\Dispatchable; | ||||
| use Illuminate\Queue\InteractsWithQueue; | ||||
| use Illuminate\Queue\SerializesModels; | ||||
| 
 | ||||
| class PaymentIntentWebhook implements ShouldQueue | ||||
| { | ||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Utilities; | ||||
| 
 | ||||
|     public $tries = 1; //number of retries
 | ||||
| 
 | ||||
|     public $deleteWhenMissingModels = true; | ||||
| 
 | ||||
|     public $stripe_request; | ||||
| 
 | ||||
|     public $company_key; | ||||
| 
 | ||||
|     private $company_gateway_id; | ||||
| 
 | ||||
|     public $payment_completed = false; | ||||
| 
 | ||||
|     public function __construct($stripe_request, $company_key, $company_gateway_id) | ||||
|     { | ||||
|         $this->stripe_request = $stripe_request; | ||||
|         $this->company_key = $company_key; | ||||
|         $this->company_gateway_id = $company_gateway_id; | ||||
|     } | ||||
| 
 | ||||
|     public function handle() | ||||
|     { | ||||
|         // nlog($this->stripe_request);
 | ||||
|         // nlog(optional($this->stripe_request['object']['charges']['data'][0]['metadata'])['gateway_type_id']);
 | ||||
|         // nlog(optional($this->stripe_request['object']['charges']['data'][0]['metadata'])['payment_hash']);
 | ||||
|         // nlog(optional($this->stripe_request['object']['charges']['data'][0]['payment_method_details']['card'])['brand']);
 | ||||
| 
 | ||||
|         MultiDB::findAndSetDbByCompanyKey($this->company_key); | ||||
| 
 | ||||
|         $company = Company::where('company_key', $this->company_key)->first(); | ||||
| 
 | ||||
|             foreach ($this->stripe_request as $transaction) { | ||||
| 
 | ||||
|                 if(array_key_exists('payment_intent', $transaction)) | ||||
|                 { | ||||
|                     $payment = Payment::query() | ||||
|                         ->where('company_id', $company->id) | ||||
|                         ->where(function ($query) use ($transaction) { | ||||
|                             $query->where('transaction_reference', $transaction['payment_intent']) | ||||
|                                   ->orWhere('transaction_reference', $transaction['id']); | ||||
|                                 }) | ||||
|                         ->first(); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                      $payment = Payment::query() | ||||
|                         ->where('company_id', $company->id) | ||||
|                         ->where('transaction_reference', $transaction['id']) | ||||
|                         ->first(); | ||||
|                 } | ||||
| 
 | ||||
|                 if ($payment) { | ||||
|                     $payment->status_id = Payment::STATUS_COMPLETED; | ||||
|                     $payment->save(); | ||||
|      | ||||
|                     $this->payment_completed = true; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|         if($this->payment_completed) | ||||
|             return; | ||||
| 
 | ||||
| 
 | ||||
|         if(optional($this->stripe_request['object']['charges']['data'][0])['id']){ | ||||
| 
 | ||||
|             $company = Company::where('company_key', $this->company_key)->first(); | ||||
| 
 | ||||
|             $payment = Payment::query() | ||||
|                              ->where('company_id', $company->id) | ||||
|                              ->where('transaction_reference', $this->stripe_request['object']['charges']['data'][0]['id']) | ||||
|                              ->first(); | ||||
| 
 | ||||
|              //return early
 | ||||
|             if($payment && $payment->status_id == Payment::STATUS_COMPLETED){ | ||||
|                 nlog(" payment found and status correct - returning ");  | ||||
|                 return; | ||||
|             } | ||||
|             elseif($payment){ | ||||
|                 $payment->status_id = Payment::STATUS_COMPLETED; | ||||
|                 $payment->save(); | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             $hash = optional($this->stripe_request['object']['charges']['data'][0]['metadata'])['payment_hash']; | ||||
| 
 | ||||
|             $payment_hash = PaymentHash::where('hash', $hash)->first(); | ||||
| 
 | ||||
|             nlog("no payment found"); | ||||
| 
 | ||||
|             if(optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['allowed_source_types'])) | ||||
|             { | ||||
|                 nlog("hash found"); | ||||
| 
 | ||||
|                 $hash = $this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']; | ||||
| 
 | ||||
|                 $payment_hash = PaymentHash::where('hash', $hash)->first(); | ||||
|                 $invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id); | ||||
|                 $client = $invoice->client; | ||||
| 
 | ||||
|                 $this->updateCreditCardPayment($payment_hash, $client); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private function updateCreditCardPayment($payment_hash, $client) | ||||
|     { | ||||
|         $company_gateway = CompanyGateway::find($this->company_gateway_id); | ||||
|         $payment_method_type = optional($this->stripe_request['object']['charges']['data'][0]['metadata'])['gateway_type_id']; | ||||
|         $driver = $company_gateway->driver($client)->init()->setPaymentMethod($payment_method_type); | ||||
| 
 | ||||
|         $payment_hash->data = array_merge((array) $payment_hash->data, $this->stripe_request); | ||||
|         $payment_hash->save(); | ||||
|         $driver->setPaymentHash($payment_hash); | ||||
| 
 | ||||
|         $data = [ | ||||
|             'payment_method' => $payment_hash->data->object->payment_method, | ||||
|             'payment_type' => PaymentType::parseCardType(strtolower(optional($this->stripe_request['object']['charges']['data'][0]['payment_method_details']['card'])['brand'])) ?: PaymentType::CREDIT_CARD_OTHER, | ||||
|             'amount' => $payment_hash->data->amount_with_fee, | ||||
|             'transaction_reference' => $this->stripe_request['object']['charges']['data'][0]['id'], | ||||
|             'gateway_type_id' => GatewayType::CREDIT_CARD, | ||||
|         ]; | ||||
|          | ||||
|         $payment = $driver->createPayment($data, Payment::STATUS_COMPLETED); | ||||
| 
 | ||||
|         SystemLogger::dispatch( | ||||
|             ['response' => $this->stripe_request, 'data' => $data], | ||||
|             SystemLog::CATEGORY_GATEWAY_RESPONSE, | ||||
|             SystemLog::EVENT_GATEWAY_SUCCESS, | ||||
|             SystemLog::TYPE_STRIPE, | ||||
|             $client, | ||||
|             $client->company, | ||||
|         ); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|         //charge # optional($this->stripe_request['object']['charges']['data'][0])['id']
 | ||||
|         //metadata # optional($this->stripe_request['object']['charges']['data'][0]['metadata']['gateway_type_id']
 | ||||
|         //metadata # optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']
 | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  *  | ||||
|                 * $intent = \Stripe\PaymentIntent::retrieve('{{PAYMENT_INTENT_ID}}'); | ||||
|                 $charges = $intent->charges->data; | ||||
|  *  | ||||
|  *  | ||||
|  *                      $payment = Payment::query() | ||||
|                         ->where('company_id', $request->getCompany()->id) | ||||
|                         ->where('transaction_reference', $transaction['id']) | ||||
|                         ->first(); | ||||
| 
 | ||||
| 
 | ||||
|                     if ($payment) { | ||||
|                     $payment->status_id = Payment::STATUS_COMPLETED; | ||||
|                     $payment->save(); | ||||
|                 } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  * */ | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
| } | ||||
| @ -52,7 +52,10 @@ class PRZELEWY24 | ||||
|             'payment_method_types' => ['p24'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::PRZELEWY24, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -54,6 +54,10 @@ class SEPA | ||||
|             'setup_future_usage' => 'off_session', | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::SEPA, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -52,7 +52,10 @@ class SOFORT | ||||
|             'payment_method_types' => ['sofort'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::SOFORT, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -18,7 +18,7 @@ trait Utilities | ||||
|     public function convertFromStripeAmount($amount, $precision, $currency) | ||||
|     { | ||||
| 
 | ||||
|        if(in_array($amount, ["BIF","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","UGX","VND","VUV","XAF","XOF","XPF"])) | ||||
|        if(in_array($currency->code, ["BIF","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","UGX","VND","VUV","XAF","XOF","XPF"])) | ||||
|             return $amount; | ||||
| 
 | ||||
|         return $amount / pow(10, $precision); | ||||
| @ -28,7 +28,7 @@ trait Utilities | ||||
|     public function convertToStripeAmount($amount, $precision, $currency) | ||||
|     { | ||||
| 
 | ||||
|        if(in_array($amount, ["BIF","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","UGX","VND","VUV","XAF","XOF","XPF"])) | ||||
|        if(in_array($currency->code, ["BIF","CLP","DJF","GNF","JPY","KMF","KRW","MGA","PYG","RWF","UGX","VND","VUV","XAF","XOF","XPF"])) | ||||
|             return $amount;  | ||||
| 
 | ||||
|         return round(($amount * pow(10, $precision)),0); | ||||
|  | ||||
| @ -52,7 +52,10 @@ class iDeal | ||||
|             'payment_method_types' => ['ideal'], | ||||
|             'customer' => $this->stripe->findOrCreateCustomer(), | ||||
|             'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')), | ||||
| 
 | ||||
|             'metadata' => [ | ||||
|                 'payment_hash' => $this->stripe->payment_hash->hash, | ||||
|                 'gateway_type_id' => GatewayType::IDEAL, | ||||
|             ], | ||||
|         ], $this->stripe->stripe_connect_auth); | ||||
| 
 | ||||
|         $data['pi_client_secret'] = $intent->client_secret; | ||||
|  | ||||
| @ -25,25 +25,26 @@ use App\Models\PaymentHash; | ||||
| use App\Models\PaymentType; | ||||
| use App\Models\SystemLog; | ||||
| use App\PaymentDrivers\Stripe\ACH; | ||||
| use App\PaymentDrivers\Stripe\ACSS; | ||||
| use App\PaymentDrivers\Stripe\Alipay; | ||||
| use App\PaymentDrivers\Stripe\ApplePay; | ||||
| use App\PaymentDrivers\Stripe\BECS; | ||||
| use App\PaymentDrivers\Stripe\Bancontact; | ||||
| use App\PaymentDrivers\Stripe\BrowserPay; | ||||
| use App\PaymentDrivers\Stripe\Charge; | ||||
| use App\PaymentDrivers\Stripe\Connect\Verify; | ||||
| use App\PaymentDrivers\Stripe\CreditCard; | ||||
| use App\PaymentDrivers\Stripe\ImportCustomers; | ||||
| use App\PaymentDrivers\Stripe\SOFORT; | ||||
| use App\PaymentDrivers\Stripe\SEPA; | ||||
| use App\PaymentDrivers\Stripe\PRZELEWY24; | ||||
| use App\PaymentDrivers\Stripe\GIROPAY; | ||||
| use App\PaymentDrivers\Stripe\iDeal; | ||||
| use App\PaymentDrivers\Stripe\EPS; | ||||
| use App\PaymentDrivers\Stripe\Bancontact; | ||||
| use App\PaymentDrivers\Stripe\BECS; | ||||
| use App\PaymentDrivers\Stripe\ACSS; | ||||
| use App\PaymentDrivers\Stripe\BrowserPay; | ||||
| use App\PaymentDrivers\Stripe\FPX; | ||||
| use App\PaymentDrivers\Stripe\GIROPAY; | ||||
| use App\PaymentDrivers\Stripe\ImportCustomers; | ||||
| use App\PaymentDrivers\Stripe\Jobs\PaymentIntentWebhook; | ||||
| use App\PaymentDrivers\Stripe\PRZELEWY24; | ||||
| use App\PaymentDrivers\Stripe\SEPA; | ||||
| use App\PaymentDrivers\Stripe\SOFORT; | ||||
| use App\PaymentDrivers\Stripe\UpdatePaymentMethods; | ||||
| use App\PaymentDrivers\Stripe\Utilities; | ||||
| use App\PaymentDrivers\Stripe\iDeal; | ||||
| use App\Utils\Traits\MakesHash; | ||||
| use Exception; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| @ -472,10 +473,7 @@ class StripePaymentDriver extends BaseDriver | ||||
|         $response = null; | ||||
| 
 | ||||
|         try { | ||||
|             // $response = $this->stripe
 | ||||
|             //     ->refunds
 | ||||
|             //     ->create(['charge' => $payment->transaction_reference, 'amount' => $this->convertToStripeAmount($amount, $this->client->currency()->precision, $this->client->currency())], $meta);
 | ||||
| 
 | ||||
|              | ||||
|             $response = \Stripe\Refund::create([ | ||||
|                 'charge' => $payment->transaction_reference, | ||||
|                 'amount' => $this->convertToStripeAmount($amount, $this->client->currency()->precision, $this->client->currency()) | ||||
| @ -532,7 +530,15 @@ class StripePaymentDriver extends BaseDriver | ||||
|         // Allow app to catch up with webhook request.
 | ||||
|         sleep(2); | ||||
| 
 | ||||
|         if ($request->type === 'charge.succeeded' || $request->type === 'payment_intent.succeeded') { | ||||
|         //payment_intent.succeeded - this will confirm or cancel the payment
 | ||||
|         if($request->type === 'payment_intent.succeeded'){ | ||||
|             PaymentIntentWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id)->delay(10); | ||||
|             // PaymentIntentWebhook::dispatch($request->data, $request->company_key, $this->company_gateway->id);
 | ||||
|             return response()->json([], 200); | ||||
|         } | ||||
| 
 | ||||
|         if ($request->type === 'charge.succeeded') { | ||||
|         // if ($request->type === 'charge.succeeded' || $request->type === 'payment_intent.succeeded') {
 | ||||
| 
 | ||||
|             foreach ($request->data as $transaction) { | ||||
| 
 | ||||
| @ -559,6 +565,7 @@ class StripePaymentDriver extends BaseDriver | ||||
|                     $payment->save(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } elseif ($request->type === 'source.chargeable') { | ||||
|             $this->init(); | ||||
| 
 | ||||
|  | ||||
| @ -174,15 +174,17 @@ class Statement | ||||
|                 $item->tax_rate1 = 5; | ||||
|             } | ||||
| 
 | ||||
|             $product = Product::first(); | ||||
|             //$product = Product::first();
 | ||||
| 
 | ||||
|             $item->cost = (float) $product->cost; | ||||
|             $item->product_key = $product->product_key; | ||||
|             $item->notes = $product->notes; | ||||
|             $item->custom_value1 = $product->custom_value1; | ||||
|             $item->custom_value2 = $product->custom_value2; | ||||
|             $item->custom_value3 = $product->custom_value3; | ||||
|             $item->custom_value4 = $product->custom_value4; | ||||
|             $product = new \stdClass; | ||||
| 
 | ||||
|             $item->cost = (float) 10; | ||||
|             $item->product_key = 'test'; | ||||
|             $item->notes = 'test notes'; | ||||
|             $item->custom_value1 = 'custom value1'; | ||||
|             $item->custom_value2 = 'custom value2'; | ||||
|             $item->custom_value3 = 'custom value3'; | ||||
|             $item->custom_value4 = 'custom value4'; | ||||
| 
 | ||||
|             $line_items[] = $item; | ||||
|         } | ||||
|  | ||||
| @ -108,6 +108,7 @@ class CreditService | ||||
| 
 | ||||
|         $this->updateBalance($adjustment) | ||||
|              ->updatePaidToDate($adjustment) | ||||
|              ->setStatus(Credit::STATUS_APPLIED) | ||||
|              ->save(); | ||||
| 
 | ||||
|         //create a negative payment of total $this->credit->balance
 | ||||
| @ -136,7 +137,6 @@ class CreditService | ||||
|              ->client | ||||
|              ->service() | ||||
|              ->updatePaidToDate($adjustment) | ||||
|              ->setStatus(Credit::STATUS_APPLIED) | ||||
|              ->save(); | ||||
| 
 | ||||
|         event('eloquent.created: App\Models\Payment', $payment); | ||||
|  | ||||
| @ -55,6 +55,16 @@ class UpdateInvoicePayment | ||||
|             if($paid_amount > $invoice->partial && $paid_amount > $invoice->balance) | ||||
|                 $paid_amount = $invoice->balance; | ||||
| 
 | ||||
|             /*Improve performance here - 26-01-2022 - also change the order of events for invoice first*/ | ||||
|             $invoice->service() //caution what if we amount paid was less than partial - we wipe it!
 | ||||
|                 ->clearPartial() | ||||
|                 ->updateBalance($paid_amount * -1) | ||||
|                 ->updatePaidToDate($paid_amount) | ||||
|                 ->updateStatus() | ||||
|                 ->touchPdf() | ||||
|                 ->workFlow() | ||||
|                 ->save(); | ||||
| 
 | ||||
|             /* Updates the company ledger */ | ||||
|             $this->payment | ||||
|                  ->ledger() | ||||
| @ -77,19 +87,22 @@ class UpdateInvoicePayment | ||||
| 
 | ||||
|             $this->payment->applied += $paid_amount; | ||||
| 
 | ||||
|             $invoice->service() //caution what if we amount paid was less than partial - we wipe it!
 | ||||
|                 ->clearPartial() | ||||
|                 ->updateBalance($paid_amount * -1) | ||||
|                 ->updatePaidToDate($paid_amount) | ||||
|                 ->updateStatus() | ||||
|                 ->save(); | ||||
|             // $invoice->service() //caution what if we amount paid was less than partial - we wipe it!
 | ||||
|             //     ->clearPartial()
 | ||||
|             //     ->updateBalance($paid_amount * -1)
 | ||||
|             //     ->updatePaidToDate($paid_amount)
 | ||||
|             //     ->updateStatus()
 | ||||
|             //     ->save();
 | ||||
| 
 | ||||
|             //     $invoice->refresh();
 | ||||
| 
 | ||||
|             //     $invoice->service()
 | ||||
|             //             ->touchPdf(true)
 | ||||
|             //             ->workFlow()
 | ||||
|             //             ->save();
 | ||||
| 
 | ||||
| 
 | ||||
|                 $invoice->refresh(); | ||||
| 
 | ||||
|                 $invoice->service() | ||||
|                         ->touchPdf(true) | ||||
|                         ->workFlow() | ||||
|                         ->save(); | ||||
| 
 | ||||
|         }); | ||||
|          | ||||
|  | ||||
| @ -14,8 +14,8 @@ return [ | ||||
|     'require_https' => env('REQUIRE_HTTPS', true), | ||||
|     'app_url' => rtrim(env('APP_URL', ''), '/'), | ||||
|     'app_domain' => env('APP_DOMAIN', 'invoicing.co'), | ||||
|     'app_version' => '5.3.49', | ||||
|     'app_tag' => '5.3.49', | ||||
|     'app_version' => '5.3.51', | ||||
|     'app_tag' => '5.3.51', | ||||
|     'minimum_client_version' => '5.0.16', | ||||
|     'terms_version' => '1.0.1', | ||||
|     'api_secret' => env('API_SECRET', ''), | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
| 
 | ||||
| use Illuminate\Support\Facades\Route; | ||||
| 
 | ||||
| Route::group(['middleware' => ['throttle:10,1', 'api_secret_check']], function () { | ||||
| Route::group(['middleware' => ['throttle:300,1', 'api_secret_check']], function () { | ||||
|     Route::post('api/v1/signup', 'AccountController@store')->name('signup.submit'); | ||||
|     Route::post('api/v1/oauth_login', 'Auth\LoginController@oauthApiLogin'); | ||||
| }); | ||||
|  | ||||
| @ -28,7 +28,7 @@ Route::get('error', 'ClientPortal\ContactHashLoginController@errorPage')->name(' | ||||
| Route::get('client/payment/{contact_key}/{payment_id}', 'ClientPortal\InvitationController@paymentRouter')->middleware(['domain_db','contact_key_login']); | ||||
| Route::get('client/ninja/{contact_key}/{company_key}', 'ClientPortal\NinjaPlanController@index')->name('client.ninja_contact_login')->middleware(['domain_db']); | ||||
| 
 | ||||
| Route::group(['middleware' => ['auth:contact', 'locale', 'check_client_existence','domain_db'], 'prefix' => 'client', 'as' => 'client.'], function () { | ||||
| Route::group(['middleware' => ['auth:contact', 'locale', 'domain_db'], 'prefix' => 'client', 'as' => 'client.'], function () { | ||||
|     Route::get('dashboard', 'ClientPortal\DashboardController@index')->name('dashboard'); // name = (dashboard. index / create / show / update / destroy / edit
 | ||||
| 
 | ||||
|     Route::get('plan', 'ClientPortal\NinjaPlanController@plan')->name('plan'); // name = (dashboard. index / create / show / update / destroy / edit
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user