Fixes for text body templates

This commit is contained in:
David Bomba 2024-06-13 16:52:23 +10:00
parent de853b3445
commit d23866932b
8 changed files with 241 additions and 13 deletions

View File

@ -126,7 +126,7 @@ class BaseEmailEngine implements EngineInterface
if (! empty($this->variables)) {
$text = str_replace(['$paymentLink', '$viewButton', '$view_button', '$viewLink', '$view_link'], '$view_url', $text);
$text = str_replace(['$paymentLink', '$viewButton', '$view_button', '$viewLink', '$view_link'], "\r\n\r\n".'$view_url'."\r\n", $text);
$text = str_replace(array_keys($this->variables), array_values($this->variables), $text);
$text = str_replace(array_keys($this->variables), array_values($this->variables), $text);

View File

@ -16,6 +16,7 @@ use Carbon\Carbon;
use App\Models\Invoice;
use App\Models\SystemLog;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use Illuminate\Http\Request;
use App\Jobs\Util\SystemLogger;
@ -30,6 +31,8 @@ class PayPalBasePaymentDriver extends BaseDriver
{
use MakesHash;
public string $risk_guid;
public $token_billing = true;
public $can_authorise_credit_card = false;
@ -106,6 +109,7 @@ class PayPalBasePaymentDriver extends BaseDriver
public function init()
{
$this->risk_guid = Str::random(32);
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
@ -432,6 +436,7 @@ class PayPalBasePaymentDriver extends BaseDriver
'Accept-Language' => 'en_US',
'PayPal-Partner-Attribution-Id' => 'invoiceninja_SP_PPCP',
'PayPal-Request-Id' => Str::uuid()->toString(),
'PAYPAL-CLIENT-METADATA-ID' => $this->risk_guid,
], $headers);
}
@ -479,5 +484,5 @@ class PayPalBasePaymentDriver extends BaseDriver
PayPalWebhook::dispatch($request->all(), $request->headers->all(), $this->access_token);
}
}

View File

@ -16,6 +16,7 @@ use Carbon\Carbon;
use App\Models\Invoice;
use App\Models\SystemLog;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use Illuminate\Http\Request;
use App\Jobs\Util\SystemLogger;
@ -84,6 +85,7 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
*/
public function processPaymentView($data)
{
$this->init()->checkPaymentsReceivable();
$data['gateway'] = $this;
@ -97,6 +99,7 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
$data['gateway_type_id'] = $this->gateway_type_id;
$data['merchantId'] = $this->company_gateway->getConfigField('merchantId');
$data['currency'] = $this->client->currency()->code;
$data['guid'] = $this->risk_guid;
if($this->gateway_type_id == 29)
return render('gateways.paypal.ppcp.card', $data);
@ -109,7 +112,6 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
* Processes the payment response
*
* @param mixed $request
* @return void
*/
public function processPaymentResponse($request)
{
@ -366,4 +368,73 @@ class PayPalPPCPPaymentDriver extends PayPalBasePaymentDriver
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
{
$data = [];
$this->payment_hash = $payment_hash;
$data['amount_with_fee'] = $this->payment_hash->data->amount_with_fee;
$data["payment_source"] = [
"card" => [
"vault_id" => $cgt->token,
"stored_credential" => [
"payment_initiator" => "MERCHANT",
"payment_type" => "UNSCHEDULED",
"usage" => "SUBSEQUENT",
],
],
];
$orderId = $this->createOrder($data);
$r = false;
try {
$r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']);
if($r->status() == 422) {
//handle conditions where the client may need to try again.
$r = $this->handleDuplicateInvoiceId($orderId);
}
} catch(\Exception $e) {
//Rescue for duplicate invoice_id
if(stripos($e->getMessage(), 'DUPLICATE_INVOICE_ID') !== false) {
$r = $this->handleDuplicateInvoiceId($orderId);
}
}
$response = $r->json();
$data = [
'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP,
$this->client,
$this->client->company,
);
}
}

View File

@ -20,6 +20,7 @@ use App\Jobs\Util\SystemLogger;
use App\Utils\Traits\MakesHash;
use App\Exceptions\PaymentFailed;
use App\Models\ClientGatewayToken;
use App\Models\PaymentHash;
use App\PaymentDrivers\PayPal\PayPalBasePaymentDriver;
class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
@ -30,6 +31,7 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
public function processPaymentView($data)
{
$this->init();
$data['gateway'] = $this;
@ -43,6 +45,7 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
$data['funding_source'] = $this->paypal_payment_method;
$data['gateway_type_id'] = $this->gateway_type_id;
$data['currency'] = $this->client->currency()->code;
$data['guid'] = $this->risk_guid;
if($this->gateway_type_id == 29)
return render('gateways.paypal.ppcp.card', $data);
@ -56,7 +59,6 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
* processPaymentResponse
*
* @param mixed $request
* @return void
*/
public function processPaymentResponse($request)
{
@ -291,7 +293,6 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
*
* @param mixed $request
* @param array $response
* @return void
*/
public function processTokenPayment($request, array $response) {
@ -342,4 +343,72 @@ class PayPalRestPaymentDriver extends PayPalBasePaymentDriver
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
}
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
{
$data = [];
$this->payment_hash = $payment_hash;
$data['amount_with_fee'] = $this->payment_hash->data->amount_with_fee;
$data["payment_source"] = [
"card" => [
"vault_id" => $cgt->token,
"stored_credential" => [
"payment_initiator" => "MERCHANT",
"payment_type" => "UNSCHEDULED",
"usage" => "SUBSEQUENT",
],
],
];
$orderId = $this->createOrder($data);
$r = false;
try {
$r = $this->gatewayRequest("/v2/checkout/orders/{$orderId}", 'get', ['body' => '']);
if($r->status() == 422) {
//handle conditions where the client may need to try again.
$r = $this->handleDuplicateInvoiceId($orderId);
}
} catch(\Exception $e) {
//Rescue for duplicate invoice_id
if(stripos($e->getMessage(), 'DUPLICATE_INVOICE_ID') !== false) {
$r = $this->handleDuplicateInvoiceId($orderId);
}
}
$response = $r->json();
$data = [
'payment_type' => $this->getPaymentMethod((string)$cgt->gateway_type_id),
'amount' => $response['purchase_units'][0]['payments']['captures'][0]['amount']['value'],
'transaction_reference' => $response['purchase_units'][0]['payments']['captures'][0]['id'],
'gateway_type_id' => $this->gateway_type_id,
];
$payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
SystemLogger::dispatch(
['response' => $response, 'data' => $data],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL_PPCP,
$this->client,
$this->client->company,
);
}
}

View File

@ -180,7 +180,7 @@ class EmailDefaults
$breaks = ["<br />","<br>","<br/>"];
$this->email->email_object->text_body = str_ireplace($breaks, "\r\n", $this->email->email_object->body);
$this->email->email_object->text_body = strip_tags($this->email->email_object->text_body);
$this->email->email_object->text_body = str_replace(['$view_button','$viewButton'], '$view_url', $this->email->email_object->text_body);
$this->email->email_object->text_body = str_replace(['$view_button','$viewButton'], "\r\n\r\n".'$view_url'."\r\n", $this->email->email_object->text_body);
if ($this->template == 'email.template.custom') {
$this->email->email_object->body = (str_replace('$body', $this->email->email_object->body, str_replace(["\r","\n"], "", $this->email->email_object->settings->email_style_custom)));

View File

@ -29,6 +29,17 @@
@endsection
@push('footer')
<script type="application/json" fncls="fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99">
{
"f":"{{ $guid }}",
"s":"paypal.pay" // unique ID for each web page
}
</script>
<script type="text/javascript" src="https://c.paypal.com/da/r/fb.js"></script>
<style type="text/css">
.loader {
width: 48px;

View File

@ -75,6 +75,14 @@
@endsection
@push('footer')
<script type="application/json" fncls="fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99">
{
"f":"{{ $guid }}",
"s":"paypal.card" // unique ID for each web page
}
</script>
<script type="text/javascript" src="https://c.paypal.com/da/r/fb.js"></script>
@if(isset($merchantId))
<script src="https://www.paypal.com/sdk/js?client-id={!! $client_id !!}&merchantId={!! $merchantId !!}&components=card-fields" data-partner-attribution-id="invoiceninja_SP_PPCP"></script>
@ -150,6 +158,10 @@
})
.catch(error => {
console.error('Error:', error);
document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`;
document.getElementById('errors').hidden = false;
});
},
@ -157,12 +169,20 @@
window.location.href = "/client/invoices/";
},
onError: function(error) {
// onError: function(error) {
document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${error.message}`;
document.getElementById('errors').hidden = false;
},
// console.log("submit catch");
// const errorM = parseError(error);
// console.log(errorM);
// const msg = handle422Error(errorM);
// document.getElementById('errors').textContent = `Sorry, your transaction could not be processed...\n\n${msg.description}`;
// document.getElementById('errors').hidden = false;
// },
onClick: function (){
}
@ -213,10 +233,18 @@
document.querySelector('#pay-now > span').classList.add('hidden');
cardField.submit().then((response) => {
cardField.submit().then(() => {
}).catch((error) => {
let msg;
if(!['INVALID_NUMBER','INVALID_CVV','INVALID_EXPIRY'].includes(error.message))
{
const errorM = parseError(error.message);
msg = handle422Error(errorM);
}
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
@ -230,7 +258,9 @@
else if(error.message == 'INVALID_EXPIRY') {
document.getElementById('errors').textContent = "{{ ctrans('texts.invalid_cvv') }}";
}
else if(msg.description){
document.getElementById('errors').textContent = msg?.description;
}
document.getElementById('errors').hidden = false;
});
@ -242,6 +272,39 @@
}
function handle422Error(errorData) {
const errorDetails = errorData.details || [];
const detail = errorDetails[0];
return detail;
}
function parseError(errorMessage)
{
try {
JSON.parse(errorMessage);
return errorMessage;
} catch (e) {
}
const startIndex = errorMessage.indexOf('{');
const endIndex = errorMessage.lastIndexOf('}');
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
const jsonString = errorMessage.substring(startIndex, endIndex + 1);
try {
const json = JSON.parse(jsonString);
return json;
} catch (error) {
return null;
}
} else {
return null;
}
}
</script>
@ -266,7 +329,6 @@
if (payWithCreditCardToggle) {
payWithCreditCardToggle
.addEventListener('click', () => {
console.log("Cc");
document
.getElementById('save-card--container').style.display = 'grid';
document

View File

@ -25,6 +25,16 @@
@push('footer')
<script type="application/json" fncls="fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99">
{
"f":"{{ $guid }}",
"s":"paypal.ppcp.pay" // unique ID for each web page
}
</script>
<script type="text/javascript" src="https://c.paypal.com/da/r/fb.js"></script>
<script src="https://www.paypal.com/sdk/js?client-id={!! $client_id !!}&currency={!! $currency !!}&merchant-id={!! $merchantId !!}&components=buttons,funding-eligibility&intent=capture&enable-funding={!! $funding_source !!}" data-partner-attribution-id="invoiceninja_SP_PPCP"></script>
<script>