diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php
index 22fcba5c52ab..95df25c6c2cf 100644
--- a/app/Console/Commands/CheckData.php
+++ b/app/Console/Commands/CheckData.php
@@ -13,6 +13,7 @@ namespace App\Console\Commands;
use App;
use App\Factory\ClientContactFactory;
+use App\Factory\VendorContactFactory;
use App\Models\Account;
use App\Models\Client;
use App\Models\ClientContact;
@@ -72,7 +73,7 @@ class CheckData extends Command
/**
* @var string
*/
- protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--paid_to_date=} {--client_balance=}';
+ protected $signature = 'ninja:check-data {--database=} {--fix=} {--client_id=} {--vendor_id=} {--paid_to_date=} {--client_balance=}';
/**
* @var string
@@ -112,6 +113,7 @@ class CheckData extends Command
$this->checkClientBalances();
$this->checkContacts();
+ $this->checkVendorContacts();
$this->checkEntityInvitations();
$this->checkCompanyData();
@@ -248,6 +250,65 @@ class CheckData extends Command
}
+ private function checkVendorContacts()
+ {
+ // check for contacts with the contact_key value set
+ $contacts = DB::table('vendor_contacts')
+ ->whereNull('contact_key')
+ ->orderBy('id')
+ ->get(['id']);
+ $this->logMessage($contacts->count().' contacts without a contact_key');
+
+ if ($contacts->count() > 0) {
+ $this->isValid = false;
+ }
+
+ if ($this->option('fix') == 'true') {
+ foreach ($contacts as $contact) {
+ DB::table('vendor_contacts')
+ ->where('id', '=', $contact->id)
+ ->whereNull('contact_key')
+ ->update([
+ 'contact_key' => Str::random(config('ninja.key_length')),
+ ]);
+ }
+ }
+
+ // check for missing contacts
+ $vendors = DB::table('vendors')
+ ->leftJoin('vendor_contacts', function ($join) {
+ $join->on('vendor_contacts.vendor_id', '=', 'vendors.id')
+ ->whereNull('vendor_contacts.deleted_at');
+ })
+ ->groupBy('vendors.id', 'vendors.user_id', 'vendors.company_id')
+ ->havingRaw('count(vendor_contacts.id) = 0');
+
+ if ($this->option('vendor_id')) {
+ $vendors->where('vendors.id', '=', $this->option('vendor_id'));
+ }
+
+ $vendors = $vendors->get(['vendors.id', 'vendors.user_id', 'vendors.company_id']);
+ $this->logMessage($vendors->count().' vendors without any contacts');
+
+ if ($vendors->count() > 0) {
+ $this->isValid = false;
+ }
+
+ if ($this->option('fix') == 'true') {
+ foreach ($vendors as $vendor) {
+ $this->logMessage("Fixing missing vendor contacts #{$vendor->id}");
+
+ $new_contact = VendorContactFactory::create($vendor->company_id, $vendor->user_id);
+ $new_contact->vendor_id = $vendor->id;
+ $new_contact->contact_key = Str::random(40);
+ $new_contact->is_primary = true;
+ $new_contact->save();
+ }
+ }
+
+ }
+
+
private function checkFailedJobs()
{
if (config('ninja.testvars.travis')) {
diff --git a/app/Jobs/Entity/CreateEntityPdf.php b/app/Jobs/Entity/CreateEntityPdf.php
index e0d32d9532c9..f89ca3103990 100644
--- a/app/Jobs/Entity/CreateEntityPdf.php
+++ b/app/Jobs/Entity/CreateEntityPdf.php
@@ -168,10 +168,10 @@ class CreateEntityPdf implements ShouldQueue
]),
'variables' => $variables,
'options' => [
- 'all_pages_header' => $this->client->getSetting('all_pages_header'),
- 'all_pages_footer' => $this->client->getSetting('all_pages_footer'),
+ 'all_pages_header' => $this->entity->client->getSetting('all_pages_header'),
+ 'all_pages_footer' => $this->entity->client->getSetting('all_pages_footer'),
],
- 'process_markdown' => $this->client->company->markdown_enabled,
+ 'process_markdown' => $this->entity->client->company->markdown_enabled,
];
$maker = new PdfMakerService($state);
diff --git a/app/Models/Gateway.php b/app/Models/Gateway.php
index 84b13e104c03..3890db1c03f4 100644
--- a/app/Models/Gateway.php
+++ b/app/Models/Gateway.php
@@ -149,6 +149,7 @@ class Gateway extends StaticModel
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']],
+ GatewayType::FPX => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
];
break;
case 57:
diff --git a/app/PaymentDrivers/Stripe/SEPA.php b/app/PaymentDrivers/Stripe/SEPA.php
index ac2d0ccd81f6..afa218097f61 100644
--- a/app/PaymentDrivers/Stripe/SEPA.php
+++ b/app/PaymentDrivers/Stripe/SEPA.php
@@ -47,7 +47,7 @@ class SEPA
$data['country'] = $this->stripe->client->country->iso_3166_2;
$data['payment_hash'] = $this->stripe->payment_hash->hash;
- $intent = \Stripe\PaymentIntent::create([
+ $intent_data = [
'amount' => $data['stripe_amount'],
'currency' => 'eur',
'payment_method_types' => ['sepa_debit'],
@@ -58,19 +58,12 @@ class SEPA
'payment_hash' => $this->stripe->payment_hash->hash,
'gateway_type_id' => GatewayType::SEPA,
],
- ], $this->stripe->stripe_connect_auth);
+ ];
+
+ $intent = \Stripe\PaymentIntent::create($intent_data, $this->stripe->stripe_connect_auth);
$data['pi_client_secret'] = $intent->client_secret;
- if (count($data['tokens']) > 0) {
- $setup_intent = $this->stripe->stripe->setupIntents->create([
- 'payment_method_types' => ['sepa_debit'],
- 'customer' => $this->stripe->findOrCreateCustomer()->id,
- ]);
-
- $data['si_client_secret'] = $setup_intent->client_secret;
- }
-
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
$this->stripe->payment_hash->save();
diff --git a/app/Utils/Helpers.php b/app/Utils/Helpers.php
index ca4a7e5d5b7f..c80b55dc6089 100644
--- a/app/Utils/Helpers.php
+++ b/app/Utils/Helpers.php
@@ -263,9 +263,7 @@ class Helpers
}
return $value;
-
// $x = str_replace(["\n", "
"], ["\r", "
"], $value);
-
// return $x;
}
diff --git a/public/js/clients/payments/stripe-sepa.js b/public/js/clients/payments/stripe-sepa.js
index 5769f96f3c3b..308730e5e60a 100644
--- a/public/js/clients/payments/stripe-sepa.js
+++ b/public/js/clients/payments/stripe-sepa.js
@@ -1,2 +1,2 @@
/*! For license information please see stripe-sepa.js.LICENSE.txt */
-(()=>{var e,t,n,o;function a(e,t){for(var n=0;n svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmSepaDebitSetup(document.querySelector("meta[name=si-client-secret").content,{payment_method:document.querySelector("input[name=token]").value}).then((function(e){if(!e.error)return document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.setupIntent),document.querySelector("#server-response").submit();console.error(error)})).catch((function(t){e.textContent=t,e.hidden=!1}))):""===document.getElementById("sepa-name").value?(document.getElementById("sepa-name").focus(),e.textContent=document.querySelector("meta[name=translation-name-required]").content,void(e.hidden=!1)):""===document.getElementById("sepa-email-address").value?(document.getElementById("sepa-email-address").focus(),e.textContent=document.querySelector("meta[name=translation-email-required]").content,void(e.hidden=!1)):document.getElementById("sepa-mandate-acceptance").checked?(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),void o.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{sepa_debit:o.iban,billing_details:{name:document.getElementById("sepa-name").value,email:document.getElementById("sepa-email-address").value}}}).then((function(e){return e.error?o.handleFailure(e.error.message):o.handleSuccess(e)}))):(e.textContent=document.querySelector("meta[name=translation-terms-required]").content,e.hidden=!1,void console.log("Terms"))}))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}var t,n,o;return t=e,(n=[{key:"handleSuccess",value:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.paymentIntent);var t=document.querySelector('input[name="token-billing-checkbox"]:checked');t&&(document.querySelector('input[name="store_card"]').value=t.value),document.getElementById("server-response").submit()}},{key:"handleFailure",value:function(e){var t=document.getElementById("errors");t.textContent="",t.textContent=e,t.hidden=!1,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}}])&&a(t.prototype,n),o&&a(t,o),e}();new c(null!==(e=null===(t=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===t?void 0:t.content)&&void 0!==e?e:"",null!==(n=null===(o=document.querySelector('meta[name="stripe-account-id"]'))||void 0===o?void 0:o.content)&&void 0!==n?n:"").setupStripe().handle()})();
\ No newline at end of file
+(()=>{var e,t,n,a;function o(e,t){for(var n=0;n svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),a.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:document.querySelector("input[name=token]").value}).then((function(e){return e.error?a.handleFailure(e.error.message):a.handleSuccess(e)}));else{if(""===document.getElementById("sepa-name").value)return document.getElementById("sepa-name").focus(),e.textContent=document.querySelector("meta[name=translation-name-required]").content,void(e.hidden=!1);if(""===document.getElementById("sepa-email-address").value)return document.getElementById("sepa-email-address").focus(),e.textContent=document.querySelector("meta[name=translation-email-required]").content,void(e.hidden=!1);if(!document.getElementById("sepa-mandate-acceptance").checked)return e.textContent=document.querySelector("meta[name=translation-terms-required]").content,void(e.hidden=!1);document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),a.stripe.confirmSepaDebitPayment(document.querySelector("meta[name=pi-client-secret").content,{payment_method:{sepa_debit:a.iban,billing_details:{name:document.getElementById("sepa-name").value,email:document.getElementById("sepa-email-address").value}}}).then((function(e){return e.error?a.handleFailure(e.error.message):a.handleSuccess(e)}))}}))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n}var t,n,a;return t=e,(n=[{key:"handleSuccess",value:function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e.paymentIntent);var t=document.querySelector('input[name="token-billing-checkbox"]:checked');t&&(document.querySelector('input[name="store_card"]').value=t.value),document.getElementById("server-response").submit()}},{key:"handleFailure",value:function(e){var t=document.getElementById("errors");t.textContent="",t.textContent=e,t.hidden=!1,document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}}])&&o(t.prototype,n),a&&o(t,a),e}();new c(null!==(e=null===(t=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===t?void 0:t.content)&&void 0!==e?e:"",null!==(n=null===(a=document.querySelector('meta[name="stripe-account-id"]'))||void 0===a?void 0:a.content)&&void 0!==n?n:"").setupStripe().handle()})();
\ No newline at end of file
diff --git a/public/mix-manifest.json b/public/mix-manifest.json
index 5ea689623061..57a00472a44c 100755
--- a/public/mix-manifest.json
+++ b/public/mix-manifest.json
@@ -27,7 +27,7 @@
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=8f05ce6bd2d6cae7e5f2",
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=4ed4c8a09803ddd0a9a7",
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=c36ab5621413ef1de7c8",
- "/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=2daa1a70aa5f8e6988f5",
+ "/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=da7b16ffaf5645535c7c",
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=61becda97682c7909f29",
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=2a973971ed2b890524ee",
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=41367f4e80e52a0ab436",
diff --git a/resources/js/clients/payments/stripe-sepa.js b/resources/js/clients/payments/stripe-sepa.js
index e794eb9c823e..28e6fa69dfca 100644
--- a/resources/js/clients/payments/stripe-sepa.js
+++ b/resources/js/clients/payments/stripe-sepa.js
@@ -17,26 +17,21 @@ class ProcessSEPA {
setupStripe = () => {
- if (this.stripeConnect){
- // this.stripe.stripeAccount = this.stripeConnect;
-
- this.stripe = Stripe(this.key, {
- stripeAccount: this.stripeConnect,
- });
-
- }
- else {
+ if (this.stripeConnect) {
+
+ this.stripe = Stripe(this.key, {
+ stripeAccount: this.stripeConnect,
+ });
+
+ } else {
this.stripe = Stripe(this.key);
}
-
-
const elements = this.stripe.elements();
var style = {
base: {
color: '#32325d',
- fontFamily:
- '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
@@ -65,6 +60,10 @@ class ProcessSEPA {
};
this.iban = elements.create('iban', options);
this.iban.mount('#sepa-iban');
+
+ document.getElementById('sepa-name').value = document.querySelector('meta[name=client_name]').content;
+ document.getElementById('sepa-email-address').value = document.querySelector('meta[name=client_email]').content;
+
return this;
};
@@ -97,107 +96,92 @@ class ProcessSEPA {
});
document.getElementById('pay-now').addEventListener('click', (e) => {
- if (
- document.querySelector('input[name=token]').value.length !== 0
- ) {
- document.querySelector('#errors').hidden = true;
+
+ console.log(document.querySelector('input[name=token]').value);
+
+ if (document.querySelector('input[name=token]').value.length !== 0) {
document.getElementById('pay-now').disabled = true;
- document
- .querySelector('#pay-now > svg')
- .classList.remove('hidden');
- document
- .querySelector('#pay-now > span')
- .classList.add('hidden');
+ document.querySelector('#pay-now > svg').classList.remove('hidden');
+ document.querySelector('#pay-now > span').classList.add('hidden');
this.stripe
- .confirmSepaDebitSetup(
- document.querySelector('meta[name=si-client-secret')
- .content,
- {
- payment_method: document.querySelector(
- 'input[name=token]'
- ).value,
+ .confirmSepaDebitPayment(
+ document.querySelector('meta[name=pi-client-secret')
+ .content, {
+ payment_method: document.querySelector('input[name=token]').value
}
)
.then((result) => {
if (result.error) {
- console.error(error);
-
- return;
+ return this.handleFailure(result.error.message);
}
- document.querySelector(
- 'input[name="gateway_response"]'
- ).value = JSON.stringify(result.setupIntent);
-
- return document
- .querySelector('#server-response')
- .submit();
- })
- .catch((error) => {
- errors.textContent = error;
- errors.hidden = false;
+ return this.handleSuccess(result);
});
- return;
- }
+ } else {
- if (document.getElementById('sepa-name').value === '') {
- document.getElementById('sepa-name').focus();
- errors.textContent = document.querySelector(
- 'meta[name=translation-name-required]'
- ).content;
- errors.hidden = false;
- return;
- }
+ if (document.getElementById('sepa-name').value === '') {
+ document.getElementById('sepa-name').focus();
+ errors.textContent = document.querySelector(
+ 'meta[name=translation-name-required]'
+ ).content;
+ errors.hidden = false;
+ return;
+ }
- if (document.getElementById('sepa-email-address').value === '') {
- document.getElementById('sepa-email-address').focus();
- errors.textContent = document.querySelector(
- 'meta[name=translation-email-required]'
- ).content;
- errors.hidden = false;
- return;
- }
+ if (document.getElementById('sepa-email-address').value === '') {
+ document.getElementById('sepa-email-address').focus();
+ errors.textContent = document.querySelector(
+ 'meta[name=translation-email-required]'
+ ).content;
+ errors.hidden = false;
+ return;
+ }
- if (!document.getElementById('sepa-mandate-acceptance').checked) {
- errors.textContent = document.querySelector(
- 'meta[name=translation-terms-required]'
- ).content;
- errors.hidden = false;
- console.log('Terms');
- return;
- }
+ if (!document.getElementById('sepa-mandate-acceptance').checked) {
+ errors.textContent = document.querySelector(
+ 'meta[name=translation-terms-required]'
+ ).content;
+ errors.hidden = false;
- document.getElementById('pay-now').disabled = true;
- document.querySelector('#pay-now > svg').classList.remove('hidden');
- document.querySelector('#pay-now > span').classList.add('hidden');
+ return;
+ }
- this.stripe
- .confirmSepaDebitPayment(
- document.querySelector('meta[name=pi-client-secret')
- .content,
- {
- payment_method: {
- sepa_debit: this.iban,
- billing_details: {
- name: document.getElementById('sepa-name')
- .value,
- email: document.getElementById(
- 'sepa-email-address'
- ).value,
+
+ document.getElementById('pay-now').disabled = true;
+ document.querySelector('#pay-now > svg').classList.remove('hidden');
+ document.querySelector('#pay-now > span').classList.add('hidden');
+
+
+
+ this.stripe
+ .confirmSepaDebitPayment(
+ document.querySelector('meta[name=pi-client-secret')
+ .content, {
+ payment_method: {
+ sepa_debit: this.iban,
+ billing_details: {
+ name: document.getElementById('sepa-name')
+ .value,
+ email: document.getElementById(
+ 'sepa-email-address'
+ ).value,
+ },
},
- },
- }
- )
- .then((result) => {
- if (result.error) {
- return this.handleFailure(result.error.message);
- }
+ }
+ )
+ .then((result) => {
+ if (result.error) {
+ return this.handleFailure(result.error.message);
+ }
+
+ return this.handleSuccess(result);
+ });
+
+ }
- return this.handleSuccess(result);
- });
});
};
@@ -232,10 +216,10 @@ class ProcessSEPA {
}
const publishableKey =
- document.querySelector('meta[name="stripe-publishable-key"]')?.content ??
+ document.querySelector('meta[name="stripe-publishable-key"]') ? .content ? ?
'';
const stripeConnect =
- document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
+ document.querySelector('meta[name="stripe-account-id"]') ? .content ? ? '';
new ProcessSEPA(publishableKey, stripeConnect).setupStripe().handle();
diff --git a/resources/views/portal/ninja2020/gateways/stripe/sepa/pay.blade.php b/resources/views/portal/ninja2020/gateways/stripe/sepa/pay.blade.php
index 0eb9248ec828..2fb9c49c94a7 100644
--- a/resources/views/portal/ninja2020/gateways/stripe/sepa/pay.blade.php
+++ b/resources/views/portal/ninja2020/gateways/stripe/sepa/pay.blade.php
@@ -6,6 +6,8 @@
+
+