Draft: Resolve "API for insurance" #1654

Open
korina.cordero wants to merge 11 commits from 728-api-for-insurance into master
16 changed files with 1853 additions and 0 deletions

View file

@ -586,3 +586,17 @@ access_keys:
label: Update
- id: ownership_type.delete
label: Delete
- id: motor_vehicle_type
label: Motor Vehicle Type Access
acls:
- id: motor_vehicle_type.menu
label: Menu
- id: motor_vehicle_type.list
label: List
- id: motor_vehicle_type.add
label: Add
- id: motor_vehicle_type.update
label: Update
- id: motor_vehicle_type.delete
label: Delete

View file

@ -249,3 +249,7 @@ main_menu:
acl: ownership_type.menu
label: Ownership Types
parent: database
- id: motor_vehicle_type_list
acl: motor_vehicle_type.menu
label: Motor Vehicle Types
parent: database

View file

@ -0,0 +1,6 @@
# insurance api
api_insurance_create:
path: /api/insurance/create
controller: App\Controller\Insurance\InsuranceAPIController::createCTPLApplication
methods: [POST]

View file

@ -0,0 +1,35 @@
motor_vehicle_type_list:
path: /motor-vehicle-types
controller: App\Controller\MotorVehicleTypeController::index
methods: [GET]
motor_vehicle_type_rows:
path: /motor-vehicle-types/rowdata
controller: App\Controller\MotorVehicleTypeController::datatableRows
methods: [POST]
motor_vehicle_type_add_form:
path: /motor-vehicle-types/newform
controller: App\Controller\MotorVehicleTypeController::addForm
methods: [GET]
motor_vehicle_type_add_submit:
path: /motor-vehicle-types
controller: App\Controller\MotorVehicleTypeController::addSubmit
methods: [POST]
motor_vehicle_type_update_form:
path: /motor-vehicle-types/{id}
controller: App\Controller\MotorVehicleTypeController::updateForm
methods: [GET]
motor_vehicle_type_update_submit:
path: /motor-vehicle-types/{id}
controller: App\Controller\MotorVehicleTypeController::updateSubmit
methods: [POST]
motor_vehicle_type_delete:
path: /motor-vehicle-types/{id}
controller: App\Controller\MotorVehicleTypeController::deleteSubmit
methods: [DELETE]

View file

@ -328,3 +328,16 @@ services:
App\Service\WarrantySerialLoadLogger:
arguments:
$em: "@doctrine.orm.entity_manager"
# insurance connector
App\Service\InsuranceConnector:
arguments:
$base_url: "%env(INSURANCE_BASE_URL)%"
$username: "%env(INSURANCE_USERNAME)%"
$password: "%env(INSURANCE_PASSWORD)%"
$token: "%env(INSURANCE_TOKEN)%"
# insurance data validator
App\Service\InsuranceDataValidator:
arguments:
$em: "@doctrine.orm.entity_manager"

View file

@ -0,0 +1,86 @@
<?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\InsuranceConnector;
use App\Service\InsuranceDataValidator;
use App\Insurance\ClientData;
use App\Insurance\ClientType;
use App\Insurance\LineType;
class TestInsuranceConnectorCommand extends Command
{
protected $insurance;
protected $ins_validator;
protected function configure()
{
$this->setName('test:create-insurance-application')
->setDescription('Test create insurance application service.')
->setHelp('Test the create insurance application service.');
}
public function __construct(InsuranceConnector $insurance, InsuranceDataValidator $ins_validator)
{
$this->insurance = $insurance;
$this->ins_validator = $ins_validator;
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$client_data = new ClientData();
// set client info part
$client_data->setClientType(ClientType::INDIVIDUAL)
->setFirstName('Test')
->setMiddleName('Resq')
->setSurname('Customer')
->setCorporateName('Customer, Test Resq');
// set the client contact info part
$client_data->setAddressNumber('113')
->setAddressStreet('Test Street')
->setAddressBuilding('Test Building')
->setAddressBarangay('Legaspi Village')
->setAddressCity('Makati City')
->setAddressProvince('Metro Manila')
->setZipcode(1200)
->setMobileNumber('09171234567')
->setEmailAddress('test.resq@gmail.com');
// set the car info part
$client_data->setMake('HYUNDAI')
->setModel('ACCENT')
->setSeries('1.4 A/T')
->setColor('PHANTOM BLACK')
->setPlateNumber('ABC1234')
->setMvFileNumber('123456789012345')
->setMotorNumber('E31TE-0075268')
->setSerialChassis('PA0SEF210K0075701')
->setYearModel(2020)
->setMvTypeID(1)
->setBodyType('SEDAN')
->setLine(LineType::PRIVATE_CAR)
->setPublic(false);
$error_message = $this->ins_validator->validateClientData($client_data);
if ($error_message == null)
{
$result = $this->insurance->processApplication($client_data);
error_log(json_encode($result));
}
else
error_log($error_message);
return 0;
}
}

View file

@ -0,0 +1,217 @@
<?php
namespace App\Controller\Insurance;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Controller\LoggedController;
use App\Insurance\ClientData;
use App\Insurance\ClientType;
use App\Insurance\LineType;
use App\Ramcar\APIResult;
use App\Service\InsuranceDataValidator;
use App\Service\InsuranceConnector;
use App\Entity\MobileSession;
// controller to connect mobile app to insurance api
class InsuranceAPIController extends Controller implements LoggedController
{
protected $session;
public function __construct()
{
$this->session = null;
}
public function createCTPLApplication(Request $req, EntityManagerInterface $em, InsuranceDataValidator $ins_validator,
InsuranceConnector $insurance)
{
// check parameters
$required_params = [
'client_type',
'first_name',
'last_name',
'corporate_name',
'address_number',
'address_barangay',
'address_city',
'address_province',
'zipcode',
'mobile_number',
'email_address',
'make',
'model',
'series',
'color',
'plate_number',
'mv_file_number',
'motor_number',
'serial_chassis',
'year_model',
'mv_type_id',
'body_type',
'is_public',
'line',
];
// check required parameters and api key
$res = $this->checkParamsAndKey($req, $em, $required_params);
if ($res->isError())
return $res->getReturnResponse();
// create client data
$client_data = new ClientData();
$this->setClientData($req, $client_data);
// check if client data values are valid
$error_message = $ins_validator->validateClientData($client_data);
if ($error_message != null)
{
// return error message
$res->setError(true)
->setErrorMessage($error_message);
return $res->getReturnResponse();
}
$result = $insurance->processApplication($client_data);
// check status of result
if ($result['status'] == 'error')
{
// get message and return error message
$message = $result['message'];
$res->setError(true)
->setErrorMessage($message);
return $res->getReturnResponse();
}
// return data portion of result received from insurance api
$data = $result['data'];
$res->setData($data);
return $res->getReturnResponse();
}
protected function setClientData(Request $req, ClientData $client_data)
{
// set client info part
$client_data->setClientType($req->request->get('client_type', ''))
->setFirstName($req->request->get('first_name', ''))
->setMiddleName($req->request->get('middle_name', ''))
->setSurname($req->request->get('last_name', ''))
->setCorporateName($req->request->get('corporate_name', ''));
// set the client contact info part
$client_data->setAddressNumber($req->request->get('address_number', ''))
->setAddressStreet($req->request->get('address_street', ''))
->setAddressBuilding($req->request->get('address_building', ''))
->setAddressBarangay($req->request->get('address_barangay', ''))
->setAddressCity($req->request->get('address_city', ''))
->setAddressProvince($req->request->get('address_province', ''))
->setZipcode($req->request->get('zipcode', 0))
->setMobileNumber($req->request->get('mobile_number', ''))
->setEmailAddress($req->request->get('email_address', ''));
// set the car info part
$client_data->setMake($req->request->get('make', ''))
->setModel($req->request->get('model', ''))
->setSeries($req->request->get('series', ''))
->setColor($req->request->get('color', ''))
->setPlateNumber($req->request->get('plate_number', ''))
->setMvFileNumber($req->request->get('mv_file_number', ''))
->setMotorNumber($req->request->get('motor_number', ''))
->setSerialChassis($req->request->get('serial_chassis', ''))
->setYearModel($req->request->get('year_model', 0))
->setMvTypeID($req->request->get('mv_type_id', 0))
->setBodyType($req->request->get('body_type', ''))
->setLine($req->request->get('line', ''))
->setPublic($req->request->get('is_public', false));
}
protected function checkMissingParameters(Request $req, $params = [])
{
$missing = [];
// check if parameters are there
foreach ($params as $param)
{
if ($req->getMethod() == 'GET')
{
$check = $req->query->get($param);
if (empty($check))
$missing[] = $param;
}
else if ($req->getMethod() == 'POST')
{
$check = $req->request->get($param);
if (empty($check))
$missing[] = $param;
}
else
return $params;
}
return $missing;
}
protected function checkAPIKey($em, $api_key)
{
// find the api key (session id)
$session = $em->getRepository(MobileSession::class)->find($api_key);
if ($session == null)
return null;
return $session;
}
protected function checkParamsAndKey(Request $req, $em, $params)
{
// returns APIResult object
$res = new APIResult();
// check for api_key in query string
$api_key = $req->query->get('api_key');
if (empty($api_key))
{
$res->setError(true)
->setErrorMessage('Missing API key');
return $res;
}
// check missing parameters
$missing = $this->checkMissingParameters($req, $params);
if (count($missing) > 0)
{
$miss_string = implode(', ', $missing);
$res->setError(true)
->setErrorMessage('Missing parameter(s): ' . $miss_string);
return $res;
}
// check api key
$sess = $this->checkAPIKey($em, $req->query->get('api_key'));
if ($sess == null)
{
$res->setError(true)
->setErrorMessage('Invalid API Key');
return $res;
}
// store session
$this->session = $sess;
return $res;
}
}

View file

@ -0,0 +1,258 @@
<?php
namespace App\Controller;
use App\Entity\MotorVehicleType;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Catalyst\MenuBundle\Annotation\Menu;
class MotorVehicleTypeController extends Controller
{
/**
* @Menu(selected="motor_vehicle_type_list")
* @IsGranted("motor_vehicle_type.list")
*/
public function index()
{
$this->denyAccessUnlessGranted('motor_vehicle_type.list', null, 'No access.');
return $this->render('motor-vehicle-type/list.html.twig');
}
/**
* @IsGranted("motor_vehicle_type.list")
*/
public function datatableRows(Request $req)
{
// get query builder
$qb = $this->getDoctrine()
->getRepository(MotorVehicleType::class)
->createQueryBuilder('q');
// get datatable params
$datatable = $req->request->get('datatable');
// count total records
$tquery = $qb->select('COUNT(q)');
$this->setQueryFilters($datatable, $tquery);
$total = $tquery->getQuery()
->getSingleScalarResult();
// get current page number
$page = $datatable['pagination']['page'] ?? 1;
$perpage = $datatable['pagination']['perpage'];
$offset = ($page - 1) * $perpage;
// add metadata
$meta = [
'page' => $page,
'perpage' => $perpage,
'pages' => ceil($total / $perpage),
'total' => $total,
'sort' => 'asc',
'field' => 'id'
];
// build query
$query = $qb->select('q');
$this->setQueryFilters($datatable, $query);
// check if sorting is present, otherwise use default
if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) {
$order = $datatable['sort']['sort'] ?? 'asc';
$query->orderBy('q.' . $datatable['sort']['field'], $order);
} else {
$query->orderBy('q.id', 'asc');
}
// get rows for this page
$obj_rows = $query->setFirstResult($offset)
->setMaxResults($perpage)
->getQuery()
->getResult();
// process rows
$rows = [];
foreach ($obj_rows as $orow) {
// add row data
$row['id'] = $orow->getID();
$row['mv_type_id'] = $orow->getMvTypeID();
$row['lto_mv_type'] = $orow->getLtoMvType();
$row['vehicle_type'] = $orow->getVehicleType();
// add row metadata
$row['meta'] = [
'update_url' => '',
'delete_url' => ''
];
// add crud urls
if ($this->isGranted('motor_vehicle_type.update'))
$row['meta']['update_url'] = $this->generateUrl('motor_vehicle_type_update_form', ['id' => $row['id']]);
if ($this->isGranted('motor_vehicle_type.delete'))
$row['meta']['delete_url'] = $this->generateUrl('motor_vehicle_type_delete', ['id' => $row['id']]);
$rows[] = $row;
}
// response
return $this->json([
'meta' => $meta,
'data' => $rows
]);
}
/**
* @Menu(selected="motor_vehicle_type.list")
* @IsGranted("motor_vehicle_type.add")
*/
public function addForm()
{
$motor_vehicle_type = new MotorVehicleType();
$params = [
'motor_vehicle_type' => $motor_vehicle_type,
'mode' => 'create',
];
// response
return $this->render('motor-vehicle-type/form.html.twig', $params);
}
/**
* @IsGranted("motor_vehicle_type.add")
*/
public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator)
{
$motor_vehicle_type = new MotorVehicleType();
$this->setObject($motor_vehicle_type, $req);
// validate
$errors = $validator->validate($motor_vehicle_type);
// initialize error list
$error_array = [];
// add errors to list
foreach ($errors as $error) {
$error_array[$error->getPropertyPath()] = $error->getMessage();
}
// check if any errors were found
if (!empty($error_array)) {
// return validation failure response
return $this->json([
'success' => false,
'errors' => $error_array
], 422);
}
// validated! save the entity
$em->persist($motor_vehicle_type);
$em->flush();
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
/**
* @Menu(selected="motor_vehicle_type_list")
* @ParamConverter("motor_vehicle_type", class="App\Entity\MotorVehicleType")
* @IsGranted("motor_vehicle_type.update")
*/
public function updateForm($id, EntityManagerInterface $em, MotorVehicleType $motor_vehicle_type)
{
$params = [];
$params['motor_vehicle_type'] = $motor_vehicle_type;
$params['mode'] = 'update';
// response
return $this->render('motor-vehicle-type/form.html.twig', $params);
}
/**
* @ParamConverter("motor_vehicle_type", class="App\Entity\MotorVehicleType")
* @IsGranted("motor_vehicle_type.update")
*/
public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, MotorVehicleType $motor_vehicle_type)
{
$this->setObject($motor_vehicle_type, $req);
// validate
$errors = $validator->validate($motor_vehicle_type);
// initialize error list
$error_array = [];
// add errors to list
foreach ($errors as $error) {
$error_array[$error->getPropertyPath()] = $error->getMessage();
}
// check if any errors were found
if (!empty($error_array)) {
// return validation failure response
return $this->json([
'success' => false,
'errors' => $error_array
], 422);
}
// validated! save the entity
$em->flush();
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
/**
* @ParamConverter("motor_vehicle_type", class="App\Entity\MotorVehicleType")
* @IsGranted("motor_vehicle_type.update")
*/
public function deleteSubmit(EntityManagerInterface $em, MotorVehicleType $motor_vehicle_type)
{
// delete this object
$em->remove($motor_vehicle_type);
$em->flush();
// response
$response = new Response();
$response->setStatusCode(Response::HTTP_OK);
$response->send();
}
protected function setObject(MotorVehicleType $obj, Request $req)
{
// set and save values
$obj->setMvTypeID($req->request->get('mv_type_id'))
->setLtoMvType($req->request->get('lto_mv_type'))
->setVehicleType($req->request->get('vehicle_type'));
}
protected function setQueryFilters($datatable, QueryBuilder $query)
{
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
$query->where('q.lto_mv_type LIKE :filter')
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
}
}
}

View file

@ -0,0 +1,88 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
* @ORM\Table(name="motor_vehicle_type", indexes={
* @ORM\Index(name="motor_vehicle_type_idx", columns={"mv_type_id"}),
* })
*/
class MotorVehicleType
{
// unique id
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
// this is decided upon by lto
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank()
*/
protected $mv_type_id;
/**
* @ORM\Column(type="string", length=50)
* @Assert\NotBlank()
*/
protected $lto_mv_type;
/**
* @ORM\Column(type="string", length=50)
* @Assert\NotBlank()
*/
protected $vehicle_type;
public function __construct()
{
$this->mv_type_id = 0;
$this->lto_mv_type = '';
$this->vehicle_type = '';
}
public function getID()
{
return $this->id;
}
public function setMvTypeID($mv_type_id)
{
$this->mv_type_id = $mv_type_id;
return $this;
}
public function getMvTypeID()
{
return $this->mv_type_id;
}
public function setLtoMvType($lto_mv_type)
{
$this->lto_mv_type = $lto_mv_type;
return $this;
}
public function getLtoMvType()
{
return $this->lto_mv_type;
}
public function setVehicleType($vehicle_type)
{
$this->vehicle_type = $vehicle_type;
return $this;
}
public function getVehicleType()
{
return $this->vehicle_type;
}
}

View file

@ -0,0 +1,369 @@
<?php
namespace App\Insurance;
class ClientData
{
// client_info
protected $client_type; // client type. Mandatory. String. Valid values are 'C' or I'. C for corporate, I for individual
protected $first_name; // first name of client. Mandatory. String.
protected $middle_name; // middle name of client. Optional. String.
protected $surname; // surname of client. Mandatory. String.
protected $corporate_name; // corporate name or whole name of client that starts with <surname>, <first name> <middle name>. Mandatory. String.
// client_contact_info
protected $address_number; // client house number address. Mandatory. String.
protected $address_street; // client street address. Optional. String.
protected $address_building; // client build address. Optional. String.
protected $address_barangay; // client barangay address. Mandatory. String.
protected $address_city; // client city address. Mandatory. String.
protected $address_province; // client province address. Mandatory. String.
protected $zipcode; // client zip code. Mandatory. Integer.
protected $mobile_number; // client mobile number. Mandatory. String.
protected $email_address; // client email address. Mandatory. String.
// car_info
protected $make; // vehicle make. Mandatory. String.
protected $model; // vehicle model. Mandatory. String.
protected $series; // vehicle seris. Mandatory. String.
protected $color; // vehicle color. Mandatory. String.
protected $plate_number; // vehicle plate number. Mandatory. String.
protected $mv_file_number; // vehicle MV file number. Mandatory. String.
protected $motor_number; // vehicle motor number. Mandatory. String.
protected $serial_chassis; // vehicle serial or chassis number. Mandatory. String.
protected $year_model; // year model of vehicle. Mandatory. Integer.
protected $mv_type_id; // LTO mv type. Mandatory. Integer.
protected $body_type; // vehicle body type. Mandatory. String.
protected $flag_public; // public vehicle or not? Mandatory. Boolean.
protected $line; // defines where vehicle should be part of. Mandatory. String. Valid values are: PCOC - Private Car, MCOC - Mototcycle/Motorcycle with Sidecar/Tricycle(is_public is false), CCOC - Commercial Vehicle, LCOC - Motorcycle with sidecar/Tricycle(is_public is true)
public function __construct()
{
$this->client_type = '';
$this->first_name = '';
$this->middle_name = '';
$this->surname = '';
$this->corporate_name = '';
$this->address_number = '';
$this->address_street = '';
$this->address_bulding = '';
$this->address_barangay = '';
$this->address_city = '';
$this->address_province = '';
$this->zipcode = 0;
$this->mobile_number = '';
$this->email_address = '';
$this->make = '';
$this->model = '';
$this->series = '';
$this->color = '';
$this->plate_number = '';
$this->mv_file_number = '';
$this->motor_number = '';
$this->serial_chassis = '';
$this->year_model = 0;
$this->mv_type_id = 0;
$this->body_type = '';
$this->flag_public = false;
$this->line = '';
}
public function setClientType($client_type)
{
$this->client_type = $client_type;
return $this;
}
public function getClientType()
{
return $this->client_type;
}
public function setFirstName($first_name)
{
$this->first_name = $first_name;
return $this;
}
public function getFirstName()
{
return $this->first_name;
}
public function setMiddleName($middle_name)
{
$this->middle_name = $middle_name;
return $this;
}
public function getMiddleName()
{
return $this->middle_name;
}
public function setSurname($surname)
{
$this->surname = $surname;
return $this;
}
public function getSurname()
{
return $this->surname;
}
public function setCorporateName($corporate_name)
{
$this->corporate_name = $corporate_name;
return $this;
}
public function getCorporateName()
{
return $this->corporate_name;
}
public function setAddressNumber($address_number)
{
$this->address_number = $address_number;
return $this;
}
public function getAddressNumber()
{
return $this->address_number;
}
public function setAddressStreet($address_street)
{
$this->address_street = $address_street;
return $this;
}
public function getAddressStreet()
{
return $this->address_street;
}
public function setAddressBuilding($address_building)
{
$this->address_building = $address_building;
return $this;
}
public function getAddressBuilding()
{
return $this->address_building;
}
public function setAddressBarangay($address_barangay)
{
$this->address_barangay = $address_barangay;
return $this;
}
public function getAddressBarangay()
{
return $this->address_barangay;
}
public function setAddressCity($address_city)
{
$this->address_city = $address_city;
return $this;
}
public function getAddressCity()
{
return $this->address_city;
}
public function setAddressProvince($address_province)
{
$this->address_province = $address_province;
return $this;
}
public function getAddressProvince()
{
return $this->address_province;
}
public function setZipcode($zipcode)
{
$this->zipcode = $zipcode;
return $this;
}
public function getZipcode()
{
return $this->zipcode;
}
public function setMobileNumber($mobile_number)
{
$this->mobile_number = $mobile_number;
return $this;
}
public function getMobileNumber()
{
return $this->mobile_number;
}
public function setEmailAddress($email_address)
{
$this->email_address = $email_address;
return $this;
}
public function getEmailAddress()
{
return $this->email_address;
}
public function setMake($make)
{
$this->make = $make;
return $this;
}
public function getMake()
{
return $this->make;
}
public function setModel($model)
{
$this->model = $model;
return $this;
}
public function getModel()
{
return $this->model;
}
public function setSeries($series)
{
$this->series = $series;
return $this;
}
public function getSeries()
{
return $this->series;
}
public function setColor($color)
{
$this->color = $color;
return $this;
}
public function getColor()
{
return $this->color;
}
public function setPlateNumber($plate_number)
{
$this->plate_number = $plate_number;
return $this;
}
public function getPlateNumber()
{
return $this->plate_number;
}
public function setMvFileNumber($mv_file_number)
{
$this->mv_file_number = $mv_file_number;
return $this;
}
public function getMvFileNumber()
{
return $this->mv_file_number;
}
public function setMotorNumber($motor_number)
{
$this->motor_number = $motor_number;
return $this;
}
public function getMotorNumber()
{
return $this->motor_number;
}
public function setSerialChassis($serial_chassis)
{
$this->serial_chassis = $serial_chassis;
return $this;
}
public function getSerialChassis()
{
return $this->serial_chassis;
}
public function setYearModel($year_model)
{
$this->year_model = $year_model;
return $this;
}
public function getYearModel()
{
return $this->year_model;
}
public function setMvTypeID($mv_type_id)
{
$this->mv_type_id = $mv_type_id;
return $this;
}
public function getMvTypeID()
{
return $this->mv_type_id;
}
public function setBodyType($body_type)
{
$this->body_type = $body_type;
return $this;
}
public function getBodyType()
{
return $this->body_type;
}
public function setLine($line)
{
$this->line = $line;
return $this;
}
public function getLine()
{
return $this->line;
}
public function setPublic($flag_public = true)
{
$this->flag_public = $flag_public;
return $this;
}
public function isPublic()
{
return $this->flag_public;
}
}

View file

@ -0,0 +1,16 @@
<?php
namespace App\Insurance;
use App\Ramcar\NameValue;
class ClientType extends NameValue
{
const CORPORATE = 'C';
const INDIVIDUAL = 'I';
const COLLECTION = [
'C' => 'Corporate',
'I' => 'Individual',
];
}

View file

@ -0,0 +1,20 @@
<?php
namespace App\Insurance;
use App\Ramcar\NameValue;
class LineType extends NameValue
{
const PRIVATE_CAR = 'PCOC';
const PRIVATE_MOTORCYCLE = 'MCOC';
const COMMERCIAL_VEHICLE = 'CCOC';
const PUBLIC_MOTORCYCLE = 'LCOC';
const COLLECTION = [
'PCOC' => 'Private Car',
'MCOC' => 'Private Motorcycle/Motorcycle with Sidecar/Tricycle',
'CCOC' => 'Commercial Vehicle',
'LCOC' => 'Public Motorcycle with Sidecar/Tricycle',
];
}

View file

@ -0,0 +1,163 @@
<?php
namespace App\Service;
use App\Entity\MotorVehicleType;
use App\Insurance\ClientData;
use App\Insurance\LineType;
use App\Insurance\ClientType;
class InsuranceConnector
{
protected $base_url;
protected $username;
protected $password;
protected $token;
public function __construct($base_url, $username, $password, $token)
{
$this->base_url = $base_url;
$this->username = $username;
$this->password = $password;
$this->token = $token;
}
public function processApplication(ClientData $client_data)
{
// transform ClientData into the format needed for insurance application
$client_info = [
'client_type' => $client_data->getClientType(),
'first_name' => $client_data->getFirstName(),
'middle_name' => $client_data->getMiddleName(),
'surname' => $client_data->getSurname(),
'corporate_name' => $client_data->getCorporateName(),
];
$client_contact_info = [
'address_number' => $client_data->getAddressNumber(),
'address_street' => $client_data->getAddressStreet(),
'address_building' => $client_data->getAddressBuilding(),
'address_barangay' => $client_data->getAddressBarangay(),
'address_city' => $client_data->getAddressCity(),
'address_province' => $client_data->getAddressProvince(),
'zipcode' => $client_data->getZipcode(),
'mobile_number' => $client_data->getMobileNumber(),
'email_address' => $client_data->getEmailAddress(),
];
$car_info = [
'make' => $client_data->getMake(),
'model' => $client_data->getModel(),
'series' => $client_data->getSeries(),
'color' => $client_data->getColor(),
'plate_number' => $client_data->getPlateNumber(),
'mv_file_number' => $client_data->getMvFileNumber(),
'motor_number' => $client_data->getMotorNumber(),
'serial_chasis' => $client_data->getSerialChassis(),
'year_model' => $client_data->getYearModel(),
'mv_type_id' => $client_data->getMvTypeID(),
'body_type' => $client_data->getBodyType(),
'is_public' => $client_data->isPublic(),
'line' => $client_data->getLine(),
];
$app_data = [
'client_info' => $client_info,
'client_contact_info' => $client_contact_info,
'car_info' => $car_info,
];
$result = $this->sendApplication($app_data);
$app_result = json_decode($result, true);
// process response received from insurance
$res = $this->checkApplicationResult($app_result);
return $res;
}
protected function sendApplication($body)
{
$body_text = json_encode($body);
// generate token for basic authorization
$token = $this->generateAuthToken($this->username, $this->password);
$res = $this->curlPost('api/v1/ctpl/applications', $body_text, $token);
return $res;
}
protected function checkApplicationResult($app_result)
{
if ($app_result == null)
{
// insurance api returned an empty json
return [];
}
// check if message is set
$message = '';
if (isset($app_result['message']))
$message = $app_result['message'];
// check if id is set
$id = '';
if (isset($app_result['id']))
$id = $app_result['id'];
// check if status is set, meaning, there's an error
$status = '';
if (isset($app_result['status']))
$status = 'error';
else
$status = 'success';
$data = [
'id' => $id
];
$processed_result = [
'status' => $status,
'message' => $message,
'data' => $data,
];
return $processed_result;
}
protected function generateAuthToken($username, $password)
{
$token = base64_encode($username . ':' . $password);
// error_log('token ' . $token);
return $token;
}
protected function curlPost($url, $body, $token)
{
$curl = curl_init();
$options = [
CURLOPT_URL => $this->base_url . '/' . $url,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Basic ' . $token,
],
];
curl_setopt_array($curl, $options);
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
}

View file

@ -0,0 +1,259 @@
<?php
namespace App\Service;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\MotorVehicleType;
use App\Insurance\ClientData;
use App\Insurance\LineType;
use App\Insurance\ClientType;
class InsuranceDataValidator
{
protected $em;
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
public function validateClientData(ClientData$client_data)
{
// client type is required
if (empty($client_data->getClientType()))
{
$error = 'Client type is required.';
return $error;
}
// client type values should either be C or I
if (($client_data->getClientType() !== ClientType::CORPORATE) &&
($client_data->getClientType() !== ClientType::INDIVIDUAL))
{
$error = 'Invalid client type values. Values should only be C for corporate type or I for individual.';
return $error;
}
// first name is required
if (empty($client_data->getFirstName()))
{
$error = 'First name is required.';
return $error;
}
// surname is required
if (empty($client_data->getSurname()))
{
$error = 'Surname is required.';
return $error;
}
// corporate name is required
if (empty($client_data->getCorporateName()))
{
$error = 'Corporate name is required.';
return $error;
}
// TODO: should we check for the format of corporate name if client type is Individual?
// number address is required
if (empty($client_data->getAddressNumber()))
{
$error = 'House number address is required.';
return $error;
}
// barangay address is required
if (empty($client_data->getAddressBarangay()))
{
$error = 'Barangay address is required.';
return $error;
}
// city address is required
if (empty($client_data->getAddressCity()))
{
$error = 'City address is required.';
return $error;
}
// province address is required
if (empty($client_data->getAddressProvince()))
{
$error = 'Province address is required.';
return $error;
}
// zipcode is required
if ($client_data->getZipcode() == 0)
{
$error = 'Zipcode is required.';
return $error;
}
// mobile number is required
if (empty($client_data->getMobileNumber()))
{
$error = 'Mobile number is required.';
return $error;
}
// email address is required
if (empty($client_data->getEmailAddress()))
{
$error = 'Email address is required.';
return $error;
}
// make is required
if (empty($client_data->getMake()))
{
$error = 'Vehicle make is required.';
return $error;
}
// model is required
if (empty($client_data->getMake()))
{
$error = 'Vehicle make is required.';
return $error;
}
// series is required
if (empty($client_data->getSeries()))
{
$error = 'Vehicle series is required.';
return $error;
}
// color is required
if (empty($client_data->getColor()))
{
$error = 'Vehicle color is required.';
return $error;
}
// plate number is required
if (empty($client_data->getPlateNumber()))
{
$error = 'Plate number is required.';
return $error;
}
// TODO: the insurance api doesn't care if the plate number is valid.
// do we still check for valid plate number?
// plate number is correct format
$is_valid_plate = $this->checkPlateNumber($client_data->getPlateNumber());
if (!($is_valid_plate))
{
$error = 'Invalid plate number.';
return $error;
}
// MV file number is required
if (empty($client_data->getMvFileNumber()))
{
$error = 'MV file number is required.';
return $error;
}
// motor number is required
if (empty($client_data->getMotorNumber()))
{
$error = 'Motor number is required.';
return $error;
}
// serial or chassis number is required
if (empty($client_data->getSerialChassis()))
{
$error = 'Serial or chassis number is required.';
return $error;
}
// vehicle year model is required
if ($client_data->getYearModel() == 0)
{
$error = 'Vehicle year model is required.';
return $error;
}
// motor vehicle type id is required
if ($client_data->getMvTypeID() == 0)
{
$error = 'Motor vehicle type is required.';
return $error;
}
// check if it's a valid MV type
$mv_type_id = $client_data->getMvTypeID();
$mv_type = $this->em->getRepository(MotorVehicleType::class)->findBy(['mv_type_id' => $mv_type_id]);
if ($mv_type == null)
{
$error = 'Invalid motor vehicle type.';
return $error;
}
// body type is required
if (empty($client_data->getBodyType()))
{
$error = 'Vehicle body type is required.';
return $error;
}
// line is required
if (empty($client_data->getLine()))
{
$error = 'Line type is required.';
return $error;
}
// check line if valid
if (($client_data->getLine() !== LineType::PRIVATE_CAR) &&
($client_data->getLine() !== LineType::PRIVATE_MOTORCYCLE) &&
($client_data->getLine() !== LineType::COMMERCIAL_VEHICLE) &&
($client_data->getLine() !== LineType::PUBLIC_MOTORCYCLE))
{
$error = 'Invalid line type.';
return $error;
}
// check line type and flag_public combination
// if line type is MCOC/private motorcycle, flag_public should be false
// if line type is LCOC/public motorcycle, flag_public should be true
// TODO: should we check other combinations? Like PCOC/private car and flag_public is true?
if ($client_data->getLine() == LineType::PRIVATE_MOTORCYCLE)
{
if ($client_data->isPublic())
{
$error = 'Line type is invalid for public vehicles.';
return $error;
}
}
if (($client_data->getLine() == LineType::PUBLIC_MOTORCYCLE) ||
($client_data->getLine() == LineType::COMMERCIAL_VEHICLE))
{
if (!($client_data->isPublic()))
{
$error = 'Line type is invalid for private vehicles.';
return $error;
}
}
return null;
}
protected function checkPlateNumber($plate)
{
// check if alphanumeric, max length is 11, no spaces, uppercase
$res = preg_match("/^[A-Z0-9]{1,11}+$/", $plate);
if ($res)
return true;
return false;
}
}

View file

@ -0,0 +1,151 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">Motor Vehicle Types</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-6">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<span class="m-portlet__head-icon">
<i class="la la-industry"></i>
</span>
<h3 class="m-portlet__head-text">
{% if mode == 'update' %}
Edit Motor Vehicle Type
<small>{{ motor_vehicle_type.getLtoMvType() }}</small>
{% else %}
New Motor Vehicle Type
{% endif %}
</h3>
</div>
</div>
</div>
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('motor_vehicle_type_update_submit', {'id': motor_vehicle_type.getId()}) : url('motor_vehicle_type_add_submit') }}">
<div class="m-portlet__body">
<div class="form-group m-form__group row no-border">
<label class="col-lg-3 col-form-label" data-field="mv_type_id">
Motor Vehicle Type ID:
</label>
<div class="col-lg-9">
<input type="text" name="mv_type_id" class="form-control m-input" value="{{ motor_vehicle_type.getMvTypeID() }}">
<div class="form-control-feedback hide" data-field="mv_type_id"></div>
</div>
</div>
<div class="form-group m-form__group row no-border">
<label class="col-lg-3 col-form-label" data-field="lto_mv_type">
LTO Motor Vehicle Type:
</label>
<div class="col-lg-9">
<input type="text" name="lto_mv_type" class="form-control m-input" value="{{ motor_vehicle_type.getLtoMvType() }}">
<div class="form-control-feedback hide" data-field="lto_mv_type"></div>
</div>
</div>
<div class="form-group m-form__group row no-border">
<label class="col-lg-3 col-form-label" data-field="vehicle_type">
Vehicle Type:
</label>
<div class="col-lg-9">
<input type="text" name="vehicle_type" class="form-control m-input" value="{{ motor_vehicle_type.getVehicleType() }}">
<div class="form-control-feedback hide" data-field="vehicle_type"></div>
</div>
</div>
</div>
<div class="m-portlet__foot m-portlet__foot--fit">
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
<div class="row">
<div class="col-lg-12">
<button type="submit" class="btn btn-success">Submit</button>
<a href="{{ url('motor_vehicle_type_list') }}" class="btn btn-secondary">Back</a>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
$("#row-form").submit(function(e) {
var form = $(this);
e.preventDefault();
$.ajax({
method: "POST",
url: form.prop('action'),
data: form.serialize()
}).done(function(response) {
// remove all error classes
removeErrors();
swal({
title: 'Done!',
text: 'Your changes have been saved!',
type: 'success',
onClose: function() {
window.location.href = "{{ url('motor_vehicle_type_list') }}";
}
});
}).fail(function(response) {
if (response.status == 422) {
var errors = response.responseJSON.errors;
var firstfield = false;
// remove all error classes first
removeErrors();
// display errors contextually
$.each(errors, function(field, msg) {
var formfield = $("[name='" + field + "']");
var label = $("label[data-field='" + field + "']");
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
// add error classes to bad fields
formfield.addClass('form-control-danger');
label.addClass('has-danger');
msgbox.html(msg).addClass('has-danger').removeClass('hide');
// check if this field comes first in DOM
var domfield = formfield.get(0);
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
firstfield = domfield;
}
});
// focus on first bad field
firstfield.focus();
// scroll to above that field to make it visible
$('html, body').animate({
scrollTop: $(firstfield).offset().top - 200
}, 100);
}
});
});
// remove all error classes
function removeErrors() {
$(".form-control-danger").removeClass('form-control-danger');
$("[data-field]").removeClass('has-danger');
$(".form-control-feedback[data-field]").addClass('hide');
}
});
</script>
{% endblock %}

View file

@ -0,0 +1,154 @@
{% extends 'base.html.twig' %}
{% block body %}
<!-- BEGIN: Subheader -->
<div class="m-subheader">
<div class="d-flex align-items-center">
<div class="mr-auto">
<h3 class="m-subheader__title">
Motor Vehicle Types
</h3>
</div>
</div>
</div>
<!-- END: Subheader -->
<div class="m-content">
<!--Begin::Section-->
<div class="row">
<div class="col-xl-12">
<div class="m-portlet m-portlet--mobile">
<div class="m-portlet__body">
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
<div class="row align-items-center">
<div class="col-xl-8 order-2 order-xl-1">
<div class="form-group m-form__group row align-items-center">
<div class="col-md-4">
<div class="m-input-icon m-input-icon--left">
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
<span class="m-input-icon__icon m-input-icon__icon--left">
<span><i class="la la-search"></i></span>
</span>
</div>
</div>
</div>
</div>
<div class="col-xl-4 order-1 order-xl-2 m--align-right">
<a href="{{ url('motor_vehicle_type_add_form') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
<span>
<i class="la la-industry"></i>
<span>New Motor Vehicle Type</span>
</span>
</a>
<div class="m-separator m-separator--dashed d-xl-none"></div>
</div>
</div>
</div>
<!--begin: Datatable -->
<div id="data-rows"></div>
<!--end: Datatable -->
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(function() {
var options = {
data: {
type: 'remote',
source: {
read: {
url: '{{ url("motor_vehicle_type_rows") }}',
method: 'POST'
}
},
saveState: {
cookie: false,
webstorage: false
},
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
layout: {
scroll: true
},
columns: [
{
field: 'id',
title: 'ID',
width: 30
},
{
field: 'mv_type_id',
title: 'MV Type ID'
},
{
field: 'lto_mv_type',
title: 'LTO MV Type'
},
{
field: 'vehicle_type',
title: 'Vehicle Type'
},
{
field: 'Actions',
width: 110,
title: 'Actions',
sortable: false,
overflow: 'visible',
template: function (row, index, datatable) {
var actions = '';
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.name + '" title="Edit"><i class="la la-edit"></i></a>';
}
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.name + '" title="Delete"><i class="la la-trash"></i></a>';
}
return actions;
},
}
],
search: {
onEnter: false,
input: $('#data-rows-search'),
delay: 400
}
};
var table = $("#data-rows").mDatatable(options);
$(document).on('click', '.btn-delete', function(e) {
var url = $(this).prop('href');
var id = $(this).data('id');
var btn = $(this);
e.preventDefault();
swal({
title: 'Confirmation',
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
type: 'warning',
showCancelButton: true
}).then((result) => {
if (result.value) {
$.ajax({
method: "DELETE",
url: url
}).done(function(response) {
table.row(btn.parents('tr')).remove();
table.reload();
});
}
});
});
});
</script>
{% endblock %}