Handle paymongo webhooks #761
This commit is contained in:
parent
c5a8bda95a
commit
ee021da453
14 changed files with 515 additions and 112 deletions
|
|
@ -53,6 +53,10 @@ security:
|
||||||
pattern: ^\/test_capi\/
|
pattern: ^\/test_capi\/
|
||||||
security: false
|
security: false
|
||||||
|
|
||||||
|
paymongo:
|
||||||
|
pattern: ^\/paymongo\/
|
||||||
|
security: false
|
||||||
|
|
||||||
cust_api_v2:
|
cust_api_v2:
|
||||||
pattern: ^\/apiv2\/(?!register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/|account|account\/|account_code_validate|account_code_validate\/|account_resend_code|account_resend_code\/)
|
pattern: ^\/apiv2\/(?!register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/|account|account\/|account_code_validate|account_code_validate\/|account_resend_code|account_resend_code\/)
|
||||||
provider: api_v2_provider
|
provider: api_v2_provider
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,3 @@ insurance_listener:
|
||||||
path: /insurance/listen
|
path: /insurance/listen
|
||||||
controller: App\Controller\InsuranceController::listen
|
controller: App\Controller\InsuranceController::listen
|
||||||
methods: [POST]
|
methods: [POST]
|
||||||
|
|
||||||
insurance_payment_success:
|
|
||||||
path: /insurance/payment/success
|
|
||||||
controller: App\Controller\InsuranceController::paymentSuccess
|
|
||||||
methods: [GET]
|
|
||||||
|
|
||||||
insurance_payment_cancel:
|
|
||||||
path: /insurance/payment/cancel
|
|
||||||
controller: App\Controller\InsuranceController::paymentCancel
|
|
||||||
methods: [GET]
|
|
||||||
|
|
@ -4,3 +4,13 @@ paymongo_listener:
|
||||||
path: /paymongo/listen
|
path: /paymongo/listen
|
||||||
controller: App\Controller\PayMongoController::listen
|
controller: App\Controller\PayMongoController::listen
|
||||||
methods: [POST]
|
methods: [POST]
|
||||||
|
|
||||||
|
paymongo_payment_success:
|
||||||
|
path: /paymongo/success
|
||||||
|
controller: App\Controller\PayMongoController::paymentSuccess
|
||||||
|
methods: [GET]
|
||||||
|
|
||||||
|
paymongo_payment_cancelled:
|
||||||
|
path: /paymongo/cancelled
|
||||||
|
controller: App\Controller\PayMongoController::paymentCancelled
|
||||||
|
methods: [GET]
|
||||||
|
|
@ -216,6 +216,16 @@ services:
|
||||||
$username: "%env(INSURANCE_USERNAME)%"
|
$username: "%env(INSURANCE_USERNAME)%"
|
||||||
$password: "%env(INSURANCE_PASSWORD)%"
|
$password: "%env(INSURANCE_PASSWORD)%"
|
||||||
|
|
||||||
|
# entity listener for gateway transactions
|
||||||
|
App\EntityListener\GatewayTransactionListener:
|
||||||
|
arguments:
|
||||||
|
$em: "@doctrine.orm.entity_manager"
|
||||||
|
$ic: "@App\\Service\\InsuranceConnector"
|
||||||
|
tags:
|
||||||
|
- name: doctrine.orm.entity_listener
|
||||||
|
event: 'postUpdate'
|
||||||
|
entity: 'App\Entity\GatewayTransaction'
|
||||||
|
|
||||||
# paymongo connector
|
# paymongo connector
|
||||||
App\Service\PayMongoConnector:
|
App\Service\PayMongoConnector:
|
||||||
arguments:
|
arguments:
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,13 @@ use App\Service\InsuranceConnector;
|
||||||
use App\Service\PayMongoConnector;
|
use App\Service\PayMongoConnector;
|
||||||
|
|
||||||
use App\Entity\InsuranceApplication;
|
use App\Entity\InsuranceApplication;
|
||||||
|
use App\Entity\GatewayTransaction;
|
||||||
use App\Entity\CustomerVehicle;
|
use App\Entity\CustomerVehicle;
|
||||||
|
|
||||||
use App\Ramcar\InsuranceApplicationStatus;
|
use App\Ramcar\InsuranceApplicationStatus;
|
||||||
use App\Ramcar\InsuranceMVType;
|
use App\Ramcar\InsuranceMVType;
|
||||||
use App\Ramcar\InsuranceClientType;
|
use App\Ramcar\InsuranceClientType;
|
||||||
|
use App\Ramcar\TransactionStatus;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
|
@ -131,51 +132,65 @@ class InsuranceController extends ApiController
|
||||||
$req->files->get('orcr_file')
|
$req->files->get('orcr_file')
|
||||||
);
|
);
|
||||||
if (!$result['success']) {
|
if (!$result['success']) {
|
||||||
return new APIResponse(false, $result['error']['message']);
|
return new ApiResponse(false, $result['error']['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$premium_amount_int = (int)bcmul($result['response']['premium'], 100);
|
||||||
|
|
||||||
// build checkout item and metadata
|
// build checkout item and metadata
|
||||||
$items = [
|
$items = [
|
||||||
[
|
[
|
||||||
'name' => "Insurance Premium",
|
'name' => "Insurance Premium",
|
||||||
'description' => "Premium fee for vehicle insurance",
|
'description' => "Premium fee for vehicle insurance",
|
||||||
'quantity' => 1,
|
'quantity' => 1,
|
||||||
'amount' => (int)bcmul($result['response']['premium'], 100),
|
'amount' => $premium_amount_int,
|
||||||
'currency' => 'PHP',
|
'currency' => 'PHP',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$metadata = [
|
$now = new DateTime();
|
||||||
'customer_id' => $cust->getID(),
|
|
||||||
'customer_vehicle_id' => $cv->getID(),
|
// create gateway transaction
|
||||||
];
|
$gt = new GatewayTransaction();
|
||||||
|
$gt->setCustomer($cust);
|
||||||
|
$gt->setDateCreate($now);
|
||||||
|
$gt->setAmount($premium_amount_int);
|
||||||
|
$gt->setStatus(TransactionStatus::PENDING);
|
||||||
|
$gt->setGateway('paymongo'); // TODO: define values elsewhere
|
||||||
|
$gt->setType('insurance_premium'); // TODO: define values elsewhere
|
||||||
|
$gt->setExtTransactionId($result['response']['id']);
|
||||||
|
$this->em->persist($gt);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
// create paymongo checkout resource
|
// create paymongo checkout resource
|
||||||
$checkout = $paymongo->createCheckout(
|
$checkout = $paymongo->createCheckout(
|
||||||
$cust,
|
$cust,
|
||||||
$items,
|
$items,
|
||||||
implode("-", [$cust->getID(), $result['response']['id']]),
|
$gt->getID(),
|
||||||
"Motolite RES-Q Vehicle Insurance",
|
"Motolite RES-Q Vehicle Insurance",
|
||||||
$router->generate('insurance_payment_success', [], UrlGeneratorInterface::ABSOLUTE_URL),
|
$router->generate('paymongo_payment_success', [], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
$router->generate('insurance_payment_cancel', [], UrlGeneratorInterface::ABSOLUTE_URL),
|
$router->generate('paymongo_payment_cancelled', [], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||||
$metadata,
|
['transaction_id' => $gt->getID()], // NOTE: passing this here too for payment resource metadata
|
||||||
);
|
);
|
||||||
if (!$checkout['success']) {
|
if (!$checkout['success']) {
|
||||||
return new APIResponse(false, $checkout['error']['message']);
|
return new ApiResponse(false, $checkout['error']['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$checkout_url = $checkout['response']['data']['attributes']['checkout_url'];
|
$checkout_url = $checkout['response']['data']['attributes']['checkout_url'];
|
||||||
|
|
||||||
|
// add checkout url and id to transaction metadata
|
||||||
|
$gt->setMetadata([
|
||||||
|
'checkout_url' => $checkout_url,
|
||||||
|
'checkout_id' => $checkout['response']['data']['id'],
|
||||||
|
]);
|
||||||
|
|
||||||
// store application in db
|
// store application in db
|
||||||
$app = new InsuranceApplication();
|
$app = new InsuranceApplication();
|
||||||
$app->setDateSubmitted(new DateTime());
|
$app->setDateSubmit($now);
|
||||||
$app->setCustomer($cust);
|
$app->setCustomer($cust);
|
||||||
$app->setCustomerVehicle($cv);
|
$app->setCustomerVehicle($cv);
|
||||||
$app->setTransactionID($result['response']['id']);
|
$app->setGatewayTransaction($gt);
|
||||||
$app->setPremiumAmount($result['response']['premium']);
|
|
||||||
$app->setStatus(InsuranceApplicationStatus::CREATED);
|
$app->setStatus(InsuranceApplicationStatus::CREATED);
|
||||||
$app->setCheckoutURL($checkout_url);
|
|
||||||
$app->setCheckoutID($checkout['response']['data']['id']);
|
|
||||||
$app->setMetadata($input);
|
$app->setMetadata($input);
|
||||||
$this->em->persist($app);
|
$this->em->persist($app);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
@ -200,7 +215,7 @@ class InsuranceController extends ApiController
|
||||||
// get maker list
|
// get maker list
|
||||||
$result = $this->client->getVehicleMakers();
|
$result = $this->client->getVehicleMakers();
|
||||||
if (!$result['success']) {
|
if (!$result['success']) {
|
||||||
return new APIResponse(false, $result['error']['message']);
|
return new ApiResponse(false, $result['error']['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ApiResponse(true, '', [
|
return new ApiResponse(true, '', [
|
||||||
|
|
@ -220,7 +235,7 @@ class InsuranceController extends ApiController
|
||||||
// get maker list
|
// get maker list
|
||||||
$result = $this->client->getVehicleModels($maker_id);
|
$result = $this->client->getVehicleModels($maker_id);
|
||||||
if (!$result['success']) {
|
if (!$result['success']) {
|
||||||
return new APIResponse(false, $result['error']['message']);
|
return new ApiResponse(false, $result['error']['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ApiResponse(true, '', [
|
return new ApiResponse(true, '', [
|
||||||
|
|
@ -240,7 +255,7 @@ class InsuranceController extends ApiController
|
||||||
// get maker list
|
// get maker list
|
||||||
$result = $this->client->getVehicleTrims($model_id);
|
$result = $this->client->getVehicleTrims($model_id);
|
||||||
if (!$result['success']) {
|
if (!$result['success']) {
|
||||||
return new APIResponse(false, $result['error']['message']);
|
return new ApiResponse(false, $result['error']['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ApiResponse(true, '', [
|
return new ApiResponse(true, '', [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace App\Controller;
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\GatewayTransaction;
|
||||||
|
use App\Ramcar\TransactionStatus;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
@ -10,14 +12,89 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
|
|
||||||
class PayMongoController extends Controller
|
class PayMongoController extends Controller
|
||||||
{
|
{
|
||||||
public function listen(Request $req, EntityManagerInterface $em)
|
protected $em;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em)
|
||||||
{
|
{
|
||||||
$payload = $req->request->all();
|
$this->em = $em;
|
||||||
error_log(print_r($payload, true));
|
}
|
||||||
|
|
||||||
|
public function listen(Request $req)
|
||||||
|
{
|
||||||
|
$payload = json_decode($req->getContent(), true);
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
@file_put_contents(__DIR__ . '/../../var/log/paymongo.log', print_r($payload, true) . "\r\n----------------------------------------\r\n\r\n", FILE_APPEND);
|
||||||
|
|
||||||
|
/*
|
||||||
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// END DEBUG
|
||||||
|
|
||||||
|
// get event type and process accordingly
|
||||||
|
$attr = $payload['data']['attributes'];
|
||||||
|
$event = $attr['data'];
|
||||||
|
$event_name = $attr['type'];
|
||||||
|
|
||||||
|
switch ($event_name) {
|
||||||
|
case "payment.paid":
|
||||||
|
return $this->handlePaymentPaid($event);
|
||||||
|
break;
|
||||||
|
case "payment.failed":
|
||||||
|
return $this->handlePaymentPaid($event);
|
||||||
|
break;
|
||||||
|
case "payment.refunded": // TODO: handle refunds
|
||||||
|
case "payment.refund.updated":
|
||||||
|
case "checkout_session.payment.paid":
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->json([
|
return $this->json([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'payload' => $payload,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handlePaymentPaid($event)
|
||||||
|
{
|
||||||
|
$metadata = $event['attributes']['metadata'];
|
||||||
|
$obj = $this->getTransaction($metadata['transaction_id']);
|
||||||
|
|
||||||
|
// mark as paid
|
||||||
|
$obj->setStatus(TransactionStatus::PAID);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handlePaymentFailed(Request $req)
|
||||||
|
{
|
||||||
|
// TODO: do something about failed payments?
|
||||||
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getTransaction($id)
|
||||||
|
{
|
||||||
|
//$class_name = 'App\\Entity\\' . $type;
|
||||||
|
//$instance = new $class_name;
|
||||||
|
|
||||||
|
return $this->em->getRepository(GatewayTransaction::class)->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentSuccess(Request $req)
|
||||||
|
{
|
||||||
|
return $this->render('paymongo/success.html.twig');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentCancelled(Request $req)
|
||||||
|
{
|
||||||
|
return $this->render('paymongo/cancelled.html.twig');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
204
src/Entity/GatewayTransaction.php
Normal file
204
src/Entity/GatewayTransaction.php
Normal file
|
|
@ -0,0 +1,204 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use App\Ramcar\TransactionStatus;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity
|
||||||
|
* @ORM\Table(name="gateway_transaction")
|
||||||
|
*/
|
||||||
|
class GatewayTransaction
|
||||||
|
{
|
||||||
|
// unique id
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*/
|
||||||
|
protected $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity="Customer", inversedBy="transactions")
|
||||||
|
* @ORM\JoinColumn(name="customer_id", referencedColumnName="id")
|
||||||
|
*/
|
||||||
|
protected $customer;
|
||||||
|
|
||||||
|
// date ticket was created
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime")
|
||||||
|
*/
|
||||||
|
protected $date_create;
|
||||||
|
|
||||||
|
// date ticket was paid
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
|
*/
|
||||||
|
protected $date_pay;
|
||||||
|
|
||||||
|
// amount
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="bigint")
|
||||||
|
* @Assert\NotBlank()
|
||||||
|
*/
|
||||||
|
protected $amount;
|
||||||
|
|
||||||
|
// status of the transaction
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=50)
|
||||||
|
* @Assert\NotBlank()
|
||||||
|
*/
|
||||||
|
protected $status;
|
||||||
|
|
||||||
|
// type of transaction
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=50)
|
||||||
|
* @Assert\NotBlank()
|
||||||
|
*/
|
||||||
|
protected $type;
|
||||||
|
|
||||||
|
// gateway used for transaction
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=50)
|
||||||
|
* @Assert\NotBlank()
|
||||||
|
*/
|
||||||
|
protected $gateway;
|
||||||
|
|
||||||
|
// external transaction id
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", length=255, nullable=true)
|
||||||
|
*/
|
||||||
|
protected $ext_transaction_id;
|
||||||
|
|
||||||
|
// other data related to the transaction
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json")
|
||||||
|
*/
|
||||||
|
protected $metadata;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->date_create = new DateTime();
|
||||||
|
$this->status = TransactionStatus::PENDING;
|
||||||
|
$this->metadata = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getID()
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCustomer(Customer $customer)
|
||||||
|
{
|
||||||
|
$this->customer = $customer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCustomer()
|
||||||
|
{
|
||||||
|
return $this->customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateCreate(DateTime $date)
|
||||||
|
{
|
||||||
|
$this->date_create = $date;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDateCreate()
|
||||||
|
{
|
||||||
|
return $this->date_create;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDatePay(DateTime $date)
|
||||||
|
{
|
||||||
|
$this->date_pay = $date;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatePay()
|
||||||
|
{
|
||||||
|
return $this->date_pay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setAmount($amount)
|
||||||
|
{
|
||||||
|
$this->amount = $amount;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAmount()
|
||||||
|
{
|
||||||
|
return $this->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStatus($status)
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setGateway($gateway)
|
||||||
|
{
|
||||||
|
$this->gateway = $gateway;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getGateway()
|
||||||
|
{
|
||||||
|
return $this->gateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExtTransactionId($transaction_id)
|
||||||
|
{
|
||||||
|
$this->ext_transaction_id = $transaction_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtTransactionId()
|
||||||
|
{
|
||||||
|
return $this->ext_transaction_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCallbackClass($callback_class)
|
||||||
|
{
|
||||||
|
$this->callback_class = $callback_class;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCallbackClass()
|
||||||
|
{
|
||||||
|
return $this->callback_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setMetadata($metadata)
|
||||||
|
{
|
||||||
|
$this->metadata = $metadata;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMetadata()
|
||||||
|
{
|
||||||
|
return $this->metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -36,19 +36,12 @@ class InsuranceApplication
|
||||||
*/
|
*/
|
||||||
protected $customer_vehicle;
|
protected $customer_vehicle;
|
||||||
|
|
||||||
// paramount transaction id
|
// gateway transaction
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=32)
|
* @ORM\OneToOne(targetEntity="GatewayTransaction")
|
||||||
* @Assert\NotBlank()
|
* @ORM\JoinColumn(name="gateway_transaction_id", referencedColumnName="id")
|
||||||
*/
|
*/
|
||||||
protected $transaction_id;
|
protected $gateway_transaction;
|
||||||
|
|
||||||
// premium amount
|
|
||||||
/**
|
|
||||||
* @ORM\Column(type="decimal", precision=7, scale=2)
|
|
||||||
* @Assert\NotBlank()
|
|
||||||
*/
|
|
||||||
protected $premium_amount;
|
|
||||||
|
|
||||||
// status
|
// status
|
||||||
/**
|
/**
|
||||||
|
|
@ -66,19 +59,19 @@ class InsuranceApplication
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime")
|
* @ORM\Column(type="datetime")
|
||||||
*/
|
*/
|
||||||
protected $date_submitted;
|
protected $date_submit;
|
||||||
|
|
||||||
// date the application was paid
|
// date the application was paid
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime", nullable=true)
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $date_paid;
|
protected $date_pay;
|
||||||
|
|
||||||
// date the application was marked as completed by the insurance api
|
// date the application was marked as completed by the insurance api
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime", nullable=true)
|
* @ORM\Column(type="datetime", nullable=true)
|
||||||
*/
|
*/
|
||||||
protected $date_completed;
|
protected $date_complete;
|
||||||
|
|
||||||
// form data when submitting the application
|
// form data when submitting the application
|
||||||
/**
|
/**
|
||||||
|
|
@ -86,23 +79,11 @@ class InsuranceApplication
|
||||||
*/
|
*/
|
||||||
protected $metadata;
|
protected $metadata;
|
||||||
|
|
||||||
// paymongo checkout url
|
|
||||||
/**
|
|
||||||
* @ORM\Column(type="string", length=255, nullable=true)
|
|
||||||
*/
|
|
||||||
protected $checkout_url;
|
|
||||||
|
|
||||||
// paymongo checkout id
|
|
||||||
/**
|
|
||||||
* @ORM\Column(type="string", length=32, nullable=true)
|
|
||||||
*/
|
|
||||||
protected $checkout_id;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->date_submitted = new DateTime();
|
$this->date_submit = new DateTime();
|
||||||
$this->date_paid = null;
|
$this->date_pay = null;
|
||||||
$this->date_completed = null;
|
$this->date_complete = null;
|
||||||
$this->metadata = [];
|
$this->metadata = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,35 +114,26 @@ class InsuranceApplication
|
||||||
return $this->customer_vehicle;
|
return $this->customer_vehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDateSubmitted(DateTime $date)
|
public function setDateSubmit(DateTime $date)
|
||||||
{
|
{
|
||||||
$this->date_submitted = $date;
|
$this->date_submit = $date;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDateSubmitted()
|
public function getDateSubmit()
|
||||||
{
|
{
|
||||||
return $this->date_submitted;
|
return $this->date_submit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTransactionID($id)
|
public function setGatewayTransaction(GatewayTransaction $transaction)
|
||||||
{
|
{
|
||||||
return $this->transaction_id = $id;
|
$this->gateway_transaction = $transaction;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTransactionID()
|
public function getGatewayTransaction()
|
||||||
{
|
{
|
||||||
return $this->transaction_id;
|
return $this->gateway_transaction;
|
||||||
}
|
|
||||||
|
|
||||||
public function setPremiumAmount($amount)
|
|
||||||
{
|
|
||||||
return $this->premium_amount = $amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPremiumAmount()
|
|
||||||
{
|
|
||||||
return $this->premium_amount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStatus($status)
|
public function setStatus($status)
|
||||||
|
|
@ -184,26 +156,26 @@ class InsuranceApplication
|
||||||
return $this->coc_url;
|
return $this->coc_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDatePaid(DateTime $date)
|
public function setDatePay(DateTime $date)
|
||||||
{
|
{
|
||||||
$this->date_paid = $date;
|
$this->date_pay = $date;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDatePaid()
|
public function getDatePay()
|
||||||
{
|
{
|
||||||
return $this->date_paid;
|
return $this->date_pay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDateCompleted(DateTime $date)
|
public function setDateComplete(DateTime $date)
|
||||||
{
|
{
|
||||||
$this->date_completed = $date;
|
$this->date_complete = $date;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDateCompleted()
|
public function getDateComplete()
|
||||||
{
|
{
|
||||||
return $this->date_completed;
|
return $this->date_complete;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMetadata($metadata)
|
public function setMetadata($metadata)
|
||||||
|
|
@ -215,24 +187,4 @@ class InsuranceApplication
|
||||||
{
|
{
|
||||||
return $this->metadata;
|
return $this->metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCheckoutURL($url)
|
|
||||||
{
|
|
||||||
return $this->checkout_url = $url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCheckoutURL()
|
|
||||||
{
|
|
||||||
return $this->checkout_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCheckoutID($id)
|
|
||||||
{
|
|
||||||
return $this->checkout_id = $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCheckoutID()
|
|
||||||
{
|
|
||||||
return $this->checkout_id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/EntityListener/GatewayTransactionListener.php
Normal file
75
src/EntityListener/GatewayTransactionListener.php
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\EntityListener;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use App\Entity\GatewayTransaction;
|
||||||
|
use App\Entity\InsuranceApplication;
|
||||||
|
use App\Service\InsuranceConnector;
|
||||||
|
use App\Ramcar\InsuranceApplicationStatus;
|
||||||
|
use App\Ramcar\TransactionStatus;
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
class GatewayTransactionListener
|
||||||
|
{
|
||||||
|
protected $ic;
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, InsuranceConnector $ic)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->ic = $ic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postUpdate(GatewayTransaction $gt_obj, LifecycleEventArgs $args)
|
||||||
|
{
|
||||||
|
// get transaction changes
|
||||||
|
$em = $args->getEntityManager();
|
||||||
|
$uow = $em->getUnitOfWork();
|
||||||
|
$changeset = $uow->getEntityChangeSet($gt_obj);
|
||||||
|
|
||||||
|
if (array_key_exists('status', $changeset)) {
|
||||||
|
$field_changes = $changeset['status'];
|
||||||
|
|
||||||
|
$prev_value = $field_changes[0] ?? null;
|
||||||
|
$new_value = $field_changes[1] ?? null;
|
||||||
|
|
||||||
|
// only do something if the status has changed to paid
|
||||||
|
if ($prev_value !== $new_value && $new_value === TransactionStatus::PAID) {
|
||||||
|
// handle based on type
|
||||||
|
// TODO: add types here as we go. there's probably a better way to do this.
|
||||||
|
switch ($gt_obj->getType()) {
|
||||||
|
case 'insurance_premium':
|
||||||
|
return $this->handleInsurancePremium($gt_obj);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleInsurancePremium($gt_obj)
|
||||||
|
{
|
||||||
|
// get insurance application object
|
||||||
|
$obj = $this->em->getRepository(InsuranceApplication::class)->findOneBy([
|
||||||
|
'gateway_transaction' => $gt_obj,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($obj) {
|
||||||
|
// mark as paid
|
||||||
|
$obj->setDatePay(new DateTime());
|
||||||
|
$obj->setStatus(InsuranceApplicationStatus::PAID);
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// flag on api as paid
|
||||||
|
$result = $this->ic->tagApplicationPaid($obj->getID());
|
||||||
|
if (!$result['success']) {
|
||||||
|
error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
18
src/Ramcar/TransactionStatus.php
Normal file
18
src/Ramcar/TransactionStatus.php
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Ramcar;
|
||||||
|
|
||||||
|
class TransactionStatus extends NameValue
|
||||||
|
{
|
||||||
|
const PENDING = 'pending';
|
||||||
|
const PAID = 'paid';
|
||||||
|
const CANCELLED = 'cancelled';
|
||||||
|
const REFUNDED = 'refunded';
|
||||||
|
|
||||||
|
const COLLECTION = [
|
||||||
|
'pending' => 'Pending',
|
||||||
|
'paid' => 'Paid',
|
||||||
|
'cancelled' => 'Cancelled',
|
||||||
|
'refunded' => 'Refunded',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -110,6 +110,7 @@ class InsuranceConnector
|
||||||
|
|
||||||
error_log("Insurance API Error: " . $error['message']);
|
error_log("Insurance API Error: " . $error['message']);
|
||||||
error_log(Psr7\Message::toString($e->getRequest()));
|
error_log(Psr7\Message::toString($e->getRequest()));
|
||||||
|
error_log($e->getResponse()->getBody()->getContents());
|
||||||
|
|
||||||
if ($e->hasResponse()) {
|
if ($e->hasResponse()) {
|
||||||
$error['response'] = Psr7\Message::toString($e->getResponse());
|
$error['response'] = Psr7\Message::toString($e->getResponse());
|
||||||
|
|
@ -121,7 +122,7 @@ class InsuranceConnector
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//error_log(print_r(json_decode($response->getBody(), true), true));
|
error_log(print_r(json_decode($response->getBody(), true), true));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'success' => true,
|
'success' => true,
|
||||||
|
|
|
||||||
|
|
@ -51,18 +51,21 @@ class PayMongoConnector
|
||||||
* ['name', 'description', 'quantity', 'amount', 'currency']
|
* ['name', 'description', 'quantity', 'amount', 'currency']
|
||||||
*/
|
*/
|
||||||
'line_items' => $items,
|
'line_items' => $items,
|
||||||
'reference_number' => $ref_no,
|
'reference_number' => (string)$ref_no,
|
||||||
'cancel_url' => $cancel_url,
|
'cancel_url' => $cancel_url,
|
||||||
'success_url' => $success_url,
|
'success_url' => $success_url,
|
||||||
'statement_descriptor' => $description,
|
'statement_descriptor' => $description,
|
||||||
'send_email_receipt' => true,
|
'send_email_receipt' => true,
|
||||||
'show_description' => true,
|
'show_description' => true,
|
||||||
'show_line_items' => false,
|
'show_line_items' => false,
|
||||||
'metadata' => $metadata,
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!empty($metadata)) {
|
||||||
|
$body['data']['attributes']['metadata'] = $metadata;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->doRequest('/v1/checkout_sessions', 'POST', $body);
|
return $this->doRequest('/v1/checkout_sessions', 'POST', $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
22
templates/paymongo/cancelled.html.twig
Normal file
22
templates/paymongo/cancelled.html.twig
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Payment Cancelled</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', (e) => {
|
||||||
|
if (typeof toApp !== 'undefined') {
|
||||||
|
toApp.postMessage("paymentCancelled");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
22
templates/paymongo/success.html.twig
Normal file
22
templates/paymongo/success.html.twig
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Payment Successful</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.addEventListener('load', (e) => {
|
||||||
|
if (typeof toApp !== 'undefined') {
|
||||||
|
toApp.postMessage("paymentSuccess");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in a new issue