254 lines
7.7 KiB
PHP
254 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs\Payment;
|
|
|
|
use App\Enums\Order\PaymentModeEnum;
|
|
use App\Enums\Order\TransactionStatus;
|
|
use App\Enums\Order\TransactionType;
|
|
use App\Models\Payment\Transaction;
|
|
use LDC\LaravelSystempay\Enums\ResponseType;
|
|
use LDC\LaravelSystempay\LaravelSystempay;
|
|
|
|
/**
|
|
* Ping transaction status and update itself.
|
|
* Utilise du code de laravel-systempay pour parser le statut de la réponse
|
|
* Ceci est un doublon car Systempay ne notifie pas de transactions remboursés depuis la boutique
|
|
*/
|
|
class SystempayCreditTransactionUpdate
|
|
{
|
|
/**
|
|
* Used in loop
|
|
*
|
|
* @var \App\Models\Payment\Transaction|null
|
|
*/
|
|
private $currentTransaction;
|
|
|
|
/**
|
|
* Used in loop
|
|
*
|
|
* @var \Illuminate\Support\Collection|null
|
|
*/
|
|
private $currentTransactionResponse;
|
|
|
|
/**
|
|
* Called when the job will be executed.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function handle()
|
|
{
|
|
Transaction::query()
|
|
->where('type', TransactionType::credit())
|
|
->where('status', TransactionStatus::pending())
|
|
->where('payment_mode', PaymentModeEnum::systemPay())
|
|
->each(function (Transaction $transaction) {
|
|
$this->currentTransaction = $transaction;
|
|
\call_user_func([$this, 'handleTransaction']);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Fetch system pay transaction and update its status
|
|
*
|
|
* @return void
|
|
* @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
|
|
*/
|
|
private function handleTransaction(): void
|
|
{
|
|
// phpcs:enable
|
|
$systemPay = $this->getPayment();
|
|
$client = $systemPay->generateRestClient();
|
|
|
|
$this->currentTransactionResponse = $client->get(
|
|
$this->currentTransaction->foreign_refund_id
|
|
);
|
|
|
|
$reponseType = $this->getReponseType(data_get($this->currentTransactionResponse, 'answer.detailedStatus'));
|
|
|
|
switch ($reponseType) {
|
|
case ResponseType::acceptedPayment():
|
|
$this->currentTransaction->status = TransactionStatus::validated();
|
|
$this->currentTransaction->saveOrFail();
|
|
$this->currentTransaction->mutateOrderStatus();
|
|
break;
|
|
case ResponseType::expiredPayment():
|
|
case ResponseType::canceledPayment():
|
|
case ResponseType::refusedPayment():
|
|
$this->currentTransaction->status = TransactionStatus::failed();
|
|
$this->currentTransaction->saveOrFail();
|
|
$this->currentTransaction->mutateOrderStatus();
|
|
break;
|
|
// ! Ignore these explicitely.
|
|
case ResponseType::suspendedPayment():
|
|
case ResponseType::pendingPayment():
|
|
break;
|
|
|
|
case ResponseType::needsValidation():
|
|
case ResponseType::suspectedFraud():
|
|
case ResponseType::unknown():
|
|
default:
|
|
$message = __CLASS__ . " Unhandled Systempay credit reponse Type '{$reponseType}'";
|
|
\report(new \RuntimeException($message));
|
|
} //end switch
|
|
}
|
|
|
|
/**
|
|
* Fetch the appropriate reponse type
|
|
*
|
|
* @param string $transStatus
|
|
* @return \LDC\LaravelSystempay\Enums\ResponseType
|
|
*/
|
|
private function getReponseType(string $transStatus): ResponseType
|
|
{
|
|
switch (true) {
|
|
case $this->isAcceptedPayment($transStatus):
|
|
return ResponseType::acceptedPayment();
|
|
case \in_array($transStatus, ['REFUSED']):
|
|
return ResponseType::refusedPayment();
|
|
case \in_array($transStatus, ['EXPIRED']):
|
|
return ResponseType::expiredPayment();
|
|
case \in_array($transStatus, ['SUSPENDED']):
|
|
return ResponseType::suspendedPayment();
|
|
case $this->isCanceledPayment($transStatus) or
|
|
\in_array($transStatus, ['CANCELLED']):
|
|
return ResponseType::canceledPayment();
|
|
case $this->isPendingPayment($transStatus):
|
|
return ResponseType::pendingPayment();
|
|
case $this->isToValidatePayment($transStatus):
|
|
return ResponseType::needsValidation();
|
|
case $this->isSuspectedFraud($transStatus):
|
|
return ResponseType::suspectedFraud();
|
|
default:
|
|
return ResponseType::unknown();
|
|
} //end switch
|
|
}
|
|
|
|
/**
|
|
* Check if the payment was successful (waiting confirmation or captured).
|
|
*
|
|
* @param string $transStatus
|
|
* @return boolean
|
|
*/
|
|
private function isAcceptedPayment(string $transStatus): bool
|
|
{
|
|
$confirmed_statuses = [
|
|
'AUTHORISED',
|
|
'AUTHORISED_TO_VALIDATE',
|
|
'CAPTURED',
|
|
/** capture will be redone */
|
|
'CAPTURE_FAILED'
|
|
];
|
|
|
|
return in_array($transStatus, $confirmed_statuses) || $this->isPendingPayment($transStatus);
|
|
}
|
|
|
|
/**
|
|
* Check if the payment is waiting confirmation (successful but the amount has not been
|
|
* transfered and is not yet guaranteed).
|
|
*
|
|
* @param string $transStatus
|
|
* @return boolean
|
|
*/
|
|
private function isPendingPayment(string $transStatus): bool
|
|
{
|
|
$pending_statuses = [
|
|
'INITIAL',
|
|
'WAITING_AUTHORISATION',
|
|
'WAITING_AUTHORISATION_TO_VALIDATE',
|
|
'UNDER_VERIFICATION'
|
|
];
|
|
|
|
return in_array($transStatus, $pending_statuses);
|
|
}
|
|
|
|
/**
|
|
* Check if the payment process was interrupted by the client.
|
|
*
|
|
* @param string $transStatus
|
|
* @return boolean
|
|
*/
|
|
private function isCanceledPayment(string $transStatus): bool
|
|
{
|
|
$canceled_statuses = [
|
|
'NOT_CREATED',
|
|
'ABANDONED'
|
|
];
|
|
|
|
return in_array($transStatus, $canceled_statuses);
|
|
}
|
|
|
|
/**
|
|
* Check if the payment is to validate manually in the payment platform Back Office.
|
|
*
|
|
* @param string $transStatus
|
|
* @return boolean
|
|
*/
|
|
private function isToValidatePayment(string $transStatus): bool
|
|
{
|
|
$to_validate_statuses = [
|
|
'WAITING_AUTHORISATION_TO_VALIDATE',
|
|
'AUTHORISED_TO_VALIDATE'
|
|
];
|
|
|
|
return in_array($transStatus, $to_validate_statuses);
|
|
}
|
|
|
|
/**
|
|
* Check if the payment is suspected to be fraudulent.
|
|
*
|
|
* @param string $transStatus
|
|
* @return boolean
|
|
*/
|
|
private function isSuspectedFraud(string $transStatus): bool
|
|
{
|
|
// At least one control failed ...
|
|
$risk_control = $this->getRiskControl($transStatus);
|
|
if (in_array('WARNING', $risk_control) || in_array('ERROR', $risk_control)) {
|
|
return true;
|
|
}
|
|
|
|
// Or there was an alert from risk assessment module.
|
|
$risk_assessment = $this->getRiskAssessment($transStatus);
|
|
if (in_array('INFORM', $risk_assessment)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return the risk control result.
|
|
*
|
|
* @return array[string][string]
|
|
*/
|
|
public function getRiskControl()
|
|
{
|
|
return data_get(
|
|
$this->currentTransactionResponse,
|
|
'answer.transactionDetails.fraudManagement.riskControl'
|
|
) ?? [];
|
|
}
|
|
|
|
/**
|
|
* Return the risk assessment result.
|
|
*
|
|
* @return array[string]
|
|
*/
|
|
public function getRiskAssessment()
|
|
{
|
|
return data_get(
|
|
$this->currentTransactionResponse,
|
|
'answer.transactionDetails.fraudManagement.riskAnalysis'
|
|
) ?? [];
|
|
}
|
|
|
|
/**
|
|
* Get Systempay adapter
|
|
*
|
|
* @return \LDC\LaravelSystempay\LaravelSystempay
|
|
*/
|
|
private function getPayment(): LaravelSystempay
|
|
{
|
|
return app('systempay');
|
|
}
|
|
}
|