Merge branch 'master' into 800-automatically-reject-jo-if-no-riders-or-inventory
This commit is contained in:
commit
90838b004a
6 changed files with 215 additions and 32 deletions
|
|
@ -109,6 +109,12 @@ services:
|
|||
arguments:
|
||||
$callback_url: "%env(WARRANTY_SERIAL_CALLBACK_URL)%"
|
||||
|
||||
App\Command\ProcessLatePaymongoTransactionsCommand:
|
||||
arguments:
|
||||
$em: "@doctrine.orm.entity_manager"
|
||||
$paymongo: "@App\\Service\\PayMongoConnector"
|
||||
$webhook_id: "%env(PAYMONGO_WEBHOOK_ID)%"
|
||||
|
||||
# rider tracker service
|
||||
App\Service\RiderTracker:
|
||||
arguments:
|
||||
|
|
|
|||
124
src/Command/ProcessLatePaymongoTransactionsCommand.php
Normal file
124
src/Command/ProcessLatePaymongoTransactionsCommand.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Ramcar\TransactionStatus;
|
||||
use App\Entity\GatewayTransaction;
|
||||
use App\Service\PayMongoConnector;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class ProcessLatePaymongoTransactionsCommand extends Command
|
||||
{
|
||||
protected $em;
|
||||
protected $paymongo;
|
||||
|
||||
protected $webhook_id;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, PayMongoConnector $paymongo, $webhook_id)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->paymongo = $paymongo;
|
||||
$this->webhook_id = $webhook_id;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('paymongo:checkpending')
|
||||
->setDescription('Check for any late PayMongo transactions and process if needed.')
|
||||
->setHelp('Check for any late PayMongo transactions and process if needed.')
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Ignore webhook status and process anyway.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$force = $input->getOption('force');
|
||||
|
||||
// if we aren't forcing, check webhook status first
|
||||
if (!$force) {
|
||||
$output->writeln('Checking webhook status...');
|
||||
|
||||
// check if webhook is disabled
|
||||
$webhook = $this->paymongo->getWebhook($this->webhook_id);
|
||||
|
||||
if ($webhook['success'] && $webhook['response']['data']['attributes']['status'] === 'enabled') {
|
||||
$output->writeln('<info>Webhook is enabled, no need to do anything.</info>');
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
$output->writeln('<comment>Webhook is disabled! Logging event and proceeding...</comment>');
|
||||
|
||||
$this->paymongo->log('WEBHOOK', "[]", json_encode($webhook['response'], JSON_PRETTY_PRINT), 'webhook');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('Fetching all late pending transactions...');
|
||||
|
||||
// set date threshold to 24 hours ago
|
||||
$date_threshold = (new DateTime())->modify('-24 hours');
|
||||
|
||||
$transactions = $this->em->getRepository(GatewayTransaction::class)
|
||||
->createQueryBuilder('t')
|
||||
->select('t')
|
||||
->where('t.status = :status')
|
||||
->andWhere('t.date_create <= :date_threshold')
|
||||
->setParameter('status', TransactionStatus::PENDING)
|
||||
->setParameter('date_threshold', $date_threshold)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$output->writeln('Found '. count($transactions) . ' rows matching criteria.');
|
||||
|
||||
$x = 0;
|
||||
|
||||
foreach ($transactions as $trans) {
|
||||
// check paymongo status
|
||||
$checkout = $this->paymongo->getCheckout($trans->getExtTransactionId());
|
||||
|
||||
if ($checkout['success']) {
|
||||
// check if we have any payments made
|
||||
$payments = $checkout['response']['data']['attributes']['payments'] ?? [];
|
||||
|
||||
if (!empty($payments)) {
|
||||
$amount_paid = 0;
|
||||
|
||||
// for good measure, we get all successful payments and add them up
|
||||
foreach ($payments as $payment) {
|
||||
if ($payment['attributes']['status'] === TransactionStatus::PAID) {
|
||||
$amount_paid = bcadd($amount_paid, $payment['attributes']['amount']);
|
||||
}
|
||||
}
|
||||
|
||||
// this transaction is fully paid, so we mark it as paid
|
||||
if (bccomp($trans->getAmount(), $amount_paid) <= 0) {
|
||||
$trans->setStatus(TransactionStatus::PAID);
|
||||
$trans->setDatePay(new DateTime());
|
||||
$this->em->flush();
|
||||
|
||||
$output->writeln('Marked transaction '. $trans->getID() . ' as paid.');
|
||||
$x++;
|
||||
} else {
|
||||
$output->writeln('<comment>Insufficient payment amount (' . $amount_paid . '/' . $trans->getAmount() . ') for this transaction: ' . $trans->getID() . '</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<comment>No payments found for transaction: ' . $trans->getID() . '</comment>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln('<comment>Checkout not found: ' . $checkout['error']['message'] . '</comment>');
|
||||
}
|
||||
}
|
||||
|
||||
$output->writeln('<info>Done! Processed ' . $x . ' rows.</info>');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -413,7 +413,9 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// TODO: refactor this into a jo handler class, so we don't have to repeat for control center
|
||||
|
||||
|
|
@ -466,7 +468,9 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(true, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// requeue it, instead of cancelling it
|
||||
$jo->requeue();
|
||||
|
|
@ -527,7 +531,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB);
|
||||
|
|
@ -570,7 +576,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_PRE_JO);
|
||||
|
|
@ -613,7 +621,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_PRE_JO);
|
||||
|
|
@ -656,7 +666,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_START);
|
||||
|
|
@ -700,7 +712,9 @@ class RiderAppController extends ApiController
|
|||
$jo->setStatus(JOStatus::IN_PROGRESS);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE);
|
||||
|
|
@ -761,7 +775,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB);
|
||||
|
|
@ -854,7 +870,9 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// need to check if service type is battery sales
|
||||
// if so, serial is a required parameter
|
||||
|
|
@ -1002,7 +1020,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_POST_JO);
|
||||
|
|
@ -1046,7 +1066,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $rider->getCurrentJobOrder();
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// set delivery status
|
||||
$jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_POST_JO);
|
||||
|
|
@ -1265,7 +1287,9 @@ class RiderAppController extends ApiController
|
|||
$jo = $em->getRepository(JobOrder::class)->find($jo_id);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// check if we have trade in items
|
||||
$ti_items = [];
|
||||
|
|
@ -1376,7 +1400,9 @@ class RiderAppController extends ApiController
|
|||
return new APIResponse(false, $msg);
|
||||
|
||||
// check if JO can be modified first
|
||||
$this->checkJOProgressionAllowed($jo, $rider);
|
||||
if (!$this->checkJOProgressionAllowed($em, $jo, $rider)) {
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
}
|
||||
|
||||
// check service type
|
||||
$stype_id = $req->request->get('stype_id');
|
||||
|
|
@ -1740,22 +1766,40 @@ class RiderAppController extends ApiController
|
|||
return $msg;
|
||||
}
|
||||
|
||||
protected function checkJOProgressionAllowed(JobOrder $jo, $rider)
|
||||
protected function checkJOProgressionAllowed(EntityManagerInterface $em, JobOrder $jo, &$rider)
|
||||
{
|
||||
$allowed = true;
|
||||
|
||||
error_log("JO delivery status is " . $jo->getDeliveryStatus() . " (not allowed: " . DeliveryStatus::CANCELLED . ")");
|
||||
error_log("JO status is " . $jo->getStatus() . " (not allowed: " . JOStatus::CANCELLED . ")");
|
||||
|
||||
// TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working.
|
||||
// check delivery status
|
||||
switch ($jo->getDeliveryStatus())
|
||||
{
|
||||
case DeliveryStatus::CANCELLED:
|
||||
$allowed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// check JO status as well
|
||||
switch ($jo->getStatus())
|
||||
{
|
||||
case JOStatus::CANCELLED:
|
||||
// if this is the rider's current JO, set to null
|
||||
if ($rider->getCurrentJobOrder() === $jo) {
|
||||
$rider->setCurrentJobOrder();
|
||||
}
|
||||
|
||||
return new APIResponse(false, 'Job order can no longer be modified.');
|
||||
$allowed = false;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
// if this is the rider's current JO, set to null
|
||||
if (!$allowed) {
|
||||
if ($rider->getCurrentJobOrder() === $jo) {
|
||||
$rider->setCurrentJobOrder();
|
||||
$em->persist($rider);
|
||||
$em->flush();
|
||||
}
|
||||
}
|
||||
|
||||
return $allowed;
|
||||
}
|
||||
|
||||
protected function debugRequest(Request $req)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use Symfony\Component\HttpFoundation\Request;
|
|||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class PayMongoController extends Controller
|
||||
{
|
||||
protected $pm;
|
||||
|
|
@ -45,10 +47,8 @@ class PayMongoController extends Controller
|
|||
switch ($event_name) {
|
||||
case "payment.paid":
|
||||
return $this->handlePaymentPaid($event);
|
||||
break;
|
||||
case "payment.failed":
|
||||
return $this->handlePaymentPaid($event);
|
||||
break;
|
||||
return $this->handlePaymentFailed($event);
|
||||
case "payment.refunded": // TODO: handle refunds
|
||||
case "payment.refund.updated":
|
||||
case "checkout_session.payment.paid":
|
||||
|
|
@ -69,6 +69,7 @@ class PayMongoController extends Controller
|
|||
if (!empty($obj)) {
|
||||
// mark as paid
|
||||
$obj->setStatus(TransactionStatus::PAID);
|
||||
$obj->setDatePay(new DateTime());
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +78,7 @@ class PayMongoController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
protected function handlePaymentFailed(Request $req)
|
||||
protected function handlePaymentFailed($event)
|
||||
{
|
||||
// TODO: do something about failed payments?
|
||||
return $this->json([
|
||||
|
|
|
|||
|
|
@ -58,17 +58,20 @@ class GatewayTransactionListener
|
|||
'gateway_transaction' => $gt_obj,
|
||||
]);
|
||||
|
||||
if (!empty($obj)) {
|
||||
// make sure the object exists and has not been processed yet
|
||||
if (!empty($obj) && $obj->getStatus() === InsuranceApplicationStatus::CREATED) {
|
||||
// mark as paid
|
||||
$obj->setDatePay(new DateTime());
|
||||
$obj->setStatus(InsuranceApplicationStatus::PAID);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
// flag on api as paid
|
||||
$result = $this->ic->tagApplicationPaid($obj->getExtTransactionId());
|
||||
if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') {
|
||||
error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
|
||||
// flag on api as paid
|
||||
$result = $this->ic->tagApplicationPaid($obj->getExtTransactionId());
|
||||
|
||||
// something went wrong with insurance api
|
||||
if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') {
|
||||
error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ class PayMongoConnector
|
|||
return $this->doRequest('/v1/checkout_sessions/' . $checkout_id, 'GET');
|
||||
}
|
||||
|
||||
public function getWebhook($id)
|
||||
{
|
||||
return $this->doRequest('/v1/webhooks/'. $id, 'GET');
|
||||
}
|
||||
|
||||
protected function generateHash()
|
||||
{
|
||||
return base64_encode($this->secret_key);
|
||||
|
|
|
|||
Loading…
Reference in a new issue