diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index 3aa197474147..405e5c1ccf4a 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -112,8 +112,8 @@ class InvoiceItemSum { $item_tax = 0; -// info(print_r($this->item,1)); -// info(print_r($this->invoice,1)); + // info(print_r($this->item,1)); + // info(print_r($this->invoice,1)); $amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount / 100)); $item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount); diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index 9163f2fb9d1f..99bcca814ca8 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -12,7 +12,6 @@ namespace App\Http\Requests\Invoice; use App\Http\Requests\Request; -use App\Http\ValidationRules\Invoice\UniqueInvoiceNumberRule; use App\Http\ValidationRules\Project\ValidProjectForClient; use App\Models\Invoice; use App\Utils\Traits\CleanLineItems; diff --git a/app/Import/Definitions/PaymentMap.php b/app/Import/Definitions/PaymentMap.php index c9567e50e044..7ff554be0096 100644 --- a/app/Import/Definitions/PaymentMap.php +++ b/app/Import/Definitions/PaymentMap.php @@ -55,4 +55,3 @@ class PaymentMap ]; } } - diff --git a/app/Import/Transformers/BaseTransformer.php b/app/Import/Transformers/BaseTransformer.php index 404fad114a32..9371d802281a 100644 --- a/app/Import/Transformers/BaseTransformer.php +++ b/app/Import/Transformers/BaseTransformer.php @@ -50,7 +50,7 @@ class BaseTransformer public function getInvoiceTypeId($data, $field) { - return (isset($data[$field]) && $data[$field]) ? $data[$field] : '1'; + return (isset($data[$field]) && $data[$field]) ? $data[$field] : '1'; } public function getCurrencyByCode($data) @@ -60,8 +60,9 @@ class BaseTransformer if ($code) { $currency = $this->maps['currencies']->where('code', $code)->first(); - if($currency_id) + if ($currency_id) { return $currency->id; + } } return $this->maps['company']->settings->currency_id; @@ -69,28 +70,28 @@ class BaseTransformer public function getClient($client_name, $client_email) { - $clients = $this->maps['company']->clients; $clients = $clients->where('name', $client_name); - if($clients->count() >= 1) + if ($clients->count() >= 1) { return $clients->first()->id; + } $contacts = ClientContact::where('company_id', $this->maps['company']->id) ->where('email', $client_email); - if($contacts->count() >=1) + if ($contacts->count() >=1) { return $contacts->first()->client_id; + } - return NULL; - + return null; } -/////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////// /** * @param $name * @@ -147,12 +148,12 @@ class BaseTransformer * @return float */ public function getFloat($data, $field) - { - - if(array_key_exists($field, $data)) + { + if (array_key_exists($field, $data)) { $number = preg_replace('/[^0-9-.]+/', '', $data[$field]); - else + } else { $number = 0; + } return Number::parseStringFloat($number); } diff --git a/app/Import/Transformers/InvoiceItemTransformer.php b/app/Import/Transformers/InvoiceItemTransformer.php index 5ddcca8df3c7..ff93281dc476 100644 --- a/app/Import/Transformers/InvoiceItemTransformer.php +++ b/app/Import/Transformers/InvoiceItemTransformer.php @@ -11,8 +11,6 @@ namespace App\Import\Transformers; -use Illuminate\Support\Str; - /** * Class InvoiceItemTransformer. */ @@ -45,4 +43,4 @@ class InvoiceItemTransformer extends BaseTransformer 'type_id' => $this->getInvoiceTypeId($data, 'item.type_id'), ]; } -} \ No newline at end of file +} diff --git a/app/Import/Transformers/InvoiceTransformer.php b/app/Import/Transformers/InvoiceTransformer.php index 5ed42f8a07c0..d640d00536a2 100644 --- a/app/Import/Transformers/InvoiceTransformer.php +++ b/app/Import/Transformers/InvoiceTransformer.php @@ -11,8 +11,6 @@ namespace App\Import\Transformers; -use Illuminate\Support\Str; - /** * Class InvoiceTransformer. */ @@ -60,4 +58,4 @@ class InvoiceTransformer extends BaseTransformer 'exchange_rate' => $this->getString($data, 'invoice.exchange_rate'), ]; } -} \ No newline at end of file +} diff --git a/app/Import/Transformers/PaymentTransformer.php b/app/Import/Transformers/PaymentTransformer.php index 5ce5042f5b99..b3070da1f053 100644 --- a/app/Import/Transformers/PaymentTransformer.php +++ b/app/Import/Transformers/PaymentTransformer.php @@ -11,8 +11,6 @@ namespace App\Import\Transformers; -use Illuminate\Support\Str; - /** * Class PaymentTransformer. */ @@ -45,4 +43,4 @@ class PaymentTransformer extends BaseTransformer 'method' => $this ]; } -} \ No newline at end of file +} diff --git a/app/Import/Transformers/ProductTransformer.php b/app/Import/Transformers/ProductTransformer.php index c932823d6651..05a8e6a887bb 100644 --- a/app/Import/Transformers/ProductTransformer.php +++ b/app/Import/Transformers/ProductTransformer.php @@ -11,8 +11,6 @@ namespace App\Import\Transformers; -use Illuminate\Support\Str; - /** * Class ProductTransformer. */ diff --git a/app/Jobs/Import/CSVImport.php b/app/Jobs/Import/CSVImport.php index 5ef23217e46d..f54016ac8532 100644 --- a/app/Jobs/Import/CSVImport.php +++ b/app/Jobs/Import/CSVImport.php @@ -126,17 +126,17 @@ info(print_r($data,1)); private function importInvoice() { - $invoice_transformer = new InvoiceTransformer($this->maps); $records = $this->getCsvData(); $invoice_number_key = array_search('Invoice Number', reset($records)); - if ($this->skip_header) + if ($this->skip_header) { array_shift($records); + } - if(!$invoice_number_key){ + if (!$invoice_number_key) { info("no invoice number to use as key - returning"); return; } @@ -144,15 +144,12 @@ info(print_r($data,1)); $unique_invoices = []; //get an array of unique invoice numbers - foreach($records as $key => $value) - { + foreach ($records as $key => $value) { $unique_invoices[] = $value[$invoice_number_key]; } - foreach($unique_invoices as $unique) - { - - $invoices = array_filter($records, function($value) use($invoice_number_key, $unique){ + foreach ($unique_invoices as $unique) { + $invoices = array_filter($records, function ($value) use ($invoice_number_key, $unique) { return $value[$invoice_number_key] == $unique; }); @@ -163,9 +160,7 @@ info(print_r($data,1)); $invoice = $invoice_transformer->transform($invoice_data); $this->processInvoice($invoices, $invoice); - } - } private function processInvoice($invoices, $invoice) @@ -174,15 +169,12 @@ info(print_r($data,1)); $item_transformer = new InvoiceItemTransformer($this->maps); $items = []; - foreach($invoices as $record) - { - + foreach ($invoices as $record) { $keys = $this->column_map; $values = array_intersect_key($record, $this->column_map); $invoice_data = array_combine($keys, $values); $items[] = $item_transformer->transform($invoice_data); - } $invoice['line_items'] = $this->cleanItems($items); @@ -193,17 +185,19 @@ info(print_r($data,1)); $this->error_array['invoices'] = ['invoice' => $invoice, 'error' => json_encode($validator->errors())]; } else { - $invoice = $invoice_repository->save($invoice, InvoiceFactory::create($this->company->id, $this->setUser($record))); + if ($validator->fails()) { + $this->error_array[] = ['invoice' => $invoice, 'error' => json_encode($validator->errors())]; + } else { + $invoice = $invoice_repository->save($invoice, InvoiceFactory::create($this->company->id, $this->setUser($record))); - $this->maps['invoices'][] = $invoice->id; + $this->maps['invoices'][] = $invoice->id; - $this->performInvoiceActions($invoice, $record, $invoice_repository); - } + $this->performInvoiceActions($invoice, $record, $invoice_repository); + } } private function performInvoiceActions($invoice, $record, $invoice_repository) { - $invoice = $this->actionInvoiceStatus($invoice, $record, $invoice_repository); } @@ -217,7 +211,7 @@ info(print_r($data,1)); case 'Sent': $invoice = $invoice->service()->markSent()->save(); break; - case 'Viewed'; + case 'Viewed': $invoice = $invoice->service()->markSent()->save(); break; default: @@ -225,7 +219,7 @@ info(print_r($data,1)); break; } - if($invoice->balance < $invoice->amount && $invoice->status_id <= Invoice::STATUS_SENT){ + if ($invoice->balance < $invoice->amount && $invoice->status_id <= Invoice::STATUS_SENT) { $invoice->status_id = Invoice::STATUS_PARTIAL; $invoice->save(); } @@ -243,11 +237,11 @@ info(print_r($data,1)); $client_repository = new ClientRepository($contact_repository); $client_transformer = new ClientTransformer($this->maps); - if ($this->skip_header) + if ($this->skip_header) { array_shift($records); + } foreach ($records as $record) { - $keys = $this->column_map; $values = array_intersect_key($record, $this->column_map); @@ -280,17 +274,16 @@ info(print_r($data,1)); private function importProduct() { - $product_repository = new ProductRepository(); $product_transformer = new ProductTransformer($this->maps); $records = $this->getCsvData(); - if ($this->skip_header) + if ($this->skip_header) { array_shift($records); + } - foreach ($records as $record) - { + foreach ($records as $record) { $keys = $this->column_map; $values = array_intersect_key($record, $this->column_map); diff --git a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php index ae3e12cf6c12..918dfeb63f90 100644 --- a/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php +++ b/app/PaymentDrivers/Authorize/AuthorizeCreditCard.php @@ -75,7 +75,7 @@ class AuthorizeCreditCard $client_gateway_token = $authorise_payment_method->createClientGatewayToken($payment_profile, $gateway_customer_reference); } - $data = (new ChargePaymentProfile($this->authorize))->chargeCustomerProfile($gateway_customer_reference, $payment_profile_id, $data['amount_with_fee']); + $data = (new ChargePaymentProfile($this->authorize))->chargeCustomerProfile($gateway_customer_reference, $payment_profile_id, $data['total']['amount_with_fee']); return $this->handleResponse($data, $request); } @@ -106,13 +106,13 @@ class AuthorizeCreditCard // $payment_record['transaction_reference'] = $response->getTransactionResponse()->getTransId(); // $this->authorize->createPayment($payment_record); - + $this->storePayment($payment_hash, $data); - + // $payment = $this->createPaymentRecord($data, $amount); // $payment->meta = $cgt->meta; // $payment->save(); - + // $payment_hash->payment_id = $payment->id; // $payment_hash->save(); diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php index b3654c9d6a40..f2a8a7ebda16 100644 --- a/app/PaymentDrivers/CheckoutCom/CreditCard.php +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -64,8 +64,8 @@ class CreditCard $data['company_gateway'] = $this->checkout->company_gateway; $data['client'] = $this->checkout->client; $data['currency'] = $this->checkout->client->getCurrencyCode(); - $data['value'] = $this->checkout->convertToCheckoutAmount($data['amount_with_fee'], $this->checkout->client->getCurrencyCode()); - $data['raw_value'] = $data['amount_with_fee']; + $data['value'] = $this->checkout->convertToCheckoutAmount($data['total']['amount_with_fee'], $this->checkout->client->getCurrencyCode()); + $data['raw_value'] = $data['total']['amount_with_fee']; $data['customer_email'] = $this->checkout->client->present()->email; return render('gateways.checkout.credit_card.pay', $data); diff --git a/app/PaymentDrivers/PayPalExpressPaymentDriver.php b/app/PaymentDrivers/PayPalExpressPaymentDriver.php index 752ebf48c69d..5756abcbff1c 100644 --- a/app/PaymentDrivers/PayPalExpressPaymentDriver.php +++ b/app/PaymentDrivers/PayPalExpressPaymentDriver.php @@ -88,7 +88,7 @@ class PayPalExpressPaymentDriver extends BaseDriver $this->initializeOmnipayGateway(); - $this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['amount_with_fee']]); + $this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]); $this->payment_hash->save(); $response = $this->omnipay_gateway @@ -100,7 +100,7 @@ class PayPalExpressPaymentDriver extends BaseDriver return $response->redirect(); } - PaymentFailureMailer::dispatch($this->client, $response->getData(), $this->client->company, $data['amount_with_fee']); + PaymentFailureMailer::dispatch($this->client, $response->getData(), $this->client->company, $data['total']['amount_with_fee']); $message = [ 'server_response' => $response->getMessage(), @@ -183,7 +183,7 @@ class PayPalExpressPaymentDriver extends BaseDriver 'currency' => $this->client->getCurrencyCode(), 'transactionType' => 'Purchase', 'clientIp' => request()->getClientIp(), - 'amount' => $data['amount_with_fee'], + 'amount' => $data['total']['amount_with_fee'], 'returnUrl' => route('client.payments.response', [ 'company_gateway_id' => $this->company_gateway->id, 'payment_hash' => $this->payment_hash->hash, @@ -223,11 +223,11 @@ class PayPalExpressPaymentDriver extends BaseDriver }); }); - if ($total != $data['amount_with_fee']) { + if ($total != $data['total']['amount_with_fee']) { $items[0][] = new Item([ 'name' => trans('texts.taxes_and_fees'), 'description' => '', - 'price' => $data['amount_with_fee'] - $total, + 'price' => $data['total']['amount_with_fee'] - $total, 'quantity' => 1, ]); } diff --git a/app/PaymentDrivers/Stripe/ACH.php b/app/PaymentDrivers/Stripe/ACH.php index db8a7e610920..6ef3a4381b0f 100644 --- a/app/PaymentDrivers/Stripe/ACH.php +++ b/app/PaymentDrivers/Stripe/ACH.php @@ -22,6 +22,8 @@ use App\Models\Payment; use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\StripePaymentDriver; +use Exception; +use Stripe\Customer; use Stripe\Exception\CardException; use Stripe\Exception\InvalidRequestException; @@ -68,10 +70,10 @@ class ACH { $this->stripe->init(); - $bank_account = \Stripe\Customer::retrieveSource($request->customer, $request->source); + $bank_account = Customer::retrieveSource($request->customer, $request->source); try { - $status = $bank_account->verify(['amounts' => request()->transactions]); + $bank_account->verify(['amounts' => request()->transactions]); $token->meta->verified_at = now(); $token->save(); @@ -90,7 +92,7 @@ class ACH $data['currency'] = $this->stripe->client->getCurrencyCode(); $data['payment_method_id'] = GatewayType::BANK_TRANSFER; $data['customer'] = $this->stripe->findOrCreateCustomer(); - $data['amount'] = $this->stripe->convertToStripeAmount($data['amount_with_fee'], $this->stripe->client->currency()->precision); + $data['amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision); return render('gateways.stripe.ach.pay', $data); } @@ -205,7 +207,7 @@ class ACH ]; return $this->stripe->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]); - } catch (\Exception $e) { + } catch (Exception $e) { return $this->stripe->processInternallyFailedPayment($this->stripe, $e); } } diff --git a/app/PaymentDrivers/Stripe/Alipay.php b/app/PaymentDrivers/Stripe/Alipay.php index d3feaf73bcb9..aaf7f51ed031 100644 --- a/app/PaymentDrivers/Stripe/Alipay.php +++ b/app/PaymentDrivers/Stripe/Alipay.php @@ -17,6 +17,7 @@ use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Jobs\Mail\PaymentFailureMailer; use App\Jobs\Util\SystemLogger; use App\Models\GatewayType; +use App\Models\Payment; use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\StripePaymentDriver; @@ -36,7 +37,7 @@ class Alipay $data['gateway'] = $this->stripe; $data['return_url'] = $this->buildReturnUrl(); $data['currency'] = $this->stripe->client->getCurrencyCode(); - $data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['amount_with_fee'], $this->stripe->client->currency()->precision); + $data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision); $data['invoices'] = $this->stripe->payment_hash->invoices(); $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]); @@ -77,7 +78,7 @@ class Alipay 'transaction_reference' => $source, ]; - $payment = $this->stripe->createPayment($data, \App\Models\Payment::STATUS_PENDING); + $payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING); SystemLogger::dispatch( ['response' => $this->stripe->payment_hash->data, 'data' => $data], diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index 461fa5462e97..d3a06c7d3f79 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -16,12 +16,13 @@ use App\Exceptions\PaymentFailed; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Jobs\Mail\PaymentFailureMailer; use App\Jobs\Util\SystemLogger; -use App\Models\ClientGatewayToken; use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\StripePaymentDriver; +use Stripe\PaymentIntent; +use Stripe\PaymentMethod; class CreditCard { @@ -59,7 +60,7 @@ class CreditCard public function paymentView(array $data) { $payment_intent_data = [ - 'amount' => $this->stripe->convertToStripeAmount($data['amount_with_fee'], $this->stripe->client->currency()->precision), + 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision), 'currency' => $this->stripe->client->getCurrencyCode(), 'customer' => $this->stripe->findOrCreateCustomer(), 'description' => collect($data['invoices'])->pluck('id'), // TODO: More meaningful description. @@ -91,7 +92,7 @@ class CreditCard $state = array_merge($state, $request->all()); $state['store_card'] = boolval($state['store_card']); - $state['payment_intent'] = \Stripe\PaymentIntent::retrieve($state['server_response']->id); + $state['payment_intent'] = PaymentIntent::retrieve($state['server_response']->id); $state['customer'] = $state['payment_intent']->customer; $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $state); @@ -111,7 +112,7 @@ class CreditCard private function processSuccessfulPayment() { $stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method); - + $data = [ 'payment_method' => $this->stripe->payment_hash->data->server_response->payment_method, 'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)), @@ -128,13 +129,13 @@ class CreditCard $customer->id = $this->stripe->payment_hash->data->customer; $this->stripe->attach($this->stripe->payment_hash->data->server_response->payment_method, $customer); - + $stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method); - + $this->storePaymentMethod($stripe_method, $this->stripe->payment_hash->data->payment_method_id, $customer); } - $payment = $this->stripe->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + $payment = $this->stripe->createPayment($data, Payment::STATUS_COMPLETED); SystemLogger::dispatch( ['response' => $this->stripe->payment_hash->data->server_response, 'data' => $data], @@ -174,7 +175,7 @@ class CreditCard throw new PaymentFailed('Failed to process the payment.', 500); } - private function storePaymentMethod(\Stripe\PaymentMethod $method, $payment_method_id, $customer) + private function storePaymentMethod(PaymentMethod $method, $payment_method_id, $customer) { try { $payment_meta = new \stdClass; @@ -195,26 +196,4 @@ class CreditCard return $this->stripe->processInternallyFailedPayment($this->stripe, $e); } } - - private function saveCard($state) - { - $state['payment_method']->attach(['customer' => $state['customer']]); - - $company_gateway_token = new ClientGatewayToken(); - $company_gateway_token->company_id = $this->stripe->client->company->id; - $company_gateway_token->client_id = $this->stripe->client->id; - $company_gateway_token->token = $state['payment_method']->id; - $company_gateway_token->company_gateway_id = $this->stripe->company_gateway->id; - $company_gateway_token->gateway_type_id = $state['gateway_type_id']; - $company_gateway_token->gateway_customer_reference = $state['customer']; - $company_gateway_token->meta = $state['payment_meta']; - $company_gateway_token->save(); - - if ($this->stripe->client->gateway_tokens->count() == 1) { - $this->stripe->client->gateway_tokens()->update(['is_default' => 0]); - - $company_gateway_token->is_default = 1; - $company_gateway_token->save(); - } - } } diff --git a/app/PaymentDrivers/Stripe/SOFORT.php b/app/PaymentDrivers/Stripe/SOFORT.php index 0b4a3f294f2b..f5c4e1204ed8 100644 --- a/app/PaymentDrivers/Stripe/SOFORT.php +++ b/app/PaymentDrivers/Stripe/SOFORT.php @@ -12,14 +12,14 @@ namespace App\PaymentDrivers\Stripe; -use App\Events\Payment\PaymentWasCreated; +use App\Exceptions\PaymentFailed; +use App\Jobs\Mail\PaymentFailureMailer; use App\Jobs\Util\SystemLogger; use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\StripePaymentDriver; -use App\Utils\Ninja; class SOFORT { @@ -34,74 +34,90 @@ class SOFORT public function paymentView(array $data) { $data['gateway'] = $this->stripe; - $data['return_url'] = $this->buildReturnUrl($data); - $data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['amount_with_fee'], $this->stripe->client->currency()->precision); + $data['return_url'] = $this->buildReturnUrl(); + $data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision); $data['client'] = $this->stripe->client; $data['country'] = $this->stripe->client->country->iso_3166_2; + $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]); + $this->stripe->payment_hash->save(); + return render('gateways.stripe.sofort.pay', $data); } - private function buildReturnUrl($data): string + private function buildReturnUrl(): string { return route('client.payments.response', [ 'company_gateway_id' => $this->stripe->company_gateway->id, - 'gateway_type_id' => GatewayType::SOFORT, - 'hashed_ids' => implode(',', $data['hashed_ids']), - 'amount' => $data['amount'], - 'fee' => $data['fee'], + 'payment_hash' => $this->stripe->payment_hash->hash, + 'payment_method_id' => GatewayType::SOFORT, ]); } public function paymentResponse($request) { - $state = array_merge($request->all(), []); - $amount = $state['amount'] + $state['fee']; - $state['amount'] = $this->stripe->convertToStripeAmount($amount, $this->stripe->client->currency()->precision); + $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all()); + $this->stripe->payment_hash->save(); if ($request->redirect_status == 'succeeded') { - return $this->processSuccessfulPayment($state); + return $this->processSuccessfulPayment($request->source); } - return $this->processUnsuccessfulPayment($state); + return $this->processUnsuccessfulPayment(); } - public function processSuccessfulPayment($state) + public function processSuccessfulPayment(string $source) { - $state['charge_id'] = $state['source']; + /* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */ $this->stripe->init(); - $state['payment_type'] = PaymentType::SOFORT; - $data = [ - 'payment_method' => $state['charge_id'], - 'payment_type' => $state['payment_type'], - 'amount' => $state['amount'], - 'gateway_type_id' => GatewayType::SOFORT, + 'payment_method' => $this->stripe->payment_hash->data->source, + 'payment_type' => PaymentType::SOFORT, + 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision), + 'transaction_reference' => $source, ]; $payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING); - /* @todo: https://github.com/invoiceninja/invoiceninja/pull/3789/files#r436175798 */ - if (isset($state['hashed_ids'])) { - $this->stripe->attachInvoices($payment, $state['hashed_ids']); - } - - event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); - - $logger_message = [ - 'server_response' => $state, - 'data' => $data, - ]; - - SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->stripe->client); + SystemLogger::dispatch( + ['response' => $this->stripe->payment_hash->data, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_STRIPE, + $this->stripe->client + ); return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]); } - public function processUnsuccessfulPayment($state) + public function processUnsuccessfulPayment() { - return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled')); + $server_response = $this->stripe->payment_hash->data; + + PaymentFailureMailer::dispatch($this->stripe->client, $server_response->redirect_status, $this->stripe->client->company, $server_response->amount); + + PaymentFailureMailer::dispatch( + $this->stripe->client, + $server_response, + $this->stripe->client->company, + $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->stripe_amount, $this->stripe->client->currency()->precision) + ); + + $message = [ + 'server_response' => $server_response, + 'data' => $this->stripe->payment_hash->data, + ]; + + SystemLogger::dispatch( + $message, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_STRIPE, + $this->stripe->client + ); + + throw new PaymentFailed('Failed to process the payment.', 500); } } diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 3ca5f80e4a2f..10cc679c9109 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -21,17 +21,18 @@ use App\Models\GatewayType; use App\Models\Payment; use App\Models\PaymentHash; use App\Models\SystemLog; -use App\PaymentDrivers\Stripe\ACH; use App\PaymentDrivers\Stripe\Alipay; use App\PaymentDrivers\Stripe\Charge; use App\PaymentDrivers\Stripe\CreditCard; use App\PaymentDrivers\Stripe\SOFORT; use App\PaymentDrivers\Stripe\Utilities; use App\Utils\Traits\MakesHash; +use Exception; use Illuminate\Support\Carbon; -use Illuminate\View\View; use Stripe\Customer; +use Stripe\Exception\ApiErrorException; use Stripe\PaymentIntent; +use Stripe\PaymentMethod; use Stripe\SetupIntent; use Stripe\Stripe; use Stripe\StripeClient; @@ -55,7 +56,7 @@ class StripePaymentDriver extends BaseDriver public static $methods = [ GatewayType::CREDIT_CARD => CreditCard::class, - GatewayType::BANK_TRANSFER => ACH::class, + GatewayType::BANK_TRANSFER => SOFORT::class, GatewayType::ALIPAY => Alipay::class, GatewayType::SOFORT => SOFORT::class, GatewayType::APPLE_PAY => 1, // TODO @@ -152,8 +153,7 @@ class StripePaymentDriver extends BaseDriver * Proxy method to pass the data into payment method authorizeView(). * * @param array $data - * - * @return Factory|View + * @return \Illuminate\Http\RedirectResponse|mixed */ public function authorizeView(array $data) { @@ -169,8 +169,8 @@ class StripePaymentDriver extends BaseDriver /** * Processes the gateway response for credit card authorization. * - * @param Request $request The returning request object - * @return Factory|View + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse|mixed */ public function authorizeResponse($request) { @@ -187,7 +187,7 @@ class StripePaymentDriver extends BaseDriver * Process the payment with gateway. * * @param array $data - * @return Factory|View|void + * @return \Illuminate\Http\RedirectResponse|mixed */ public function processPaymentView(array $data) { @@ -216,7 +216,7 @@ class StripePaymentDriver extends BaseDriver * * @param array $data The data array to be passed to Stripe * @return PaymentIntent The Stripe payment intent object - * @throws \Stripe\Exception\ApiErrorException + * @throws ApiErrorException */ public function createPaymentIntent($data): ?PaymentIntent { @@ -230,7 +230,7 @@ class StripePaymentDriver extends BaseDriver * to enter card details without initiating a transaction. * * @return SetupIntent - * @throws \Stripe\Exception\ApiErrorException + * @throws ApiErrorException */ public function getSetupIntent(): SetupIntent { @@ -253,7 +253,7 @@ class StripePaymentDriver extends BaseDriver * * @return null|Customer A Stripe customer object * @throws \Laracasts\Presenter\Exceptions\PresenterException - * @throws \Stripe\Exception\ApiErrorException + * @throws ApiErrorException */ public function findOrCreateCustomer(): ?Customer { @@ -277,7 +277,7 @@ class StripePaymentDriver extends BaseDriver } if (!$customer) { - throw new \Exception('Unable to create gateway customer'); + throw new Exception('Unable to create gateway customer'); } return $customer; @@ -316,7 +316,7 @@ class StripePaymentDriver extends BaseDriver 'description' => $response->failure_reason, 'code' => 422, ]; - } catch (\Exception $e) { + } catch (Exception $e) { SystemLogger::dispatch(['server_response' => $response, 'data' => request()->all(),], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->client); info($e->getMessage()); @@ -394,7 +394,7 @@ class StripePaymentDriver extends BaseDriver try { $stripe_payment_method = $this->getStripePaymentMethod($payment_method); $stripe_payment_method->attach(['customer' => $customer->id]); - } catch (\Stripe\Exception\ApiErrorException | \Exception $e) { + } catch (ApiErrorException | Exception $e) { $this->processInternallyFailedPayment($this, $e); } } @@ -413,7 +413,7 @@ class StripePaymentDriver extends BaseDriver ); try { - $response = $stripe->paymentMethods->detach($token->token); + $stripe->paymentMethods->detach($token->token); } catch (Exception $e) { SystemLogger::dispatch([ 'server_response' => $e->getMessage(), 'data' => request()->all(), @@ -431,13 +431,13 @@ class StripePaymentDriver extends BaseDriver * * @param string $source * - * @return \Stripe\PaymentMethod|void + * @return PaymentMethod|void */ public function getStripePaymentMethod(string $source) { try { - return \Stripe\PaymentMethod::retrieve($source); - } catch (\Stripe\Exception\ApiErrorException | \Exception $e) { + return PaymentMethod::retrieve($source); + } catch (ApiErrorException | Exception $e) { return $this->processInternallyFailedPayment($this, $e); } } diff --git a/app/Services/Invoice/HandleRestore.php b/app/Services/Invoice/HandleRestore.php index f3d7eff21a75..7ca3ede349aa 100644 --- a/app/Services/Invoice/HandleRestore.php +++ b/app/Services/Invoice/HandleRestore.php @@ -94,8 +94,9 @@ class HandleRestore extends AbstractService $new_invoice_number = substr($this->invoice->number, 0, $pos); - if(strlen($new_invoice_number) == 0) + if (strlen($new_invoice_number) == 0) { $new_invoice_number = null; + } try { $this->invoice->number = $new_invoice_number; diff --git a/config/ninja.php b/config/ninja.php index 3d66a5fd15b9..5ce7fc883912 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -7,7 +7,7 @@ return [ 'production' => env('NINJA_PROD', false), 'license' => env('NINJA_LICENSE', ''), 'version_url' => 'https://raw.githubusercontent.com/invoiceninja/invoiceninja/v5-stable/VERSION.txt', - 'app_name' => env('APP_NAME','Invoice Ninja'), + 'app_name' => env('APP_NAME', 'Invoice Ninja'), 'app_env' => env('APP_ENV', 'selfhosted'), 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), diff --git a/database/migrations/2020_12_20_005609_change_products_table_cost_resolution.php b/database/migrations/2020_12_20_005609_change_products_table_cost_resolution.php index 96cd7a95a3d4..c7682c5f2ac7 100644 --- a/database/migrations/2020_12_20_005609_change_products_table_cost_resolution.php +++ b/database/migrations/2020_12_20_005609_change_products_table_cost_resolution.php @@ -30,6 +30,3 @@ class ChangeProductsTableCostResolution extends Migration // } } - - - \ No newline at end of file diff --git a/database/seeders/CountriesSeeder.php b/database/seeders/CountriesSeeder.php index 399ccd4fb377..326facdfe095 100644 --- a/database/seeders/CountriesSeeder.php +++ b/database/seeders/CountriesSeeder.php @@ -51,7 +51,7 @@ class CountriesSeeder extends Seeder 'sub_region_code' => $country['sub-region-code'], 'eea' => (bool) $country['eea'], 'thousand_separator' => '', - 'decimal_separator' => '', + 'decimal_separator' => '', ]); } } diff --git a/public/js/clients/payments/stripe-sofort.js b/public/js/clients/payments/stripe-sofort.js index 0c5a0c951173..82d95903e1fa 100755 --- a/public/js/clients/payments/stripe-sofort.js +++ b/public/js/clients/payments/stripe-sofort.js @@ -1,2 +1,2 @@ /*! For license information please see stripe-sofort.js.LICENSE.txt */ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}new function e(t){var r=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),n(this,"setupStripe",(function(){return r.stripe=Stripe(r.key),r})),n(this,"handle",(function(){var e={type:"sofort",amount:document.querySelector('meta[name="amount"]').content,currency:"eur",redirect:{return_url:document.querySelector('meta[name="return-url"]').content},sofort:{country:document.querySelector('meta[name="country"').content}};document.getElementById("pay-now").addEventListener("click",(function(t){document.getElementById("pay-now-button").disabled=!0,document.querySelector("#pay-now-button > svg").classList.remove("hidden"),document.querySelector("#pay-now-button > span").classList.add("hidden"),r.stripe.createSource(e).then((function(e){if(e.hasOwnProperty("source"))return window.location=e.source.redirect.url;document.getElementById("pay-now-button").disabled=!1,document.querySelector("#pay-now-button > svg").classList.add("hidden"),document.querySelector("#pay-now-button > span").classList.remove("hidden"),this.errors.textContent="",this.errors.textContent=e.error.message,this.errors.hidden=!1,document.getElementById("pay-now").disabled=!1}))}))})),this.key=t,this.errors=document.getElementById("errors")}(document.querySelector('meta[name="stripe-publishable-key"]').content).setupStripe().handle()}}); \ No newline at end of file +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=6)}({6:function(e,t,n){e.exports=n("RFiP")},RFiP:function(e,t){function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}new function e(t){var r=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),n(this,"setupStripe",(function(){return r.stripe=Stripe(r.key),r})),n(this,"handle",(function(){var e={type:"sofort",amount:document.querySelector('meta[name="amount"]').content,currency:"eur",redirect:{return_url:document.querySelector('meta[name="return-url"]').content},sofort:{country:document.querySelector('meta[name="country"').content}};document.getElementById("pay-now").addEventListener("click",(function(t){document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),r.stripe.createSource(e).then((function(e){if(e.hasOwnProperty("source"))return window.location=e.source.redirect.url;document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden"),this.errors.textContent="",this.errors.textContent=e.error.message,this.errors.hidden=!1,document.getElementById("pay-now").disabled=!1}))}))})),this.key=t,this.errors=document.getElementById("errors")}(document.querySelector('meta[name="stripe-publishable-key"]').content).setupStripe().handle()}}); \ No newline at end of file diff --git a/public/mix-manifest.json b/public/mix-manifest.json index b540dd00e15b..9bc78aa1c276 100755 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -10,7 +10,7 @@ "/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=c4012ad90f17d60432ad", "/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=6dbe9316b98deea55421", "/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=f4659d26a26d2f408397", - "/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=7f5b13e34c75e63c015e", + "/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=bb7c55ca3da2d29e55d2", "/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=1b8f9325aa6e8595e7fa", "/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=85bcae0a646882e56b12", "/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=5c35d28cf0a3286e7c45", diff --git a/resources/js/clients/payments/stripe-sofort.js b/resources/js/clients/payments/stripe-sofort.js index 2e5da55ac7a5..58dac03e1014 100644 --- a/resources/js/clients/payments/stripe-sofort.js +++ b/resources/js/clients/payments/stripe-sofort.js @@ -30,23 +30,23 @@ class ProcessSOFORT { .content, }, sofort: { - country: document.querySelector('meta[name="country"').content, + country: document.querySelector('meta[name="country"]').content, }, }; document.getElementById('pay-now').addEventListener('click', (e) => { - document.getElementById('pay-now-button').disabled = true; - document.querySelector('#pay-now-button > svg').classList.remove('hidden'); - document.querySelector('#pay-now-button > span').classList.add('hidden'); + document.getElementById('pay-now').disabled = true; + document.querySelector('#pay-now > svg').classList.remove('hidden'); + document.querySelector('#pay-now > span').classList.add('hidden'); this.stripe.createSource(data).then(function(result) { if (result.hasOwnProperty('source')) { return (window.location = result.source.redirect.url); } - document.getElementById('pay-now-button').disabled = false; - document.querySelector('#pay-now-button > svg').classList.add('hidden'); - document.querySelector('#pay-now-button > span').classList.remove('hidden'); + document.getElementById('pay-now').disabled = false; + document.querySelector('#pay-now > svg').classList.add('hidden'); + document.querySelector('#pay-now > span').classList.remove('hidden'); this.errors.textContent = ''; this.errors.textContent = result.error.message; diff --git a/tests/Feature/Import/ImportCsvTest.php b/tests/Feature/Import/ImportCsvTest.php index f0d7aeb5b792..8e409f28ed06 100644 --- a/tests/Feature/Import/ImportCsvTest.php +++ b/tests/Feature/Import/ImportCsvTest.php @@ -150,7 +150,6 @@ class ImportCsvTest extends TestCase CSVImport::dispatchNow($data, $this->company); $this->assertGreaterThan($pre_import, Product::count()); - } private function getCsvData($csvfile)