mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +01:00
Paypal refactor
This commit is contained in:
parent
78fc17b1cb
commit
4008b24acd
@ -159,6 +159,11 @@ class CompanyGateway extends BaseModel
|
||||
|
||||
protected $touches = [];
|
||||
|
||||
public function isPayPal()
|
||||
{
|
||||
return in_array($this->gateway_key, ['80af24a6a691230bbec33e930ab40666','80af24a6a691230bbec33e930ab40665']);
|
||||
}
|
||||
|
||||
public function getEntityType()
|
||||
{
|
||||
return self::class;
|
||||
|
@ -192,6 +192,7 @@ class PaymentMethod
|
||||
'label' => ctrans('texts.apply_credit'),
|
||||
'company_gateway_id' => CompanyGateway::GATEWAY_CREDIT,
|
||||
'gateway_type_id' => GatewayType::CREDIT,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
}
|
||||
|
||||
@ -210,12 +211,14 @@ class PaymentMethod
|
||||
'label' => $gateway->getConfigField('name').$fee_label,
|
||||
'company_gateway_id' => $gateway->id,
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
} else {
|
||||
$this->payment_urls[] = [
|
||||
'label' => $gateway->getTypeAlias($type).$fee_label,
|
||||
'company_gateway_id' => $gateway->id,
|
||||
'gateway_type_id' => $type,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
}
|
||||
|
||||
@ -236,12 +239,14 @@ class PaymentMethod
|
||||
'label' => $gateway->getConfigField('name').$fee_label,
|
||||
'company_gateway_id' => $gateway_id,
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
} else {
|
||||
$this->payment_urls[] = [
|
||||
'label' => $gateway->getTypeAlias($gateway_type_id).$fee_label,
|
||||
'company_gateway_id' => $gateway_id,
|
||||
'gateway_type_id' => $gateway_type_id,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -259,6 +264,7 @@ class PaymentMethod
|
||||
'label' => ctrans('texts.apply_credit'),
|
||||
'company_gateway_id' => CompanyGateway::GATEWAY_CREDIT,
|
||||
'gateway_type_id' => GatewayType::CREDIT,
|
||||
'is_paypal' => $gateway->isPayPal(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,9 @@ class AutoBillInvoice extends AbstractService
|
||||
|
||||
public function __construct(private Invoice $invoice, protected string $db)
|
||||
{
|
||||
|
||||
$this->client = $this->invoice->client;
|
||||
|
||||
}
|
||||
|
||||
public function run()
|
||||
@ -49,8 +52,7 @@ class AutoBillInvoice extends AbstractService
|
||||
MultiDB::setDb($this->db);
|
||||
|
||||
/* @var \App\Modesl\Client $client */
|
||||
$this->client = $this->invoice->client;
|
||||
|
||||
|
||||
$is_partial = false;
|
||||
|
||||
/* Is the invoice payable? */
|
||||
@ -272,7 +274,7 @@ class AutoBillInvoice extends AbstractService
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
private function applyUnappliedPayment(): self
|
||||
public function applyUnappliedPayment(): self
|
||||
{
|
||||
$unapplied_payments = Payment::query()
|
||||
->where('client_id', $this->client->id)
|
||||
@ -284,6 +286,11 @@ class AutoBillInvoice extends AbstractService
|
||||
->get();
|
||||
|
||||
$available_unapplied_balance = $unapplied_payments->sum('amount') - $unapplied_payments->sum('applied');
|
||||
|
||||
nlog($this->client->id);
|
||||
nlog($this->invoice->id);
|
||||
nlog($unapplied_payments->sum('amount'));
|
||||
nlog($unapplied_payments->sum('applied'));
|
||||
|
||||
nlog("available unapplied balance = {$available_unapplied_balance}");
|
||||
|
||||
@ -347,7 +354,7 @@ class AutoBillInvoice extends AbstractService
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
private function applyCreditPayment(): self
|
||||
public function applyCreditPayment(): self
|
||||
{
|
||||
$available_credits = Credit::query()->where('client_id', $this->client->id)
|
||||
->where('is_deleted', false)
|
||||
|
109
public/build/assets/app-234e3402.js
vendored
109
public/build/assets/app-234e3402.js
vendored
File diff suppressed because one or more lines are too long
1
public/build/assets/app-f3b33400.css
vendored
1
public/build/assets/app-f3b33400.css
vendored
File diff suppressed because one or more lines are too long
9
public/build/assets/payment-1bdbd169.js
vendored
9
public/build/assets/payment-1bdbd169.js
vendored
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* 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
|
||||
*/class s{constructor(t,e,a){this.shouldDisplayTerms=t,this.shouldDisplaySignature=e,this.shouldDisplayRff=a,this.submitting=!1,this.steps=new Map,this.shouldDisplayRff&&this.steps.set("rff",{element:document.getElementById("displayRequiredFieldsModal"),nextButton:document.getElementById("rff-next-step"),callback:()=>{const n={firstName:document.querySelector('input[name="rff_first_name"]'),lastName:document.querySelector('input[name="rff_last_name"]'),email:document.querySelector('input[name="rff_email"]')};n.firstName&&(document.querySelector('input[name="contact_first_name"]').value=n.firstName.value),n.lastName&&(document.querySelector('input[name="contact_last_name"]').value=n.lastName.value),n.email&&(document.querySelector('input[name="contact_email"]').value=n.email.value)}}),this.shouldDisplaySignature&&this.steps.set("signature",{element:document.getElementById("displaySignatureModal"),nextButton:document.getElementById("signature-next-step"),boot:()=>this.signaturePad=new SignaturePad(document.getElementById("signature-pad"),{penColor:"rgb(0, 0, 0)"}),callback:()=>document.querySelector('input[name="signature"').value=this.signaturePad.toDataURL()}),this.shouldDisplayTerms&&this.steps.set("terms",{element:document.getElementById("displayTermsModal"),nextButton:document.getElementById("accept-terms-button")})}handleMethodSelect(t){if(document.getElementById("company_gateway_id").value=t.dataset.companyGatewayId,document.getElementById("payment_method_id").value=t.dataset.gatewayTypeId,this.steps.size===0)return this.submitForm();const e=this.steps.values().next().value;e.element.removeAttribute("style"),e.boot&&e.boot(),console.log(e),e.nextButton.addEventListener("click",()=>{e.element.setAttribute("style","display: none;"),this.steps=new Map(Array.from(this.steps.entries()).slice(1)),e.callback&&e.callback(),this.handleMethodSelect(t)})}submitForm(){this.submitting=!0,document.getElementById("payment-form").submit()}handle(){document.querySelectorAll(".dropdown-gateway-button").forEach(t=>{t.addEventListener("click",()=>{this.submitting||this.handleMethodSelect(t)})})}}const i=document.querySelector('meta[name="require-invoice-signature"]').content,o=document.querySelector('meta[name="show-invoice-terms"]').content,l=document.querySelector('meta[name="show-required-fields-form"]').content;new s(!!+o,!!+i,!!+l).handle();
|
@ -9,7 +9,7 @@
|
||||
]
|
||||
},
|
||||
"resources/js/app.js": {
|
||||
"file": "assets/app-234e3402.js",
|
||||
"file": "assets/app-e0713224.js",
|
||||
"imports": [
|
||||
"_index-08e160a7.js",
|
||||
"__commonjsHelpers-725317a4.js"
|
||||
@ -23,7 +23,7 @@
|
||||
"src": "resources/js/clients/invoices/action-selectors.js"
|
||||
},
|
||||
"resources/js/clients/invoices/payment.js": {
|
||||
"file": "assets/payment-1bdbd169.js",
|
||||
"file": "assets/payment-357f3929.js",
|
||||
"isEntry": true,
|
||||
"src": "resources/js/clients/invoices/payment.js"
|
||||
},
|
||||
@ -240,7 +240,7 @@
|
||||
"src": "resources/js/setup/setup.js"
|
||||
},
|
||||
"resources/sass/app.scss": {
|
||||
"file": "assets/app-f3b33400.css",
|
||||
"file": "assets/app-906435d5.css",
|
||||
"isEntry": true,
|
||||
"src": "resources/sass/app.scss"
|
||||
}
|
||||
|
17
resources/js/clients/invoices/payment.js
vendored
17
resources/js/clients/invoices/payment.js
vendored
@ -18,6 +18,7 @@ class Payment {
|
||||
this.steps = new Map()
|
||||
|
||||
if (this.shouldDisplayRff) {
|
||||
|
||||
this.steps.set("rff", {
|
||||
element: document.getElementById('displayRequiredFieldsModal'),
|
||||
nextButton: document.getElementById('rff-next-step'),
|
||||
@ -39,6 +40,7 @@ class Payment {
|
||||
if (fields.email) {
|
||||
document.querySelector('input[name="contact_email"]').value = fields.email.value;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -71,7 +73,20 @@ class Payment {
|
||||
element.dataset.companyGatewayId;
|
||||
document.getElementById("payment_method_id").value =
|
||||
element.dataset.gatewayTypeId;
|
||||
|
||||
|
||||
if (element.dataset.isPaypal == '1') {
|
||||
|
||||
var rff_city = document.getElementById("rff_city");
|
||||
var rff_postal_code = document.getElementById("rff_postal_code");
|
||||
|
||||
if (rff_city)
|
||||
rff_city.classList.remove('hidden');
|
||||
|
||||
if (rff_postal_code)
|
||||
rff_postal_code.classList.remove('hidden');
|
||||
|
||||
}
|
||||
|
||||
if (this.steps.size === 0) {
|
||||
return this.submitForm();
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
<a href="#" @click="open = false" dusk="pay-with-custom"
|
||||
data-company-gateway-id="{{ $method['company_gateway_id'] }}"
|
||||
data-gateway-type-id="{{ $method['gateway_type_id'] }}"
|
||||
data-is-paypal="{{ $method['is_paypal'] }}"
|
||||
class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
|
||||
dusk="payment-method">
|
||||
{{ \App\Models\CompanyGateway::find($method['company_gateway_id'])->firstOrFail()->getConfigField('name') }}
|
||||
@ -31,6 +32,7 @@
|
||||
<a href="#" @click="open = false" dusk="pay-with-{{ $index }}"
|
||||
data-company-gateway-id="{{ $method['company_gateway_id'] }}"
|
||||
data-gateway-type-id="{{ $method['gateway_type_id'] }}"
|
||||
data-is-paypal="{{ $method['is_paypal'] }}"
|
||||
class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900"
|
||||
dusk="payment-method">
|
||||
{{ $method['label'] }}
|
||||
|
@ -2,7 +2,7 @@
|
||||
style="display: none"
|
||||
id="displayRequiredFieldsModal"
|
||||
class="fixed bottom-0 inset-x-0 px-4 pb-4 sm:inset-0 sm:flex sm:items-center sm:justify-center"
|
||||
x-data="{ open: true }"
|
||||
x-data="formValidation()"
|
||||
>
|
||||
<div
|
||||
x-show="open"
|
||||
@ -45,56 +45,120 @@
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{{ ctrans('texts.details') }}
|
||||
</h3>
|
||||
<div class="mt-2">
|
||||
@if(strlen(auth()->guard('contact')->user()->first_name) === 0)
|
||||
<div class="col-span-6 sm:col-span-3">
|
||||
<label for="first_name" class="input-label">{{ ctrans('texts.first_name') }}</label>
|
||||
<input id="first_name" class="input w-full" name="rff_first_name" value="{{ auth()->guard('contact')->user()->first_name }}" />
|
||||
<label for="rff_first_name" class="input-label">{{ ctrans('texts.first_name') }}</label>
|
||||
<input
|
||||
id="rff_first_name"
|
||||
class="input w-full"
|
||||
name="rff_first_name"
|
||||
value="{{ auth()->guard('contact')->user()->first_name }}"
|
||||
x-model="rff_first_name"
|
||||
@blur="validateFirstName()"
|
||||
:class="{ 'border-red-500': errors.rff_first_name }"
|
||||
/>
|
||||
<span x-show="errors.rff_first_name" class="validation validation-fail block w-full" role="alert" x-text="errors.rff_first_name"></span>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(strlen(auth()->guard('contact')->user()->last_name) === 0)
|
||||
<div class="col-span-6 sm:col-span-3">
|
||||
<label for="last_name" class="input-label">{{ ctrans('texts.last_name') }}</label>
|
||||
<input id="last_name" class="input w-full" name="rff_last_name" value="{{ auth()->guard('contact')->user()->last_name }}"/>
|
||||
<label for="rff_last_name" class="input-label">{{ ctrans('texts.last_name') }}</label>
|
||||
<input
|
||||
id="rff_last_name"
|
||||
class="input w-full"
|
||||
name="rff_last_name"
|
||||
x-model="rff_last_name"
|
||||
@blur="validateLastName()"
|
||||
:class="{ 'border-red-500': errors.rff_last_name }"
|
||||
/>
|
||||
<span x-show="errors.rff_last_name" class="validation validation-fail block w-full" role="alert" x-text="errors.rff_last_name"></span>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(strlen(auth()->guard('contact')->user()->email) === 0)
|
||||
<div class="col-span-6 sm:col-span-3">
|
||||
<label for="email" class="input-label">{{ ctrans('texts.email') }}</label>
|
||||
<input id="email" class="input w-full" name="rff_email" value="{{ auth()->guard('contact')->user()->email }}"/>
|
||||
<input
|
||||
id="rff_email"
|
||||
class="input w-full"
|
||||
name="rff_email"
|
||||
x-model="rff_email"
|
||||
@blur="validateEmail()"
|
||||
:class="{ 'border-red-500': errors.rff_email }"
|
||||
/>
|
||||
<span x-show="errors.rff_email" class="validation validation-fail block w-full" role="alert" x-text="errors.rff_email"></span>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(strlen(auth()->guard('contact')->user()->client->city) === 0)
|
||||
<div class="col-span-6 sm:col-span-3 hidden" id="rff_city">
|
||||
<label for="city" class="input-label">{{ ctrans('texts.city') }}</label>
|
||||
<input
|
||||
id="rff_city"
|
||||
class="input w-full"
|
||||
name="rff_city"
|
||||
x-model="rff_city"
|
||||
@blur="validateCity()"
|
||||
:class="{ 'border-red-500': errors.rff_city }"
|
||||
/>
|
||||
<span x-show="errors.rff_city" class="validation validation-fail block w-full" role="alert" x-text="errors.rff_city"></span>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(strlen(auth()->guard('contact')->user()->client->postal_code) === 0)
|
||||
<div class="col-span-6 sm:col-span-3 hidden" id="rff_postal_code">
|
||||
<label for="postal_code" class="input-label">{{ ctrans('texts.postal_code') }}</label>
|
||||
<input
|
||||
id="rff_postal_code"
|
||||
class="input w-full"
|
||||
name="rff_postal_code"
|
||||
x-model="rff_postal_code"
|
||||
@blur="validatePostalCode()"
|
||||
:class="{ 'border-red-500': errors.rff_postal_code }"
|
||||
/>
|
||||
<span x-show="errors.rff_postal_code" class="validation validation-fail block w-full" role="alert" x-text="errors.rff_postal_code"></span>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse" >
|
||||
<div
|
||||
class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto"
|
||||
x-data
|
||||
>
|
||||
class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto">
|
||||
<button
|
||||
type="button"
|
||||
id="rff-next-step"
|
||||
@@click="validateForm"
|
||||
class="button button-primary bg-primary"
|
||||
>
|
||||
{{ ctrans('texts.next_step') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
id="rff-next-step"
|
||||
class="hidden">
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<div
|
||||
class="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto"
|
||||
x-data
|
||||
|
||||
>
|
||||
<button
|
||||
@click="document.getElementById('displayRequiredFieldsModal').style.display = 'none';"
|
||||
type="button"
|
||||
class="button button-secondary"
|
||||
id="close-button"
|
||||
@click="document.getElementById('displayRequiredFieldsModal').style.display = 'none';"
|
||||
>
|
||||
{{ ctrans('texts.close') }}
|
||||
</button>
|
||||
@ -102,3 +166,64 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function formValidation() {
|
||||
|
||||
return {
|
||||
open: true,
|
||||
rff_last_name: '{{ auth()->guard('contact')->user()->last_name }}',
|
||||
rff_first_name: '{{ auth()->guard('contact')->user()->first_name }}',
|
||||
rff_email: '{{ auth()->guard('contact')->user()->email }}',
|
||||
rff_city: '{{ auth()->guard('contact')->user()->client->city }}',
|
||||
rff_postal_code: '{{ auth()->guard('contact')->user()->client->postal_code }}',
|
||||
errors: {
|
||||
rff_first_name: '',
|
||||
rff_last_name: '',
|
||||
rff_city: '',
|
||||
rff_postal_code: '',
|
||||
rff_email: ''
|
||||
},
|
||||
|
||||
validateFirstName() {
|
||||
this.errors.rff_first_name = this.rff_first_name.trim() === '' ? '{{ ctrans('texts.first_name') }}' + ' ' + '{{ ctrans('texts.required') }}' : '';
|
||||
},
|
||||
|
||||
validateLastName() {
|
||||
this.errors.rff_last_name = this.rff_last_name.trim() === '' ? '{{ ctrans('texts.last_name') }}' + ' ' + '{{ ctrans('texts.required') }}' : '';
|
||||
},
|
||||
|
||||
validateEmail() {
|
||||
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
this.errors.rff_email = !emailPattern.test(this.rff_email.trim()) ? '{{ ctrans('texts.provide_email') }}' : '';
|
||||
},
|
||||
|
||||
validatePostalCode() {
|
||||
this.errors.rff_postal_code = this.rff_postal_code.trim() === '' ? '{{ ctrans('texts.postal_code') }}' + ' ' + '{{ ctrans('texts.required') }}' : '';
|
||||
},
|
||||
|
||||
validateCity() {
|
||||
this.errors.rff_city = this.rff_city.trim() === '' ? '{{ ctrans('texts.city') }}' + ' ' + '{{ ctrans('texts.required') }}' : '';
|
||||
},
|
||||
|
||||
validateForm() {
|
||||
|
||||
this.validateFirstName();
|
||||
this.validateLastName();
|
||||
this.validateEmail();
|
||||
this.validateCity();
|
||||
this.validatePostalCode();
|
||||
|
||||
if (!this.errors.rff_first_name && !this.errors.rff_last_name) {
|
||||
|
||||
const next_rff = document.getElementById('rff-next-step');
|
||||
next_rff.click();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
@ -22,6 +22,9 @@
|
||||
<input type="hidden" name="contact_last_name" value="{{ auth()->guard('contact')->user()->last_name }}">
|
||||
<input type="hidden" name="contact_email" value="{{ auth()->guard('contact')->user()->email }}">
|
||||
|
||||
<input type="hidden" name="client_city" value="{{ auth()->guard('contact')->user()->client->city }}">
|
||||
<input type="hidden" name="client_postal_code" value="{{ auth()->guard('contact')->user()->client->postal_code }}">
|
||||
|
||||
<div class="container mx-auto">
|
||||
<div class="grid grid-cols-6 gap-4">
|
||||
<div class="col-span-6 md:col-start-2 md:col-span-4">
|
||||
|
Loading…
Reference in New Issue
Block a user