Merge branch 'master' of gitlab.com:jankstudio/resq into 194-catalyst-api-bundle-acl
This commit is contained in:
commit
29f574e25c
35 changed files with 1104 additions and 136 deletions
|
|
@ -28,3 +28,10 @@ RT_SHORTCODE=1234
|
||||||
MQTT_IP_ADDRESS=localhost
|
MQTT_IP_ADDRESS=localhost
|
||||||
MQTT_PORT=8883
|
MQTT_PORT=8883
|
||||||
MQTT_CERT=/location/of/cert/file.crt
|
MQTT_CERT=/location/of/cert/file.crt
|
||||||
|
|
||||||
|
# redis client
|
||||||
|
REDIS_CLIENT_SCHEME=tcp
|
||||||
|
REDIS_CLIENT_HOST=127.0.0.1
|
||||||
|
REDIS_CLIENT_PORT=6379
|
||||||
|
REDIS_CLIENT_PASSWORD=foobared
|
||||||
|
#
|
||||||
|
|
|
||||||
|
|
@ -72,14 +72,19 @@ services:
|
||||||
|
|
||||||
App\Service\MQTTClient:
|
App\Service\MQTTClient:
|
||||||
arguments:
|
arguments:
|
||||||
$ip_address: "%env(MQTT_IP_ADDRESS)%"
|
$redis_client: "@App\\Service\\RedisClientProvider"
|
||||||
$port: "%env(MQTT_PORT)%"
|
|
||||||
$cert: "%env(MQTT_CERT)%"
|
|
||||||
|
|
||||||
App\Service\APNSClient:
|
App\Service\APNSClient:
|
||||||
arguments:
|
arguments:
|
||||||
$ip_address: "%env(APNS_REDIS_IP_ADDRESS)%"
|
$redis_client: "@App\\Service\\RedisClientProvider"
|
||||||
$port: "%env(APNS_REDIS_PORT)%"
|
|
||||||
|
App\Service\RedisClientProvider:
|
||||||
|
arguments:
|
||||||
|
$scheme: "%env(REDIS_CLIENT_SCHEME)%"
|
||||||
|
$host: "%env(REDIS_CLIENT_HOST)%"
|
||||||
|
$port: "%env(REDIS_CLIENT_PORT)%"
|
||||||
|
$password: "%env(REDIS_CLIENT_PASSWORD)%"
|
||||||
|
$env_flag: "dev"
|
||||||
|
|
||||||
Catalyst\APIBundle\Security\APIKeyUserProvider:
|
Catalyst\APIBundle\Security\APIKeyUserProvider:
|
||||||
arguments:
|
arguments:
|
||||||
|
|
|
||||||
104
src/Command/GenerateBatteryCompatibilityCommand.php
Normal file
104
src/Command/GenerateBatteryCompatibilityCommand.php
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\VehicleManufacturer;
|
||||||
|
use App\Entity\Vehicle;
|
||||||
|
use App\Entity\Battery;
|
||||||
|
use App\Entity\BatteryManufacturer;
|
||||||
|
use App\Entity\BatteryModel;
|
||||||
|
use App\Entity\BatterySize;
|
||||||
|
|
||||||
|
class GenerateBatteryCompatibilityCommand extends Command
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
protected $vmfg_index;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function populateVehicleManufacturerIndex()
|
||||||
|
{
|
||||||
|
$vms = $this->em->getRepository(VehicleManufacturer::class)->findAll();
|
||||||
|
|
||||||
|
$this->vmfg_index = [];
|
||||||
|
foreach ($vms as $vm)
|
||||||
|
{
|
||||||
|
$mfg_name = $vm->getName();
|
||||||
|
// $this->vmfg_index[$mfg_name] = [];
|
||||||
|
|
||||||
|
// get vehicles from manufacturer
|
||||||
|
$make_array = [];
|
||||||
|
$vehicles = $vm->getVehicles();
|
||||||
|
foreach ($vehicles as $vehicle)
|
||||||
|
{
|
||||||
|
$batteries = $vehicle->getBatteries();
|
||||||
|
$comp_batt = [];
|
||||||
|
foreach ($batteries as $battery)
|
||||||
|
{
|
||||||
|
// set to the first compatible battery found until a more expensive one is found
|
||||||
|
$comp_batt['id'] = $battery->getID();
|
||||||
|
$comp_batt['name'] = $battery->getModel()->getName() . ' ' .
|
||||||
|
$battery->getSize()->getName();
|
||||||
|
$comp_batt['image_url'] = '/assets/img/products/' . strtolower($battery->getModel()->getName()) . '.png';
|
||||||
|
$comp_batt['description'] = '';
|
||||||
|
//$comp_batt['description'] = $battery->getDescription();
|
||||||
|
|
||||||
|
// store the selling price for comparison
|
||||||
|
$batt_price = $battery->getSellingPrice();
|
||||||
|
|
||||||
|
// find the most expensive compatible battery
|
||||||
|
if ($battery->getSellingPrice() > $batt_price)
|
||||||
|
{
|
||||||
|
$comp_batt['id'] = $battery->getID();
|
||||||
|
$comp_batt['name'] = $battery->getModel()->getName() . ' ' .
|
||||||
|
$battery->getSize()->getName();
|
||||||
|
$comp_batt['image_url'] = $battery->getImageFile();
|
||||||
|
//$comp_batt['description'] = $battery->getDescription();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if no compatible batteries
|
||||||
|
if (!empty($comp_batt))
|
||||||
|
$make_array[$vehicle->getMake()][$vehicle->getModelYearFormatted()] = $comp_batt;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if empty
|
||||||
|
if (!empty($make_array))
|
||||||
|
$this->vmfg_index[$mfg_name] = $make_array;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('battery:generate_compatibility_json')
|
||||||
|
->setDescription('Generate a json file containing the vehicles and their compatible batteries')
|
||||||
|
->setHelp('Generate a json file containing the vehicles and their compatible batteries')
|
||||||
|
->addArgument('file', InputArgument::REQUIRED, 'Path and name for JSON file.');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$filename = $input->getArgument('file');
|
||||||
|
$this->populateVehicleManufacturerIndex();
|
||||||
|
|
||||||
|
$json_file = fopen($filename, 'w');
|
||||||
|
fwrite($json_file, json_encode($this->vmfg_index, JSON_PRETTY_PRINT));
|
||||||
|
fclose($json_file);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/Command/GenerateWarrantyFromJobOrderCommand.php
Normal file
215
src/Command/GenerateWarrantyFromJobOrderCommand.php
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
use App\Entity\Warranty;
|
||||||
|
use App\Entity\SAPBattery;
|
||||||
|
|
||||||
|
use App\Ramcar\ServiceType;
|
||||||
|
use App\Ramcar\WarrantyStatus;
|
||||||
|
|
||||||
|
class GenerateWarrantyFromJobOrderCommand extends Command
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
protected $sapbatt_hash;
|
||||||
|
protected $warranties_hash;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $em)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
|
||||||
|
$this->loadSAPBatteries();
|
||||||
|
$this->loadWarranties();
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('warranty:generate')
|
||||||
|
->setDescription('Generates warranty from job order and inserts into database')
|
||||||
|
->setHelp('Generate warranty from job order');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function computeDateExpire($date_create, $warranty_period)
|
||||||
|
{
|
||||||
|
$expire_date = clone $date_create;
|
||||||
|
$expire_date->add(new DateInterval('P'.$warranty_period.'M'));
|
||||||
|
return $expire_date;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadSAPBatteries()
|
||||||
|
{
|
||||||
|
$this->sapbatt_hash = [];
|
||||||
|
|
||||||
|
$sap_batteries = $this->em->getRepository(SAPBattery::class)->findAll();
|
||||||
|
foreach($sap_batteries as $sap_batt)
|
||||||
|
{
|
||||||
|
$id = $sap_batt->getID();
|
||||||
|
$brand_size = $sap_batt->getBrand()->getID() . " " . $sap_batt->getSize()->getID();
|
||||||
|
$this->sapbatt_hash[$id] = $brand_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadWarranties()
|
||||||
|
{
|
||||||
|
$this->warranties_hash = [];
|
||||||
|
|
||||||
|
/*
|
||||||
|
$warranties = $this->em->getRepository(Warranty::class)->findAll();
|
||||||
|
foreach($warranties as $warranty)
|
||||||
|
{
|
||||||
|
$plate_number = $warranty->getPlateNumber();
|
||||||
|
$date_expire = $warranty->getDateExpire();
|
||||||
|
|
||||||
|
// skip null date expire
|
||||||
|
if ($date_expire == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$expiry_date = $date_expire->format('Y-m-d');
|
||||||
|
|
||||||
|
$this->warranties_hash[$plate_number][$expiry_date] = $warranty->getID();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findSAPBattery($batt_id)
|
||||||
|
{
|
||||||
|
if (!isset($this->sapbatt_hash[$batt_id]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findWarranty($plate_number, $expiry_date)
|
||||||
|
{
|
||||||
|
$date_expire = $expiry_date->format('Y-m-d');
|
||||||
|
if (!isset($this->warranties_hash[$plate_number][$date_expire]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$em = $this->em;
|
||||||
|
|
||||||
|
// to save on joins, go with invoice item first
|
||||||
|
$query = $em->createQuery('select ii,i,jo,cv from App\Entity\InvoiceItem ii inner join ii.invoice i inner join i.job_order jo inner join jo.cus_vehicle cv join jo.customer c where ii.battery is not null and jo.service_type = :service_type');
|
||||||
|
$query->setParameter('service_type', ServiceType::BATTERY_REPLACEMENT_NEW);
|
||||||
|
/*
|
||||||
|
$query = $em->createQuery('SELECT jo FROM App\Entity\JobOrder jo
|
||||||
|
WHERE jo.service_type = :service_type');
|
||||||
|
$query->setParameter('service_type', ServiceType::BATTERY_REPLACEMENT_NEW);
|
||||||
|
*/
|
||||||
|
|
||||||
|
$result = $query->iterate();
|
||||||
|
|
||||||
|
foreach ($result as $row)
|
||||||
|
{
|
||||||
|
$invoice_item = $row[0];
|
||||||
|
$invoice = $invoice_item->getInvoice();
|
||||||
|
$jo = $invoice->getJobOrder();
|
||||||
|
$cv = $jo->getCustomerVehicle();
|
||||||
|
$customer = $jo->getCustomer();
|
||||||
|
/*
|
||||||
|
$invoice_items = [];
|
||||||
|
// for now, one invoice == one battery
|
||||||
|
|
||||||
|
|
||||||
|
$invoice_items = $jo->getInvoice()->getItems();
|
||||||
|
$invoice_item = $invoice_items[0];
|
||||||
|
*/
|
||||||
|
if ($invoice_item != null)
|
||||||
|
{
|
||||||
|
if($invoice_item->getBattery() != null)
|
||||||
|
{
|
||||||
|
// manually retrieve the SAPBattery using the SAPCode
|
||||||
|
$battery_sap_code = $invoice_item->getBattery()->getSAPCode();
|
||||||
|
$found_battery = $this->findSAPBattery($battery_sap_code);
|
||||||
|
$sap_code = '\'' . $battery_sap_code . '\'';
|
||||||
|
if (!$found_battery)
|
||||||
|
{
|
||||||
|
$sap_code = 'NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get warranty period for battery
|
||||||
|
// TODO: base it on the battery type
|
||||||
|
$warranty_period = 0;
|
||||||
|
if ($invoice_item->getBattery()->getWarrantyPrivate() != null)
|
||||||
|
{
|
||||||
|
$warranty_period = $invoice_item->getBattery()->getWarrantyPrivate();
|
||||||
|
}
|
||||||
|
if ($invoice_item->getBattery()->getWarrantyCommercial() != null)
|
||||||
|
{
|
||||||
|
$warranty_period = $invoice_item->getBattery()->getWarrantyCommercial();
|
||||||
|
}
|
||||||
|
if ($invoice_item->getBattery()->getWarrantyTnv() != null)
|
||||||
|
{
|
||||||
|
$warranty_period = $invoice_item->getBattery()->getWarrantyTnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invoice->getDateCreate() != null)
|
||||||
|
{
|
||||||
|
// check if plate number is "clean". If not, do not insert into warranty
|
||||||
|
if (!(Warranty::cleanPlateNumber($cv->getPlateNumber())))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if warranty already exists
|
||||||
|
$cleaned_plate_number = Warranty::cleanPlateNumber($cv->getPlateNumber());
|
||||||
|
|
||||||
|
$expiry_date = $this->computeDateExpire($jo->getInvoice()->getDateCreate(), $warranty_period);
|
||||||
|
$found_warranty = $this->findWarranty($cleaned_plate_number, $expiry_date);
|
||||||
|
if (!$found_warranty)
|
||||||
|
{
|
||||||
|
$bty_model_id = $invoice_item->getBattery()->getModel()->getID();
|
||||||
|
$bty_size_id = $invoice_item->getBattery()->getSize()->getID();
|
||||||
|
$warranty_class = $jo->getWarrantyClass();
|
||||||
|
|
||||||
|
$date = $jo->getInvoice()->getDateCreate();
|
||||||
|
$date_purchase = $date->format('Y-m-d');
|
||||||
|
|
||||||
|
$date_create = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
|
$date_expire = $expiry_date->format('Y-m-d');
|
||||||
|
|
||||||
|
$first_name = addslashes(trim($customer->getFirstName()));
|
||||||
|
$last_name = addslashes(trim($customer->getLastName()));
|
||||||
|
$mobile_number = addslashes(trim($customer->getPhoneMobile()));
|
||||||
|
|
||||||
|
$values = '(' . $bty_model_id . ',' . $bty_size_id . ',NULL,\'' . $warranty_class . '\',\''
|
||||||
|
. $cleaned_plate_number . '\',\'' . WarrantyStatus::ACTIVE . '\',\'' . $date_create . '\',\'' . $date_purchase
|
||||||
|
. '\',\'' . $date_expire . '\',NULL,'
|
||||||
|
. $sap_code . ',NULL,\'' . $first_name . '\',\'' . $last_name . '\',\'' . $mobile_number . '\');';
|
||||||
|
|
||||||
|
$sql_statement = 'INSERT INTO `warranty` (bty_model_id,bty_size_id,serial,warranty_class,plate_number,status,date_create,date_purchase,date_expire,date_claim,sap_bty_id,claim_id,first_name,last_name,mobile_number) VALUES ' . $values . "\n";
|
||||||
|
|
||||||
|
echo $sql_statement;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->detach($row[0]);
|
||||||
|
$em->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/Command/TestHubCounterCommand.php
Normal file
39
src/Command/TestHubCounterCommand.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use App\Service\HubCounter;
|
||||||
|
|
||||||
|
class TestHubCounterCommand extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('test:hubcounter')
|
||||||
|
->setDescription('Test hubcounter service. Currently tests addAvailableRider and getAvailableRiderCount.')
|
||||||
|
->setHelp('Test hubcounter service. Currently tests addAvailableRider and getAvailableRiderCount.')
|
||||||
|
->addArgument('hub_id', InputArgument::REQUIRED, 'Hub ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(HubCounter $hc)
|
||||||
|
{
|
||||||
|
$this->hc = $hc;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$hub_id = $input->getArgument('hub_id');
|
||||||
|
|
||||||
|
$this->hc->addAvailableRider($hub_id);
|
||||||
|
|
||||||
|
$available_rc = $this->hc->getAvailableRiderCount($hub_id);
|
||||||
|
|
||||||
|
echo "Available Riders in Hub: " . $available_rc . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/Command/TestJobOrderManagerCommand.php
Normal file
40
src/Command/TestJobOrderManagerCommand.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use App\Service\JobOrderManager;
|
||||||
|
|
||||||
|
class TestJobOrderManagerCommand extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('test:fulfilljoborder')
|
||||||
|
->setDescription('Test fulfill job order service.')
|
||||||
|
->setHelp('Test the fulfill job order service.')
|
||||||
|
->addArgument('job_order_id', InputArgument::REQUIRED, 'Job Order ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(JobOrderManager $jo_manager)
|
||||||
|
{
|
||||||
|
$this->jo_manager = $jo_manager;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$jo_id = $input->getArgument('job_order_id');
|
||||||
|
|
||||||
|
$result = $this->jo_manager->fulfillJobOrder($jo_id);
|
||||||
|
|
||||||
|
if ($result)
|
||||||
|
echo "Job Order successfully updated" . "\n";
|
||||||
|
else
|
||||||
|
echo "Job Order not updated" . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/Command/TestRegAPNSCommand.php
Normal file
40
src/Command/TestRegAPNSCommand.php
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Service\APNSClient;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
class TestRegAPNSCommand extends Command
|
||||||
|
{
|
||||||
|
protected $apns;
|
||||||
|
|
||||||
|
public function __construct( APNSClient $apns)
|
||||||
|
{
|
||||||
|
$this->apns = $apns;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('apns:test_reg')
|
||||||
|
->setDescription('Test new format for Apple Push Notification.')
|
||||||
|
->setHelp('Test new format for Apple Push Notification.')
|
||||||
|
->addArgument('push_id', InputArgument::REQUIRED, 'push_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$push_id = $input->getArgument('push_id');
|
||||||
|
$this->apns->sendReg($push_id, 'Test Delay', 'Body');
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/Command/TestRiderTrackerCommand.php
Normal file
46
src/Command/TestRiderTrackerCommand.php
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||||
|
|
||||||
|
use App\Service\RiderTracker;
|
||||||
|
|
||||||
|
class TestRiderTrackerCommand extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('test:ridertracker')
|
||||||
|
->setDescription('Test the rider tracker service')
|
||||||
|
->setHelp('Test the rider tracker service.')
|
||||||
|
->addArgument('rider_id', InputArgument::REQUIRED, 'Rider ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(RiderTracker $rtracker)
|
||||||
|
{
|
||||||
|
$this->rtracker = $rtracker;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$rider_id = $input->getArgument('rider_id');
|
||||||
|
|
||||||
|
$coordinates = $this->rtracker->getRiderLocation($rider_id);
|
||||||
|
|
||||||
|
if ($coordinates != null)
|
||||||
|
{
|
||||||
|
echo "Rider Location: " . $coordinates->getLongitude() . "," . $coordinates->getLatitude() . "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Invalid rider id." . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/Command/UpdateCustomerVehicleBatteryCommand.php
Normal file
67
src/Command/UpdateCustomerVehicleBatteryCommand.php
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
use Doctrine\Common\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
|
||||||
|
use App\Ramcar\JOStatus;
|
||||||
|
|
||||||
|
class UpdateCustomerVehicleBatteryCommand extends Command
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
protected $custvehicle_hash;
|
||||||
|
|
||||||
|
public function __construct(ObjectManager $om)
|
||||||
|
{
|
||||||
|
$this->em = $om;
|
||||||
|
$this->custvehicle_hash = [];
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('joborder:updatebattery')
|
||||||
|
->setDescription('Update customer vehicle battery information.')
|
||||||
|
->setHelp('Updates the customer vehicle battery based on the latest battery purchased. ');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
// get all job orders with fulfilled status
|
||||||
|
$jos = $this->em->getRepository(JobOrder::class)->findBy(['status' => JOStatus::FULFILLED], ['date_create' => 'DESC']);
|
||||||
|
foreach ($jos as $jo)
|
||||||
|
{
|
||||||
|
if ($jo->getCustomerVehicle() != null)
|
||||||
|
{
|
||||||
|
$custvehicle_id = $jo->getCustomerVehicle()->getID();
|
||||||
|
// check if custvehicle is in hash. This would mean that the battery has already been set
|
||||||
|
if(!isset($this->custvehicle_hash[$custvehicle_id]))
|
||||||
|
{
|
||||||
|
// get battery purchased from job order
|
||||||
|
$items = $jo->getInvoice()->getItems();
|
||||||
|
foreach($items as $item)
|
||||||
|
{
|
||||||
|
if ($item->getBattery() != null)
|
||||||
|
{
|
||||||
|
// set battery of vehicle to the latest battery purchased
|
||||||
|
$new_battery = $item->getBattery();
|
||||||
|
$jo->getCustomerVehicle()->setCurrentBattery($new_battery);
|
||||||
|
|
||||||
|
// add customer vehicle to hash
|
||||||
|
$this->custvehicle_hash[$custvehicle_id] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ use App\Service\InvoiceCreator;
|
||||||
use App\Service\RisingTideGateway;
|
use App\Service\RisingTideGateway;
|
||||||
use App\Service\MQTTClient;
|
use App\Service\MQTTClient;
|
||||||
use App\Service\GeofenceTracker;
|
use App\Service\GeofenceTracker;
|
||||||
|
use App\Service\RiderTracker;
|
||||||
|
|
||||||
use App\Entity\MobileSession;
|
use App\Entity\MobileSession;
|
||||||
use App\Entity\Customer;
|
use App\Entity\Customer;
|
||||||
|
|
@ -1116,7 +1117,7 @@ class APIController extends Controller
|
||||||
return $res->getReturnResponse();
|
return $res->getReturnResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRiderStatus(Request $req)
|
public function getRiderStatus(Request $req, RiderTracker $rt)
|
||||||
{
|
{
|
||||||
$required_params = [];
|
$required_params = [];
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
@ -1243,8 +1244,9 @@ class APIController extends Controller
|
||||||
case JOStatus::ASSIGNED:
|
case JOStatus::ASSIGNED:
|
||||||
case JOStatus::IN_TRANSIT:
|
case JOStatus::IN_TRANSIT:
|
||||||
case JOStatus::IN_PROGRESS:
|
case JOStatus::IN_PROGRESS:
|
||||||
$coord = $jo->getHub()->getCoordinates();
|
|
||||||
$rider = $jo->getRider();
|
$rider = $jo->getRider();
|
||||||
|
// get rider coordinates from redis
|
||||||
|
$coord = $rt->getRiderLocation($rider->getID());
|
||||||
|
|
||||||
// default image url
|
// default image url
|
||||||
$url_prefix = $req->getSchemeAndHttpHost();
|
$url_prefix = $req->getSchemeAndHttpHost();
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use Doctrine\ORM\Query;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
|
||||||
|
|
||||||
use App\Menu\Generator as MenuGenerator;
|
use App\Menu\Generator as MenuGenerator;
|
||||||
use App\Access\Generator as ACLGenerator;
|
use App\Access\Generator as ACLGenerator;
|
||||||
|
|
@ -275,7 +276,19 @@ class RoleController extends BaseController
|
||||||
], 422);
|
], 422);
|
||||||
} else {
|
} else {
|
||||||
// validated! save the entity
|
// validated! save the entity
|
||||||
$em->flush();
|
// catch the exception in case user updated the id
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
catch(ForeignKeyConstraintViolationException $e)
|
||||||
|
{
|
||||||
|
$error_array['id'] = 'Role has already been assigned to user/s and id cannot be updated';
|
||||||
|
return $this->json([
|
||||||
|
'success' => false,
|
||||||
|
'errors' => $error_array
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
// return successful response
|
// return successful response
|
||||||
return $this->json([
|
return $this->json([
|
||||||
|
|
|
||||||
|
|
@ -162,30 +162,37 @@ class Warranty
|
||||||
// trim and make upper case
|
// trim and make upper case
|
||||||
$clean_plate = strtoupper(trim($plate));
|
$clean_plate = strtoupper(trim($plate));
|
||||||
|
|
||||||
// remove invalid characters
|
// check if alphanumeric, max length is 11, no spaces
|
||||||
$clean_plate = preg_replace("/[^A-Z0-9]/", '', $clean_plate);
|
$res = preg_match("/^[A-Z0-9]{1,11}+$/", $clean_plate);
|
||||||
|
|
||||||
// check for 4 to 5 digit diplomatic plate
|
|
||||||
$res = preg_match("/^[0-9]{4,5}$/", $clean_plate);
|
|
||||||
if ($res)
|
|
||||||
return $clean_plate;
|
|
||||||
|
|
||||||
// ABC-1234 or ABC-123 or ABC-12 format
|
|
||||||
$res = preg_match("/^[A-Z]{3}[0-9]{2,4}$/", $clean_plate);
|
|
||||||
if ($res)
|
|
||||||
return $clean_plate;
|
|
||||||
|
|
||||||
// AB-123 or AB-12345 or AB-1234 format (motorcycles)
|
|
||||||
$res = preg_match("/^[A-Z]{2}[0-9]{3,5}$/", $clean_plate);
|
|
||||||
if ($res)
|
|
||||||
return $clean_plate;
|
|
||||||
|
|
||||||
// 1234-AB format (motorcycles)
|
|
||||||
$res = preg_match("/^[0-9]{4}[A-Z]{2}$/", $clean_plate);
|
|
||||||
if ($res)
|
if ($res)
|
||||||
return $clean_plate;
|
return $clean_plate;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// remove invalid characters
|
||||||
|
//$clean_plate = preg_replace("/[^A-Z0-9]/", '', $clean_plate);
|
||||||
|
|
||||||
|
// check for 4 to 5 digit diplomatic plate
|
||||||
|
//$res = preg_match("/^[0-9]{4,5}$/", $clean_plate);
|
||||||
|
//if ($res)
|
||||||
|
// return $clean_plate;
|
||||||
|
|
||||||
|
// ABC-1234 or ABC-123 or ABC-12 format
|
||||||
|
//$res = preg_match("/^[A-Z]{3}[0-9]{2,4}$/", $clean_plate);
|
||||||
|
//if ($res)
|
||||||
|
// return $clean_plate;
|
||||||
|
|
||||||
|
// AB-123 or AB-12345 or AB-1234 format (motorcycles)
|
||||||
|
//$res = preg_match("/^[A-Z]{2}[0-9]{3,5}$/", $clean_plate);
|
||||||
|
//if ($res)
|
||||||
|
// return $clean_plate;
|
||||||
|
|
||||||
|
// 1234-AB format (motorcycles)
|
||||||
|
//$res = preg_match("/^[0-9]{4}[A-Z]{2}$/", $clean_plate);
|
||||||
|
//if ($res)
|
||||||
|
// return $clean_plate;
|
||||||
|
|
||||||
|
//return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setPlateNumber($plate)
|
public function setPlateNumber($plate)
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,24 @@ namespace App\Service;
|
||||||
use Mosquitto\Client as MosquittoClient;
|
use Mosquitto\Client as MosquittoClient;
|
||||||
use App\Entity\JobOrder;
|
use App\Entity\JobOrder;
|
||||||
use App\Ramcar\MobileOSType;
|
use App\Ramcar\MobileOSType;
|
||||||
use Redis;
|
|
||||||
|
|
||||||
class APNSClient
|
class APNSClient
|
||||||
{
|
{
|
||||||
|
// TODO: make this a config entry
|
||||||
const REDIS_KEY = 'apns_push';
|
const REDIS_KEY = 'apns_push';
|
||||||
|
|
||||||
// protected $mclient;
|
// protected $mclient;
|
||||||
protected $redis;
|
protected $redis;
|
||||||
|
|
||||||
public function __construct($ip_address, $port)
|
public function __construct(RedisClientProvider $redis_client)
|
||||||
{
|
{
|
||||||
$this->redis = new Redis();
|
$this->redis = $redis_client->getRedisClient();
|
||||||
$this->redis->connect($ip_address, $port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
// $this->mclient->disconnect();
|
// $this->mclient->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function push($token, $message)
|
public function push($token, $message)
|
||||||
{
|
{
|
||||||
|
|
@ -53,4 +52,9 @@ class APNSClient
|
||||||
$this->push($push_id, $message);
|
$this->push($push_id, $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function sendReg($push_id, $message)
|
||||||
|
{
|
||||||
|
$this->push($push_id, $message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,10 @@ class HubCounter
|
||||||
protected $em;
|
protected $em;
|
||||||
protected $redis;
|
protected $redis;
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $em)
|
public function __construct(EntityManagerInterface $em, RedisClientProvider $redis_client)
|
||||||
{
|
{
|
||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
|
$this->redis = $redis_client->getRedisClient();
|
||||||
// TODO: make it read redis settings from config
|
|
||||||
// build a service maybe?
|
|
||||||
$this->redis = new Predis\Client();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get rider key based on id
|
// get rider key based on id
|
||||||
|
|
@ -45,7 +42,7 @@ class HubCounter
|
||||||
return $value;
|
return $value;
|
||||||
|
|
||||||
// not in cache
|
// not in cache
|
||||||
$hub = $em->getRepository(Hub::class)->find($hub_id);
|
$hub = $this->em->getRepository(Hub::class)->find($hub_id);
|
||||||
$riders = $hub->getActiveRiders();
|
$riders = $hub->getActiveRiders();
|
||||||
$rider_count = count($riders);
|
$rider_count = count($riders);
|
||||||
|
|
||||||
|
|
|
||||||
53
src/Service/JobOrderManager.php
Normal file
53
src/Service/JobOrderManager.php
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\JobOrder;
|
||||||
|
|
||||||
|
use App\Ramcar\ServiceType;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
class JobOrderManager
|
||||||
|
{
|
||||||
|
protected $em;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fulfillJobOrder($jo_id)
|
||||||
|
{
|
||||||
|
$results = $this->em->getRepository(JobOrder::class)->findby(array('id' => $jo_id, 'service_type' => ServiceType::BATTERY_REPLACEMENT_NEW));
|
||||||
|
if (isset($results[0]))
|
||||||
|
{
|
||||||
|
$jo = $results[0];
|
||||||
|
$jo->fulfill();
|
||||||
|
|
||||||
|
$cust_vehicle = $jo->getCustomerVehicle();
|
||||||
|
$invoice = $jo->getInvoice();
|
||||||
|
$this->updateCustomerVehicleBattery($cust_vehicle, $invoice);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateCustomerVehicleBattery($cust_vehicle, $invoice)
|
||||||
|
{
|
||||||
|
if (($cust_vehicle != null) && ($invoice != null))
|
||||||
|
{
|
||||||
|
$items = $invoice->getItems();
|
||||||
|
foreach ($items as $item)
|
||||||
|
{
|
||||||
|
$new_battery = $item->getBattery();
|
||||||
|
$cust_vehicle->setCurrentBattery($new_battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ namespace App\Service;
|
||||||
|
|
||||||
use Mosquitto\Client as MosquittoClient;
|
use Mosquitto\Client as MosquittoClient;
|
||||||
use App\Entity\JobOrder;
|
use App\Entity\JobOrder;
|
||||||
use Redis;
|
|
||||||
|
|
||||||
class MQTTClient
|
class MQTTClient
|
||||||
{
|
{
|
||||||
|
|
@ -15,27 +14,15 @@ class MQTTClient
|
||||||
// protected $mclient;
|
// protected $mclient;
|
||||||
protected $redis;
|
protected $redis;
|
||||||
|
|
||||||
public function __construct($ip_address, $port, $cert)
|
public function __construct(RedisClientProvider $redis_client)
|
||||||
{
|
{
|
||||||
// we use redis now
|
$this->redis = $redis_client->getRedisClient();
|
||||||
// we have an mqtt server listening on redis and sending to mqtt
|
|
||||||
$this->redis = new Redis();
|
|
||||||
$this->redis->connect('127.0.0.1', 6379);
|
|
||||||
|
|
||||||
/*
|
|
||||||
error_log("connecting to mqtt server - $ip_address : $port");
|
|
||||||
error_log("using $cert");
|
|
||||||
$this->mclient = new MosquittoClient();
|
|
||||||
$this->mclient->setTlsCertificates($cert);
|
|
||||||
$this->mclient->setTlsOptions(MosquittoClient::SSL_VERIFY_NONE, 'tlsv1');
|
|
||||||
$this->mclient->connect($ip_address, $port);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
// $this->mclient->disconnect();
|
// $this->mclient->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function publish($channel, $message)
|
public function publish($channel, $message)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
44
src/Service/RedisClientProvider.php
Normal file
44
src/Service/RedisClientProvider.php
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Predis\Client as PredisClient;
|
||||||
|
|
||||||
|
class RedisClientProvider
|
||||||
|
{
|
||||||
|
protected $redis;
|
||||||
|
protected $scheme;
|
||||||
|
protected $host;
|
||||||
|
protected $port;
|
||||||
|
protected $password;
|
||||||
|
protected $env_flag;
|
||||||
|
|
||||||
|
public function __construct($scheme, $host, $port, $password, $env_flag)
|
||||||
|
{
|
||||||
|
$this->scheme = $scheme;
|
||||||
|
$this->host = $host;
|
||||||
|
$this->port = $port;
|
||||||
|
$this->password = $password;
|
||||||
|
$this->env_flag = $env_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRedisClient()
|
||||||
|
{
|
||||||
|
if ($this->env_flag == 'dev')
|
||||||
|
{
|
||||||
|
$this->redis = new PredisClient([
|
||||||
|
"scheme"=>$this->scheme,
|
||||||
|
"host"=>$this->host,
|
||||||
|
"port"=>$this->port]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->redis = new PredisClient([
|
||||||
|
"scheme"=>$this->scheme,
|
||||||
|
"host"=>$this->host,
|
||||||
|
"port"=>$this->port,
|
||||||
|
"password"=>$this->password]);
|
||||||
|
}
|
||||||
|
return $this->redis;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/Service/RiderTracker.php
Normal file
52
src/Service/RiderTracker.php
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Rider;
|
||||||
|
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||||
|
|
||||||
|
class RiderTracker
|
||||||
|
{
|
||||||
|
const RIDER_PREFIX_KEY = 'rider.location';
|
||||||
|
|
||||||
|
protected $em;
|
||||||
|
protected $redis;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em, RedisClientProvider $redis_client)
|
||||||
|
{
|
||||||
|
$this->em = $em;
|
||||||
|
$this->redis = $redis_client->getRedisClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRiderKey($rider_id)
|
||||||
|
{
|
||||||
|
return self::RIDER_PREFIX_KEY . '.' . $rider_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRiderLocation($rider_id)
|
||||||
|
{
|
||||||
|
$coordinates = new Point(0,0);
|
||||||
|
$key = $this->getRiderKey($rider_id);
|
||||||
|
|
||||||
|
// check redis cache for rider information
|
||||||
|
if (($this->redis->hexists($key, 'longitude')) &&
|
||||||
|
($this->redis->hexists($key, 'latitude')))
|
||||||
|
{
|
||||||
|
$long = $this->redis->hget($key, 'longitude');
|
||||||
|
$lat = $this->redis->hget($key, 'latitude');
|
||||||
|
|
||||||
|
$coordinates = new Point($long, $lat);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$rider = $this->em->getRepository(Rider::class)->find($rider_id);
|
||||||
|
$coordinates = $rider->getHub()->getCoordinates();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $coordinates;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
symfony.lock
15
symfony.lock
|
|
@ -1,4 +1,16 @@
|
||||||
{
|
{
|
||||||
|
"creof/doctrine2-spatial": {
|
||||||
|
"version": "1.2.0"
|
||||||
|
},
|
||||||
|
"creof/geo-parser": {
|
||||||
|
"version": "2.1.0"
|
||||||
|
},
|
||||||
|
"creof/wkb-parser": {
|
||||||
|
"version": "v2.3.0"
|
||||||
|
},
|
||||||
|
"creof/wkt-parser": {
|
||||||
|
"version": "2.2.0"
|
||||||
|
},
|
||||||
"data-dog/audit-bundle": {
|
"data-dog/audit-bundle": {
|
||||||
"version": "v0.1.10"
|
"version": "v0.1.10"
|
||||||
},
|
},
|
||||||
|
|
@ -263,6 +275,9 @@
|
||||||
"symfony/stopwatch": {
|
"symfony/stopwatch": {
|
||||||
"version": "v4.0.2"
|
"version": "v4.0.2"
|
||||||
},
|
},
|
||||||
|
"symfony/thanks": {
|
||||||
|
"version": "v1.1.0"
|
||||||
|
},
|
||||||
"symfony/twig-bridge": {
|
"symfony/twig-bridge": {
|
||||||
"version": "v4.0.2"
|
"version": "v4.0.2"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -114,11 +114,11 @@
|
||||||
var actions = '';
|
var actions = '';
|
||||||
|
|
||||||
if (row.meta.update_url != '') {
|
if (row.meta.update_url != '') {
|
||||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.username + '" title="Edit"><i class="la la-edit"></i></a>';
|
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.meta.delete_url != '') {
|
if (row.meta.delete_url != '') {
|
||||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.username + '" title="Delete"><i class="la la-trash"></i></a>';
|
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.name + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
|
|
||||||
|
|
@ -893,7 +893,8 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script>
|
<!-- <script src="//maps.google.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script> -->
|
||||||
|
<script src="//maps.googleapis.com/maps/api/js?key={{ gmaps_api_key }}" type="text/javascript"></script>
|
||||||
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
<script src="/assets/vendors/custom/gmaps/gmaps.js" type="text/javascript"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -118,11 +118,11 @@
|
||||||
var actions = '';
|
var actions = '';
|
||||||
|
|
||||||
if (row.meta.update_url != '') {
|
if (row.meta.update_url != '') {
|
||||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.username + '" title="Edit"><i class="la la-edit"></i></a>';
|
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.meta.delete_url != '') {
|
if (row.meta.delete_url != '') {
|
||||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.username + '" title="Delete"><i class="la la-trash"></i></a>';
|
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.name + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).fail(function(response) {
|
}).fail(function(response) {
|
||||||
if (response.status == 422) {
|
if (response.status == 422 || response.status == 403) {
|
||||||
var errors = response.responseJSON.errors;
|
var errors = response.responseJSON.errors;
|
||||||
var firstfield = false;
|
var firstfield = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,11 +93,11 @@
|
||||||
var actions = '';
|
var actions = '';
|
||||||
|
|
||||||
if (row.meta.update_url != '') {
|
if (row.meta.update_url != '') {
|
||||||
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.username + '" title="Edit"><i class="la la-edit"></i></a>';
|
actions += '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" data-id="' + row.name + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row.meta.delete_url != '') {
|
if (row.meta.delete_url != '') {
|
||||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.username + '" title="Delete"><i class="la la-trash"></i></a>';
|
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.id + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class APNSClient():
|
||||||
def setupConnection(self):
|
def setupConnection(self):
|
||||||
# socket
|
# socket
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
wsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, certfile=self.cert_file)
|
wsock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1_2, certfile=self.cert_file)
|
||||||
wsock.connect((self.host, self.port))
|
wsock.connect((self.host, self.port))
|
||||||
|
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
|
|
|
||||||
12
utils/apns_sender/apns_sender.service
Normal file
12
utils/apns_sender/apns_sender.service
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Apple Push Notification Sender Service
|
||||||
|
After=mosquitto.service redis.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/python /root/www/resq/utils/apns_sender/new_sender.py
|
||||||
|
StandardInput=tty-force
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
90
utils/apns_sender/new_sender.py
Normal file
90
utils/apns_sender/new_sender.py
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
from daemonize import Daemonize
|
||||||
|
from apns import APNs, Frame, Payload
|
||||||
|
import redis
|
||||||
|
import time
|
||||||
|
import signal
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import struct
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def sigint_handler(signal, frame):
|
||||||
|
sys.exit(0)
|
||||||
|
os._exit(0)
|
||||||
|
|
||||||
|
def redisLoop(apns, logger):
|
||||||
|
r = redis.StrictRedis(host='localhost', port=6379, db=0)
|
||||||
|
while 1:
|
||||||
|
#logger.info("Checking queue for messages to send...")
|
||||||
|
time.sleep(0)
|
||||||
|
data = r.brpop("apns_push", 10)
|
||||||
|
if data:
|
||||||
|
info = data[1].split('|')
|
||||||
|
logger.info("Token: " + info[0] + " message: " + info[1])
|
||||||
|
try:
|
||||||
|
apns.sendNotification(info[0], info[1], "notification")
|
||||||
|
except TypeError:
|
||||||
|
logger.info("Invalid token: " + info[0])
|
||||||
|
|
||||||
|
|
||||||
|
def sigint_handler(signal, frame):
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def get_logger():
|
||||||
|
logger = logging.getLogger("apns_logger")
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
fh = logging.FileHandler("/tmp/apns_sender.log")
|
||||||
|
fmt = '%(asctime)s - %(threadName)s - %(levelname)s - %(message)s'
|
||||||
|
formatter = logging.Formatter(fmt)
|
||||||
|
fh.setFormatter(formatter)
|
||||||
|
|
||||||
|
logger.addHandler(fh)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
class APNSClient():
|
||||||
|
def __init__(self, title, cert_file, logger):
|
||||||
|
self.title = title
|
||||||
|
self.cert_file = cert_file
|
||||||
|
self.logger = logger
|
||||||
|
# connect
|
||||||
|
self.apns = APNs(cert_file=self.cert_file)
|
||||||
|
|
||||||
|
def sendNotification(self, token, body, notif_type):
|
||||||
|
# apns packet
|
||||||
|
alert = {"title" : self.title,
|
||||||
|
"body" : body,
|
||||||
|
"type" : notif_type}
|
||||||
|
|
||||||
|
payload = Payload(alert=alert, sound="default", badge=1, content_available=True)
|
||||||
|
self.apns.gateway_server.send_notification(token, payload)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logger = get_logger()
|
||||||
|
logger.info("Starting apns_sender")
|
||||||
|
|
||||||
|
#apns = APNs(use_sandbox=False, cert_file=cert_file)
|
||||||
|
#apns = setup_apns()
|
||||||
|
|
||||||
|
# TODO: load from config file
|
||||||
|
cert_file = "/root/ios_push_test/ios_prod.pem"
|
||||||
|
apns = APNSClient("Motolite Res-q", cert_file, logger)
|
||||||
|
|
||||||
|
logger.info("Starting redis loop")
|
||||||
|
redisLoop(apns, logger)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGINT, sigint_handler)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pid = "/tmp/apns_sender.pid"
|
||||||
|
#daemon = Daemonize(app="apns_sender", pid=pid, action=main)
|
||||||
|
#daemon.start()
|
||||||
|
main()
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
load data local infile '/tmp/plate_numbers.csv' into table plate_number fields terminated by ',';
|
load data local infile '/tmp/plate_numbers.csv' into table plate_number fields terminated by ',';
|
||||||
|
load data infile '/tmp/legacy_jo.csv' into table legacy_job_order fields terminated by '|' (id, trans_date, trans_type, origin, car_brand, car_make, car_model, car_color, cust_name, cust_first_name, cust_middle_name, cust_last_name, cust_contact, cust_mobile, cust_landline, delivery_instructions, agent_notes_1, delivery_date, delivery_time, advance_order, stage, cancel_reason, cancel_reason_specify, payment_method, prepared_by, dispatch_time, dispatch_date, dispatched_by, address, landmark, date_purchase, plate_number);
|
||||||
load data infile '/tmp/legacy_jo_row.csv' into table legacy_job_order_row fields terminated by ',' enclosed by '"' lines terminated by '\n' (job_order_id, item, qty, price, price_level, status, account, enrollee) set id = null;
|
load data infile '/tmp/legacy_jo_row.csv' into table legacy_job_order_row fields terminated by ',' enclosed by '"' lines terminated by '\n' (job_order_id, item, qty, price, price_level, status, account, enrollee) set id = null;
|
||||||
load data local infile '/tmp/warranty.csv' into table warranty fields terminated by ',' (bty_model_id, bty_size_id, serial, warranty_class, plate_number, status, date_create, date_purchase, date_expire, date_claim, claim_id, sap_bty_id, first_name, last_name, mobile_number) set id = null;
|
load data local infile '/tmp/warranty.csv' into table warranty fields terminated by ',' (bty_model_id, bty_size_id, serial, warranty_class, plate_number, status, date_create, date_purchase, date_expire, date_claim, claim_id, sap_bty_id, first_name, last_name, mobile_number) set id = null;
|
||||||
load data infile '/tmp/legacy_jo.csv' into table legacy_job_order fields terminated by '|' (id, trans_date, trans_type, origin, car_brand, car_make, car_model, car_color, cust_name, cust_first_name, cust_middle_name, cust_last_name, cust_contact, cust_mobile, cust_landline, delivery_instructions, agent_notes_1, delivery_date, delivery_time, advance_order, stage, cancel_reason, cancel_reason_specify, payment_method, prepared_by, dispatch_time, dispatch_date, dispatched_by, address, landmark, date_purchase, plate_number);
|
|
||||||
|
|
|
||||||
104
utils/legacy_load/sap_battery.sql
Normal file
104
utils/legacy_load/sap_battery.sql
Normal file
File diff suppressed because one or more lines are too long
12
utils/mqtt_sender/mqtt_sender.service
Normal file
12
utils/mqtt_sender/mqtt_sender.service
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[Unit]
|
||||||
|
Description=MQTT Sender Service
|
||||||
|
After=mosquitto.service redis.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/python /root/www/resq/utils/mqtt_sender/mqtt_sender.py
|
||||||
|
StandardInput=tty-force
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -1,42 +1,38 @@
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
import ssl
|
import ssl
|
||||||
from threading import Thread
|
|
||||||
import redis
|
import redis
|
||||||
import time
|
import time
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import mysql.connector
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
def mysql_connect(user, password, host, database):
|
class RiderLocationCache(object):
|
||||||
conn = mysql.connector.connect(user=user,
|
|
||||||
password=password,
|
|
||||||
host=host,
|
|
||||||
database=database)
|
|
||||||
return conn
|
|
||||||
|
|
||||||
def init_subscriptions(client, conn):
|
def run(self, client):
|
||||||
# given mysql connection, get all rider sessions
|
print "running loop..."
|
||||||
query = ("select id from rider_session")
|
client.loop_forever()
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute(query)
|
# TODO: fix this and put these guys back under the class
|
||||||
for (id) in cursor:
|
def init_subscriptions(client):
|
||||||
print "subscribing to rider session %s" % id
|
print "subscribing to wildcard #"
|
||||||
client.subscribe('motorider_%s' % id)
|
client.subscribe('#')
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
def on_connect(client, userdata, flags, rc):
|
def on_connect(client, userdata, flags, rc):
|
||||||
conn = mysql_connect('resq', 'Motolite456', '127.0.0.1', 'resq')
|
init_subscriptions(client)
|
||||||
init_subscriptions(client, conn)
|
#print("Connected with result code "+str(rc))
|
||||||
print("Connected with result code "+str(rc))
|
# client.subscribe("$SYS/#")
|
||||||
client.subscribe("$SYS/#")
|
|
||||||
|
def user_data_set(userdata):
|
||||||
|
conn = redis.StrictRedis(host='localhost', port=6379, db=0)
|
||||||
|
return conn
|
||||||
|
|
||||||
def on_publish(client, userdata, mid):
|
def on_publish(client, userdata, mid):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def on_message(client, userdata, message):
|
def on_message(client, userdata, message):
|
||||||
print("message topic=",message.topic[0:10])
|
redis_conn = user_data_set(userdata)
|
||||||
|
#print("message topic=", message.topic[0:10])
|
||||||
|
|
||||||
if message.topic[0:10] != 'motorider_':
|
if message.topic[0:10] != 'motorider_':
|
||||||
return
|
return
|
||||||
|
|
@ -44,6 +40,7 @@ def on_message(client, userdata, message):
|
||||||
|
|
||||||
# check if json decodable
|
# check if json decodable
|
||||||
res = json.loads(message.payload)
|
res = json.loads(message.payload)
|
||||||
|
#print res
|
||||||
|
|
||||||
# get rider session id
|
# get rider session id
|
||||||
sess_id = message.topic[10:]
|
sess_id = message.topic[10:]
|
||||||
|
|
@ -56,51 +53,17 @@ def on_message(client, userdata, message):
|
||||||
if res['event'] != 'driver_location':
|
if res['event'] != 'driver_location':
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# save the longitude and latitude
|
||||||
|
# get the rider id from sess_id
|
||||||
|
rider_key = "rider.location.%s" % sess_id
|
||||||
|
rider_long = str(res['longitude'])
|
||||||
|
rider_lat = str(res['latitude'])
|
||||||
|
|
||||||
|
# set the location
|
||||||
|
redis_conn.hmset(rider_key, {'longitude': rider_long, 'latitude': rider_lat})
|
||||||
|
|
||||||
# update our redis key
|
# update our redis key
|
||||||
key = 'location_%s' % sess_id
|
key = 'location_%s' % sess_id
|
||||||
print "setting %s" % key
|
#print "setting %s" % key
|
||||||
redis_conn.setex(key, 1600, message.payload)
|
redis_conn.setex(key, 1600, message.payload)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def getRedis(i):
|
|
||||||
r = redis.StrictRedis(host='localhost', port=6379, db=0)
|
|
||||||
while 1:
|
|
||||||
time.sleep(0)
|
|
||||||
data = r.brpop("events", 10)
|
|
||||||
if data:
|
|
||||||
info = data[1].split('|')
|
|
||||||
print "Channel: " + info[0] + " message: " + info[1]
|
|
||||||
client.publish(info[0], info[1])
|
|
||||||
|
|
||||||
|
|
||||||
def sigint_handler(signal, frame):
|
|
||||||
print 'Interrupted'
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
client = mqtt.Client()
|
|
||||||
client.on_connect = on_connect
|
|
||||||
# client.on_publish = on_publish
|
|
||||||
client.on_message = on_message
|
|
||||||
|
|
||||||
redis_conn = redis.StrictRedis(host='localhost', port=6379, db=0)
|
|
||||||
|
|
||||||
|
|
||||||
#client.tls_set(
|
|
||||||
# "/etc/letsencrypt/live/resqaws.jankstudio.com/fullchain.pem", cert_reqs=ssl.CERT_NONE,
|
|
||||||
# tls_version=ssl.PROTOCOL_TLSv1)
|
|
||||||
client.tls_set(
|
|
||||||
"/root/aws_ssl_keys/fullchain.pem", cert_reqs=ssl.CERT_NONE,
|
|
||||||
tls_version=ssl.PROTOCOL_TLSv1)
|
|
||||||
client.connect("resqaws.jankstudio.com", 8883, 60)
|
|
||||||
|
|
||||||
|
|
||||||
#t = Thread(target=getRedis, args=(1,))
|
|
||||||
|
|
||||||
#t.start()
|
|
||||||
|
|
||||||
#signal.signal(signal.SIGINT, sigint_handler)
|
|
||||||
client.loop_forever()
|
|
||||||
|
|
||||||
|
|
|
||||||
23
utils/rider_location_cache/riderloc.py
Normal file
23
utils/rider_location_cache/riderloc.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
import rider_location_cache as rlc
|
||||||
|
import ssl
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
client = mqtt.Client()
|
||||||
|
client.on_connect = rlc.on_connect
|
||||||
|
# client.on_publish = on_publish
|
||||||
|
client.on_message = rlc.on_message
|
||||||
|
|
||||||
|
#client.tls_set(
|
||||||
|
# "/etc/letsencrypt/live/resqaws.jankstudio.com/fullchain.pem", cert_reqs=ssl.CERT_NONE,
|
||||||
|
# tls_version=ssl.PROTOCOL_TLSv1)
|
||||||
|
client.tls_set(
|
||||||
|
"/root/aws_ssl_keys/fullchain.pem", cert_reqs=ssl.CERT_NONE,
|
||||||
|
tls_version=ssl.PROTOCOL_TLSv1)
|
||||||
|
#client.connect("resqaws.jankstudio.com", 8883, 60)
|
||||||
|
client.connect("localhost", 8883, 60)
|
||||||
|
|
||||||
|
|
||||||
|
rider_location = rlc.RiderLocationCache()
|
||||||
|
rider_location.run(client)
|
||||||
12
utils/rider_location_cache/riderloc.service
Normal file
12
utils/rider_location_cache/riderloc.service
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Rider Location Cache Service
|
||||||
|
After=mosquitto.service redis.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/python /root/www/resq/utils/rider_location_cache/riderloc.py
|
||||||
|
StandardInput=tty-force
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
13
utils/test_apns/test_apns.py
Normal file
13
utils/test_apns/test_apns.py
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
from apns import APNs, Frame, Payload
|
||||||
|
|
||||||
|
|
||||||
|
#apns = APNs(use_sandbox=True, cert_file='/root/ios_push_test/motoliteUserDev.pem')
|
||||||
|
apns = APNs(cert_file='/root/ios_push_test/motoliteUserProd.pem')
|
||||||
|
|
||||||
|
alert = {"title" : "Motolite Res-q Notification",
|
||||||
|
"body" : "Test Notification",
|
||||||
|
"type" : "register"}
|
||||||
|
|
||||||
|
token_hex = "0D89F702B8E5A235E5100C47912DCBC346CE503DBB860572402031595D6F4C6C"
|
||||||
|
payload = Payload(alert=alert, sound="default", badge=1, content_available=True)
|
||||||
|
apns.gateway_server.send_notification(token_hex, payload)
|
||||||
1
utils/warranty_expire/warranty_expire.sql
Normal file
1
utils/warranty_expire/warranty_expire.sql
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
update warranty set status='expired' where date_expire is not null and date_expire < now() - interval 1 day;
|
||||||
Loading…
Reference in a new issue