diff --git a/catalyst/api-bundle/Access/Generator.php b/catalyst/api-bundle/Access/Generator.php deleted file mode 100644 index 20d60b74..00000000 --- a/catalyst/api-bundle/Access/Generator.php +++ /dev/null @@ -1,9 +0,0 @@ -setName('api:test-connector-all') - ->setDescription('Test API connector with all commands.') - ->setHelp('Test API Connector with all commands.') - ->addArgument('protocol', InputArgument::REQUIRED, 'protocol') - ->addArgument('server', InputArgument::REQUIRED, 'server') - ->addArgument('api_key', InputArgument::REQUIRED, 'api_key') - ->addArgument('secret_key', InputArgument::REQUIRED, 'secret_key'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $protocol = $input->getArgument('protocol'); - $server = $input->getArgument('server'); - $api_key = $input->getArgument('api_key'); - $secret_key = $input->getArgument('secret_key'); - - // api client - $api = new APIClient($server, $api_key, $secret_key); - $api->setProtocol($protocol); - - // test - $api->get('/capi/test'); - - // TODO: shift this out of the bundle, since it's project specific - - // warranty register - $serial = 'AJ34LJADR12134LKJL5'; - $plate_num = 'XEN918'; - $params = [ - 'serial' => $serial, - 'plate_number' => $plate_num, - 'warranty_class' => 'private', - 'sku' => 'WMEB24CB-CPN00-LX', - 'date_purchase' => '20181001', - 'date_expire' => '20191001', - 'first_name' => 'First', - 'last_name' => 'Last', - 'mobile_number' => '09231234567', - ]; - //$api->post('/capi/warranties', $params); - - // get all warranties - $params = [ - 'order' => 'DESC', - 'limit' => '5', - 'start' => '1', - ]; - - //$api->get('/capi/warranties', $params); - - - // warranty find - //$api->get('/capi/warranties/' . $serial); - - // warranty update - $id = 86811; - $params = [ - 'serial' => $serial, - 'plate_number' => $plate_num, - 'warranty_class' => 'private', - 'sku' => 'WMEB24CB-CPN00-LX', - 'date_purchase' => '20181001', - 'date_expire' => '20191001', - 'first_name' => 'First', - 'last_name' => 'Last', - 'mobile_number' => '123456789111', - ]; - //$api->post('/capi/warranties/'. $id, $params); - - // warranty set privacy policy - $id = 86811; - $policy_id = 2; - $params = [ - 'privacy_policy_id' => $policy_id, - ]; - //$api->post('/capi/warranties/' . $id .'/privacypolicy', $params); - - // warranty claim - $id = 86811; - $serial = 'AJ34LJADR12134LKJL5'; - $params = [ - 'serial' => $serial, - ]; - //$api->post('/capi/warranties/' . $id . '/claim', $params); - - // warranty cancel - $id = 86811; - //$api->get('/capi/warranties/' . $id . '/cancel'); - - // plate warranty - //$api->get('/capi/plates/' . $plate_num . '/warranties'); - - // warranty delete - $id = 86811; - //$api->post('/capi/warranties/' . $id . '/delete'); - - // battery - //$api->get('/capi/battery_brands'); - //$api->get('/capi/battery_sizes'); - //$api->get('/capi/batteries'); - - // vehicle - //$api->get('/capi/vehicle_manufacturers'); - //$api->get('/capi/vehicles'); - - // privacy policy - $privacy_policy_id = 2; - //$api->get('/capi/privacy_policy/' . $privacy_policy_id ); - - // register new customer - $params = [ - 'first_name' => 'Krispups', - 'last_name' =>'Porzindog', - 'mobile_number' => '9221111111', - 'v_make_id' => '22241', - 'v_model_year' => '2018', - 'v_plate_number' => 'KPP1234', - 'v_color' => 'White', - 'v_condition' => 'new', - 'v_fuel_type' => 'gas', - ]; - //$api->post('/capi/quick_registration', $params); - - // get warranties given list of serial numbers - $serial_list = [ - 'AJ34LJADR12134LKJM4', - 'AJ34LJADR12134LKJL5', - 'test', - ]; - - $params = [ - 'serial_list' => $serial_list, - ]; - - $api->post('/capi/warranties_list', $params); - } -} diff --git a/catalyst/api-bundle/Command/TestCommand.php b/catalyst/api-bundle/Command/TestCommand.php deleted file mode 100644 index 3d03ae0d..00000000 --- a/catalyst/api-bundle/Command/TestCommand.php +++ /dev/null @@ -1,104 +0,0 @@ -setName('api:test-connector') - ->setDescription('Test API connector.') - ->setHelp('Test API Connector.') - ->addArgument('protocol', InputArgument::REQUIRED, 'protocol') - ->addArgument('server', InputArgument::REQUIRED, 'server') - ->addArgument('api_key', InputArgument::REQUIRED, 'api_key') - ->addArgument('secret_key', InputArgument::REQUIRED, 'secret_key'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $protocol = $input->getArgument('protocol'); - $server = $input->getArgument('server'); - $api_key = $input->getArgument('api_key'); - $secret_key = $input->getArgument('secret_key'); - - // api client - $api = new APIClient($server, $api_key, $secret_key); - $api->setProtocol($protocol); - - // test - $api->get('/capi/test'); - - // TODO: shift this out of the bundle, since it's project specific - - - // warranty register - $serial = 'AJ34LJADR12134LKJL5'; - $plate_num = 'XEN918'; - $params = [ - 'serial' => $serial, - 'plate_number' => $plate_num, - 'warranty_class' => 'private', - 'sku' => 'WMEB24CB-CPN00-LX', - 'date_purchase' => '20181001', - 'date_expire' => '20191001', - 'first_name' => 'First', - 'last_name' => 'Last', - 'mobile_number' => '12345678910', - ]; - $api->post('/capi/warranties', $params); - - // get all warranties - $api->get('/capi/warranties'); - - - /* - // warranty find - $api->get('/capi/warranties/' . $serial); - */ - - // warranty claim - $id = 86811; - $serial = 'AJ34LJADR12134LKJL'; - $params = [ - 'serial' => $serial, - ]; - $api->post('/capi/warranties/' . $id . '/claim', $params); - - // add battery - $sku = 'WZMB31QT-CPP00-S'; - $brand_id = '4'; - $size_id = '1'; - $params = [ - 'sku' => $sku, - 'brand_id' => $brand_id, - 'size_id' => $size_id, - ]; - $api->post('/capi/batteries', $params); - - /* - - // plate warranty - $api->get('/capi/plates/' . $plate_num . '/warranties'); - - // battery - $api->get('/capi/battery_brands'); - $api->get('/capi/battery_sizes'); - $api->get('/capi/batteries'); - - // vehicle - // $api->get('/capi/vehicle_manufacturers'); - // $api->get('/capi/vehicles'); - */ - } -} diff --git a/catalyst/api-bundle/Command/UserCreateCommand.php b/catalyst/api-bundle/Command/UserCreateCommand.php deleted file mode 100644 index cea9682c..00000000 --- a/catalyst/api-bundle/Command/UserCreateCommand.php +++ /dev/null @@ -1,49 +0,0 @@ -em = $em; - - parent::__construct(); - } - - protected function configure() - { - $this->setName('api:user-create') - ->setDescription('Create new API user.') - ->setHelp('Creates new API user and saves to database.') - ->addArgument('name', InputArgument::REQUIRED, 'name'); - } - - protected function execute(InputInterface $input, OutputInterface $output) - { - $name = $input->getArgument('name'); - - $user = new User(); - $user->setName($name); - - $this->em->persist($user); - $this->em->flush(); - - $output->write('API Key - ' . $user->getAPIKey() . "\n"); - $output->write('Secret Key - ' . $user->getSecretKey() . "\n"); - } - - -} diff --git a/catalyst/api-bundle/Connector/Client.php b/catalyst/api-bundle/Connector/Client.php deleted file mode 100644 index 904b7cad..00000000 --- a/catalyst/api-bundle/Connector/Client.php +++ /dev/null @@ -1,151 +0,0 @@ -protocol = 'https'; - $this->port = null; - - $this->server = $server; - $this->api_key = $api_key; - $this->secret_key = $secret_key; - $this->curl = curl_init(); - } - - public function __destruct() - { - curl_close($this->curl); - } - - public function setProtocol($protocol) - { - if ($protocol != 'http' && $protocol != 'https') - return $this; - - $this->protocol = $protocol; - return $this; - } - - protected function getDateString() - { - $date = new DateTime(); - return $date->format(self::DATE_FORMAT); - } - - public function get($url, $params = []) - { - curl_reset($this->curl); - - $date_string = $this->getDateString(); - $headers = $this->generateHeaders('GET', $url, $date_string); - - // build query string - if (count($params) > 0) - $query_string = '?' . http_build_query($params); - else - $query_string = ''; - - // build url - if ($this->port == null) - $full_url = $this->protocol . '://' . $this->server . $url . $query_string; - else - $full_url = $this->protocol . '://' . $this->server . ':' . $this->port . $url . $query_string; - - error_log($full_url); - - // curl - // curl_setopt($this->curl, CURLOPT_VERBOSE, true); - curl_setopt($this->curl, CURLOPT_URL, $full_url); - curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); - curl_setopt($this->curl, CURLOPT_USERAGENT, self::USER_AGENT); - curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($this->curl, CURLOPT_TIMEOUT, 0); - - $res = curl_exec($this->curl); - error_log($res); - } - - public function post($url, $params = []) - { - curl_reset($this->curl); - - $date_string = $this->getDateString(); - $headers = $this->generateHeaders('POST', $url, $date_string); - - // build query string - $query_string = http_build_query($params); - - // build url - if ($this->port == null) - $full_url = $this->protocol . '://' . $this->server . $url; - else - $full_url = $this->protocol . '://' . $this->server . ':' . $this->port . $url; - - error_log($full_url); - - // curl - // curl_setopt($this->curl, CURLOPT_VERBOSE, true); - curl_setopt($this->curl, CURLOPT_URL, $full_url); - curl_setopt($this->curl, CURLOPT_POST, true); - curl_setopt($this->curl, CURLOPT_POSTFIELDS, $query_string); - curl_setopt($this->curl, CURLOPT_HTTPHEADER, $headers); - curl_setopt($this->curl, CURLOPT_USERAGENT, self::USER_AGENT); - curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true); - curl_setopt($this->curl, CURLOPT_TIMEOUT, 0); - - $res = curl_exec($this->curl); - error_log($res); - } - - protected function generateSignature($method, $url, $date_string) - { - $creds = [ - $method, - $url, - $date_string, - $this->secret_key, - ]; - $sig_source = implode('|', $creds); - - error_log('SIG SOURCE - ' . $sig_source); - - $raw_sig = hash_hmac('sha1', $sig_source, $this->secret_key, true); - $enc_sig = base64_encode($raw_sig); - - return $enc_sig; - } - - protected function generateHeaders($method, $url, $date_string) - { - $sig = $this->generateSignature($method, $url, $date_string); - - $headers = [ - self::HEADER_API_KEY . ': ' . $this->api_key, - self::HEADER_SIGNATURE . ': ' . $sig, - self::HEADER_DATE . ': ' . $date_string, - ]; - - return $headers; - } -} diff --git a/catalyst/api-bundle/Controller/APIController.php b/catalyst/api-bundle/Controller/APIController.php deleted file mode 100644 index 74c63d3c..00000000 --- a/catalyst/api-bundle/Controller/APIController.php +++ /dev/null @@ -1,42 +0,0 @@ -getMethod() == 'GET') - { - $check = $req->query->get($param); - if (empty($check)) - $missing[] = $param; - } - // else if ($req->getMethod() == 'POST') - else - { - $check = $req->request->get($param); - //if (empty($check)) - if (!isset($check)) - $missing[] = $param; - } - } - - // check missing parameters - if (count($missing) > 0) - { - $miss_string = implode(', ', $missing); - return 'Missing required parameter(s): ' . $miss_string; - } - - return false; - } -} diff --git a/catalyst/api-bundle/DataFixtures/APIRoleFixtures.php b/catalyst/api-bundle/DataFixtures/APIRoleFixtures.php deleted file mode 100644 index 00b4c3e0..00000000 --- a/catalyst/api-bundle/DataFixtures/APIRoleFixtures.php +++ /dev/null @@ -1,20 +0,0 @@ -setID(Role::SUPER_ADMIN) - ->setName('Super Administrator'); - $em->persist($role); - $em->flush(); - } -} diff --git a/catalyst/api-bundle/Entity/Role.php b/catalyst/api-bundle/Entity/Role.php deleted file mode 100644 index 89637045..00000000 --- a/catalyst/api-bundle/Entity/Role.php +++ /dev/null @@ -1,28 +0,0 @@ -setAPIKey($this->generateAPIKey()) - ->setSecretKey($this->generateSecretKey()); - - // set date created - $this->date_create = new DateTime(); - $this->metadata = []; - } - - public function getID() - { - return $this->id; - } - - public function setAPIKey($api_key) - { - $this->api_key = $api_key; - return $this; - } - - public function getAPIKey() - { - return $this->api_key; - } - - public function setSecretKey($key) - { - $this->secret_key = $key; - return $this; - } - - public function getSecretKey() - { - return $this->secret_key; - } - - public function setName($name) - { - $this->name = $name; - return $this; - } - - public function getName() - { - return $this->name; - } - - public function getDateCreate() - { - return $this->date_create; - } - - public function getPassword() - { - // we don't need this for API - return 'notneeded'; - } - - public function getSalt() - { - return null; - } - - public function getUsername() - { - // since it's an api, the api key IS the username - return $this->api_key; - } - - public function eraseCredentials() - { - return; - } - - public function generateAPIKey() - { - return $this->generateKey('api'); - } - - public function generateSecretKey() - { - return $this->generateKey('secret'); - } - - public function setMetadata($meta) - { - $this->metadata = $meta; - return $this; - } - - public function getMetadata() - { - if ($this->metadata == null) - return []; - - return $this->metadata; - } - - protected function generateKey($prefix = '') - { - return md5(uniqid($prefix, true)); - } - - public function setRider($rider) - { - $this->rider = $rider; - return $this; - } - - public function getRider() - { - return $this->rider; - } -} - diff --git a/catalyst/api-bundle/Response/APIResponse.php b/catalyst/api-bundle/Response/APIResponse.php deleted file mode 100644 index baa10603..00000000 --- a/catalyst/api-bundle/Response/APIResponse.php +++ /dev/null @@ -1,20 +0,0 @@ - (bool) $success, - 'message' => (string) $message, - 'data' => $data, - ]; - parent::__construct($data, $status, $headers); - } -} - - diff --git a/catalyst/api-bundle/Security/APIKeyAuthenticator.php b/catalyst/api-bundle/Security/APIKeyAuthenticator.php deleted file mode 100644 index 27d1eaf1..00000000 --- a/catalyst/api-bundle/Security/APIKeyAuthenticator.php +++ /dev/null @@ -1,160 +0,0 @@ -em = $em; - } - - protected function validateSignature($creds, $secret_key) - { - $elements = [ - $creds['method'], - $creds['uri'], - $creds['date'], - $secret_key, - ]; - $sig_source = implode('|', $elements); - - error_log($sig_source); - - // generate signature - $raw_sig = hash_hmac('sha1', $sig_source, $secret_key, true); - $enc_sig = base64_encode($raw_sig); - - error_log($enc_sig); - - if ($enc_sig != trim($creds['signature'])) - throw new CustomUserMessageAuthenticationException('Invalid signature.'); - - } - - public function createToken(Request $req, $provider_key) - { - // api key header - $api_key = $req->headers->get(self::HEADER_API_KEY); - if ($api_key == null) - throw new BadCredentialsException('No API key sent.'); - - // check date from headers - $hdate_string = $req->headers->get(self::HEADER_DATE); - if ($hdate_string == null) - throw new BadCredentialsException('No date specified.'); - - $hdate = DateTime::createFromFormat(self::DATE_FORMAT, $hdate_string); - if ($hdate == null) - throw new BadCredentialsException('Invalid date specified.'); - - // get number of seconds difference - $date_now = new DateTime(); - $date_diff = abs($date_now->getTimestamp() - $hdate->getTimestamp()); - - // time difference is too much - if ($date_diff > self::TIME_LIMIT) - throw new BadCredentialsException('Clock synchronization error.'); - - // signature header - $sig = $req->headers->get(self::HEADER_SIGNATURE); - if ($sig == null) - throw new BadCredentialsException('No signature sent.'); - - // credentials - $creds = [ - 'api_key' => $api_key, - 'date' => $hdate_string, - 'signature' => $sig, - 'method' => $req->getRealMethod(), - 'uri' => $req->getPathInfo(), - ]; - - return new PreAuthenticatedToken( - 'anonymous', - $creds, - $provider_key - ); - } - - public function supportsToken(TokenInterface $token, $provider_key) - { - return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $provider_key; - } - - public function authenticateToken(TokenInterface $token, UserProviderInterface $user_provider, $provider_key) - { - if (!$user_provider instanceof APIKeyUserProvider) - { - throw new \InvalidArgumentException( - sprintf( - 'The user provider must be an instance of APIKeyUserProvider (%s was given).', - get_class($user_provider) - ) - ); - } - - $creds = $token->getCredentials(); - $api_key = $creds['api_key']; - $user = $user_provider->getUserByAPIKey($api_key); - - // check if api key is valid - if (!$user) - throw new CustomUserMessageAuthenticationException('Invalid API Key'); - - // check if signature is valid - $this->validateSignature($creds, $user->getSecretKey()); - - // check if user is enabled - if (!$user->isEnabled()) - { - throw new CustomUserMessageAuthenticationException('User account is disabled'); - } - - // $user = $user_provider->loadUserByUsername($username); - - return new PreAuthenticatedToken( - $user, - $api_key, - $provider_key, - $user->getRoles() - ); - } - - public function onAuthenticationFailure(Request $req, AuthenticationException $exception) - { - $data = [ - 'success' => false, - 'error' => [ - 'message' => $exception->getMessage(), - ], - ]; - return new JsonResponse($data, 401); - } -} diff --git a/catalyst/api-bundle/Security/APIKeyUserProvider.php b/catalyst/api-bundle/Security/APIKeyUserProvider.php deleted file mode 100644 index 742e8d63..00000000 --- a/catalyst/api-bundle/Security/APIKeyUserProvider.php +++ /dev/null @@ -1,62 +0,0 @@ -em = $em; - } - - public function getUserByAPIKey($api_key) - { - $user = $this->em->getRepository(User::class)->findOneBy(array('api_key' => $api_key)); - - return $user; - } - - public function getUsernameForAPIKey($apiKey) - { - // Look up the username based on the token in the database, via - // an API call, or do something entirely different - $username = 'test'; - - return $username; - } - - public function loadUserByUsername($username) - { - return new User( - $username, - null, - // the roles for the user - you may choose to determine - // these dynamically somehow based on the user - array('ROLE_API') - ); - } - - public function refreshUser(UserInterface $user) - { - // this is used for storing authentication in the session - // but in this example, the token is sent in each request, - // so authentication can be stateless. Throwing this exception - // is proper to make things stateless - throw new UnsupportedUserException(); - } - - public function supportsClass($class) - { - return User::class === $class; - } -} diff --git a/catalyst/api-bundle/Service/AccessDeniedHandler.php b/catalyst/api-bundle/Service/AccessDeniedHandler.php deleted file mode 100644 index 7cf5be90..00000000 --- a/catalyst/api-bundle/Service/AccessDeniedHandler.php +++ /dev/null @@ -1,18 +0,0 @@ -getMessage(); - - return new Response($content, 403); - } -} diff --git a/composer.json b/composer.json index 5ade4a34..27e0b4e4 100644 --- a/composer.json +++ b/composer.json @@ -4,20 +4,25 @@ "repositories": [ { "type": "vcs", - "url": "git@gitlab.com:jankstudio-catalyst/auth-bundle.git" + "url": "https://github.com/jankstudio/doctrine2-spatial.git" }, { "type": "vcs", - "url": "git@gitlab.com:jankstudio-catalyst/menu-bundle.git" + "url": "git@gitlab.com:jankstudio1/catalyst-2/api-bundle.git" + }, + { + "type": "vcs", + "url": "git@gitlab.com:jankstudio1/catalyst-2/auth-bundle.git" + }, + { + "type": "vcs", + "url": "git@gitlab.com:jankstudio1/catalyst-2/menu-bundle.git" } ], "require": { "php": "^7.1.3", "ext-iconv": "*", - "catalyst/auth-bundle": "dev-master", - "catalyst/menu-bundle": "dev-master", "composer/package-versions-deprecated": "1.11.99.4", - "creof/doctrine2-spatial": "^1.2", "data-dog/audit-bundle": "^0.1.10", "doctrine/common": "^2", "doctrine/doctrine-bundle": "^2", @@ -25,7 +30,11 @@ "doctrine/orm": "^2", "edwinhoksberg/php-fcm": "^1.0", "guzzlehttp/guzzle": "^6.3", - "hashids/hashids": "^4.1", + "hashids/hashids": "^4.1", + "jankstudio/catalyst-api-bundle": "dev-master", + "jankstudio/catalyst-auth-bundle": "dev-master", + "jankstudio/catalyst-menu-bundle": "dev-master", + "jankstudio/doctrine-spatial": "dev-master", "microsoft/azure-storage-blob": "^1.5", "predis/predis": "^1.1", "sensio/framework-extra-bundle": "^5.1", @@ -65,8 +74,7 @@ }, "autoload": { "psr-4": { - "App\\": "src/", - "Catalyst\\APIBundle\\": "catalyst/api-bundle/" + "App\\": "src/" } }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index e34b61f9..5c25c204 100644 --- a/composer.lock +++ b/composer.lock @@ -4,90 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5b5acb546514b41ab347ef37b85425c9", + "content-hash": "6e52016d46fa06387dbd9db37e6feb93", "packages": [ - { - "name": "catalyst/auth-bundle", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://gitlab.com/jankstudio-catalyst/auth-bundle.git", - "reference": "803e38f58907513c8df30c31d51303b68c645a17" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.com/api/v4/projects/jankstudio-catalyst%2Fauth-bundle/repository/archive.zip?sha=803e38f58907513c8df30c31d51303b68c645a17", - "reference": "803e38f58907513c8df30c31d51303b68c645a17", - "shasum": "" - }, - "require": { - "doctrine/dbal": "^2.5.12", - "doctrine/doctrine-cache-bundle": "~1.2", - "php": "^7.0", - "symfony/framework-bundle": "~4.0" - }, - "default-branch": true, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Catalyst\\AuthBundle\\": "" - } - }, - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kendrick Chan", - "email": "kc@jankstudio.com" - } - ], - "support": { - "issues": "https://gitlab.com/api/v4/projects/12709261/issues" - }, - "time": "2019-07-01T09:45:41+00:00" - }, - { - "name": "catalyst/menu-bundle", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://gitlab.com/jankstudio-catalyst/menu-bundle.git", - "reference": "2cf9a05862fcc6f956da4b095962915e07f14f64" - }, - "dist": { - "type": "zip", - "url": "https://gitlab.com/api/v4/projects/jankstudio-catalyst%2Fmenu-bundle/repository/archive.zip?sha=2cf9a05862fcc6f956da4b095962915e07f14f64", - "reference": "2cf9a05862fcc6f956da4b095962915e07f14f64", - "shasum": "" - }, - "require": { - "doctrine/dbal": "^2.5.12", - "doctrine/doctrine-cache-bundle": "~1.2", - "php": "^7.0", - "symfony/framework-bundle": "~4.0" - }, - "default-branch": true, - "type": "symfony-bundle", - "autoload": { - "psr-4": { - "Catalyst\\MenuBundle\\": "" - } - }, - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kendrick Chan", - "email": "kc@jankstudio.com" - } - ], - "support": { - "issues": "https://gitlab.com/api/v4/projects/12712039/issues" - }, - "time": "2019-06-14T09:43:30+00:00" - }, { "name": "composer/package-versions-deprecated", "version": "1.11.99.4", @@ -161,67 +79,6 @@ ], "time": "2021-09-13T08:41:34+00:00" }, - { - "name": "creof/doctrine2-spatial", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/creof/doctrine2-spatial.git", - "reference": "58ea5fae1c1b450ee08d7dac25cd9e8f5e6fdebd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/creof/doctrine2-spatial/zipball/58ea5fae1c1b450ee08d7dac25cd9e8f5e6fdebd", - "reference": "58ea5fae1c1b450ee08d7dac25cd9e8f5e6fdebd", - "shasum": "" - }, - "require": { - "creof/geo-parser": "~2.0", - "creof/wkb-parser": "~2.0", - "creof/wkt-parser": "~2.0", - "doctrine/orm": ">=2.3" - }, - "require-dev": { - "phpunit/phpcov": "*", - "phpunit/phpunit": "<5.0", - "satooshi/php-coveralls": "~1.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "CrEOF\\Spatial": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Derek Lambert", - "email": "dlambert@dereklambert.com" - } - ], - "description": "Doctrine2 multi-platform support for spatial types and functions", - "keywords": [ - "database", - "dbal", - "geography", - "geometry", - "gis", - "mysql", - "opengis", - "orm", - "postgis", - "postgresql", - "spatial" - ], - "support": { - "issues": "https://github.com/creof/doctrine2-spatial/issues", - "source": "https://github.com/creof/doctrine2-spatial/tree/master" - }, - "time": "2017-07-13T16:48:25+00:00" - }, { "name": "creof/geo-parser", "version": "2.2.1", @@ -1069,102 +926,6 @@ ], "time": "2021-05-06T19:21:22+00:00" }, - { - "name": "doctrine/doctrine-cache-bundle", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/DoctrineCacheBundle.git", - "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/6bee2f9b339847e8a984427353670bad4e7bdccb", - "reference": "6bee2f9b339847e8a984427353670bad4e7bdccb", - "shasum": "" - }, - "require": { - "doctrine/cache": "^1.4.2", - "doctrine/inflector": "^1.0", - "php": "^7.1", - "symfony/doctrine-bridge": "^3.4|^4.0" - }, - "require-dev": { - "instaclick/coding-standard": "~1.1", - "instaclick/object-calisthenics-sniffs": "dev-master", - "instaclick/symfony2-coding-standard": "dev-remaster", - "phpunit/phpunit": "^7.0", - "predis/predis": "~0.8", - "satooshi/php-coveralls": "^1.0", - "squizlabs/php_codesniffer": "~1.5", - "symfony/console": "^3.4|^4.0", - "symfony/finder": "^3.4|^4.0", - "symfony/framework-bundle": "^3.4|^4.0", - "symfony/phpunit-bridge": "^3.4|^4.0", - "symfony/security-acl": "^2.8", - "symfony/validator": "^3.4|^4.0", - "symfony/yaml": "^3.4|^4.0" - }, - "suggest": { - "symfony/security-acl": "For using this bundle to cache ACLs" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Bundle\\DoctrineCacheBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Fabio B. Silva", - "email": "fabio.bat.silva@gmail.com" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@hotmail.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - }, - { - "name": "Doctrine Project", - "homepage": "http://www.doctrine-project.org/" - } - ], - "description": "Symfony Bundle for Doctrine Cache", - "homepage": "https://www.doctrine-project.org", - "keywords": [ - "cache", - "caching" - ], - "support": { - "issues": "https://github.com/doctrine/DoctrineCacheBundle/issues", - "source": "https://github.com/doctrine/DoctrineCacheBundle/tree/1.4.0" - }, - "abandoned": true, - "time": "2019-11-29T11:22:01+00:00" - }, { "name": "doctrine/doctrine-migrations-bundle", "version": "2.2.3", @@ -2480,6 +2241,177 @@ }, "time": "2020-11-26T19:24:33+00:00" }, + { + "name": "jankstudio/catalyst-api-bundle", + "version": "dev-master", + "source": { + "type": "git", + "url": "git@gitlab.com:jankstudio1/catalyst-2/api-bundle.git", + "reference": "042d16534265adf81ae67c803b1ae8f0a94f3bb6" + }, + "dist": { + "type": "zip", + "url": "https://gitlab.com/api/v4/projects/jankstudio1%2Fcatalyst-2%2Fapi-bundle/repository/archive.zip?sha=042d16534265adf81ae67c803b1ae8f0a94f3bb6", + "reference": "042d16534265adf81ae67c803b1ae8f0a94f3bb6", + "shasum": "" + }, + "default-branch": true, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Catalyst\\ApiBundle\\": "" + } + }, + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Kendrick Chan", + "email": "kc@jankstudio.com" + } + ], + "support": { + "source": "https://gitlab.com/jankstudio1/catalyst-2/api-bundle/-/tree/master", + "issues": "https://gitlab.com/jankstudio1/catalyst-2/api-bundle/-/issues" + }, + "time": "2022-10-09T14:02:41+08:00" + }, + { + "name": "jankstudio/catalyst-auth-bundle", + "version": "dev-master", + "source": { + "type": "git", + "url": "git@gitlab.com:jankstudio1/catalyst-2/auth-bundle.git", + "reference": "50f18ac6d4f6198b7bfe888487e0a4009193403e" + }, + "dist": { + "type": "zip", + "url": "https://gitlab.com/api/v4/projects/jankstudio1%2Fcatalyst-2%2Fauth-bundle/repository/archive.zip?sha=50f18ac6d4f6198b7bfe888487e0a4009193403e", + "reference": "50f18ac6d4f6198b7bfe888487e0a4009193403e", + "shasum": "" + }, + "require": { + "symfony/cache": "^5.0" + }, + "default-branch": true, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Catalyst\\AuthBundle\\": "" + } + }, + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Kendrick Chan", + "email": "kc@jankstudio.com" + } + ], + "support": { + "source": "https://gitlab.com/jankstudio1/catalyst-2/auth-bundle/-/tree/master", + "issues": "https://gitlab.com/jankstudio1/catalyst-2/auth-bundle/-/issues" + }, + "time": "2022-01-19T16:21:57+08:00" + }, + { + "name": "jankstudio/catalyst-menu-bundle", + "version": "dev-master", + "source": { + "type": "git", + "url": "git@gitlab.com:jankstudio1/catalyst-2/menu-bundle.git", + "reference": "9cddeecbbbb7d61868e1b319d9abc8eda4f34ab0" + }, + "dist": { + "type": "zip", + "url": "https://gitlab.com/api/v4/projects/jankstudio1%2Fcatalyst-2%2Fmenu-bundle/repository/archive.zip?sha=9cddeecbbbb7d61868e1b319d9abc8eda4f34ab0", + "reference": "9cddeecbbbb7d61868e1b319d9abc8eda4f34ab0", + "shasum": "" + }, + "default-branch": true, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Catalyst\\MenuBundle\\": "" + } + }, + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Kendrick Chan", + "email": "kc@jankstudio.com" + } + ], + "support": { + "source": "https://gitlab.com/jankstudio1/catalyst-2/menu-bundle/-/tree/master", + "issues": "https://gitlab.com/jankstudio1/catalyst-2/menu-bundle/-/issues" + }, + "time": "2022-10-07T11:55:32+08:00" + }, + { + "name": "jankstudio/doctrine-spatial", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/jankstudio/doctrine-spatial.git", + "reference": "32b0fd126f3d81758ee74363535a44ccb3adae19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jankstudio/doctrine-spatial/zipball/32b0fd126f3d81758ee74363535a44ccb3adae19", + "reference": "32b0fd126f3d81758ee74363535a44ccb3adae19", + "shasum": "" + }, + "require": { + "creof/geo-parser": "~2.0", + "creof/wkb-parser": "~2.0", + "creof/wkt-parser": "~2.0", + "doctrine/orm": ">=2.3" + }, + "require-dev": { + "phpunit/phpcov": "*", + "phpunit/phpunit": "<5.0", + "satooshi/php-coveralls": "~1.0" + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-0": { + "CrEOF\\Spatial": "lib/" + } + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Derek Lambert", + "email": "dlambert@dereklambert.com" + } + ], + "description": "Doctrine2 multi-platform support for spatial types and functions", + "keywords": [ + "database", + "dbal", + "geography", + "geometry", + "gis", + "mysql", + "opengis", + "orm", + "postgis", + "postgresql", + "spatial" + ], + "support": { + "source": "https://github.com/jankstudio/doctrine-spatial/tree/master" + }, + "time": "2021-08-23T01:41:57+00:00" + }, { "name": "laminas/laminas-code", "version": "3.4.1", @@ -8021,8 +7953,10 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "catalyst/auth-bundle": 20, - "catalyst/menu-bundle": 20 + "jankstudio/catalyst-api-bundle": 20, + "jankstudio/catalyst-auth-bundle": 20, + "jankstudio/catalyst-menu-bundle": 20, + "jankstudio/doctrine-spatial": 20 }, "prefer-stable": false, "prefer-lowest": false, @@ -8031,5 +7965,5 @@ "ext-iconv": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } diff --git a/config/bundles.php b/config/bundles.php index 79841817..cfbe640b 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -2,7 +2,6 @@ return [ Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], - Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], @@ -11,8 +10,8 @@ return [ Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], - Catalyst\APIBundle\CatalystAPIBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + Catalyst\ApiBundle\CatalystApiBundle::class => ['all' => true], Catalyst\AuthBundle\CatalystAuthBundle::class => ['all' => true], Catalyst\MenuBundle\CatalystMenuBundle::class => ['all' => true], - Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], ]; diff --git a/config/cmb.services.yaml b/config/cmb.services.yaml index 5f24e525..5f7feb52 100644 --- a/config/cmb.services.yaml +++ b/config/cmb.services.yaml @@ -42,20 +42,6 @@ services: $cache_dir: "%kernel.cache_dir%" $config_dir: "%kernel.root_dir%/../config" - Catalyst\AuthBundle\Service\ACLGenerator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%app_acl_file%" - - Catalyst\AuthBundle\Service\ACLVoter: - arguments: - $user_class: "App\\Entity\\User" - tags: ['security.voter'] - - Catalyst\AuthBundle\Service\UserChecker: - App\Service\FileUploader: arguments: $target_dir: '%image_upload_directory%' @@ -114,50 +100,6 @@ services: arguments: $redis_client: "@App\\Service\\RedisClientProvider" - Catalyst\APIBundle\Security\APIKeyUserProvider: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Security\APIKeyAuthenticator: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Command\UserCreateCommand: - arguments: - $em: "@doctrine.orm.entity_manager" - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestCommand: - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestAPICommand: - tags: ['console.command'] - - Catalyst\APIBundle\Access\Voter: - arguments: - $acl_gen: "@Catalyst\\APIBundle\\Access\\Generator" - $user_class: "Catalyst\\APIBundle\\Entity\\User" - tags: ['security.voter'] - - Catalyst\APIBundle\Access\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%api_acl_file%" - - Catalyst\MenuBundle\Menu\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - - Catalyst\MenuBundle\Listener\MenuAnnotationListener: - arguments: - $menu_name: "main_menu" - tags: - - { name: kernel.event_listener, event: kernel.controller, method: onKernelController } - # invoice generator App\Service\InvoiceGenerator\CMBInvoiceGenerator: ~ diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml new file mode 100644 index 00000000..4a13e9e4 --- /dev/null +++ b/config/packages/catalyst_auth.yaml @@ -0,0 +1,879 @@ +catalyst_auth: + main: + user_entity: "App\\Entity\\User" + acl_data: + - id: dashboard + label: Dashboard Access + acls: + - id: dashboard.menu + label: Menu + - id: user + label: User Access + acls: + - id: user.menu + label: Menu + - id: user.list + label: List + - id: user.add + label: Add + - id: user.update + label: Update + - id: user.delete + label: Delete + - id: user.role.sadmin + label: Super Admin Role + - id: user.profile + label: User Profile + - id: role + label: Role Access + acls: + - id: role.menu + label: Menu + - id: role.list + label: List + - id: role.add + label: Add + - id: role.update + label: Update + - id: role.delete + label: Delete + - id: apiuser + label: API User Access + acls: + - id: apiuser.menu + label: Menu + - id: apiuser.list + label: List + - id: apiuser.add + label: Add + - id: apiuser.update + label: Update + - id: apiuser.delete + label: Delete + - id: apirole + label: API Role Access + acls: + - id: apirole.menu + label: Menu + - id: apirole.list + label: List + - id: apirole.add + label: Add + - id: apirole.update + label: Update + - id: apirole.delete + label: Delete + - id: logistics + label: Logistics Access + acls: + - id: logistics.menu + label: Menu + - id: battery + label: Battery Access + acls: + - id: battery.menu + label: Menu + - id: battery.list + label: List + - id: battery.add + label: Add + - id: battery.update + label: Update + - id: battery.delete + label: Delete + - id: bmfg + label: Battery Manufacturer Access + acls: + - id: bmfg.menu + label: Menu + - id: bmfg.list + label: List + - id: bmfg.add + label: Add + - id: bmfg.update + label: Update + - id: bmfg.delete + label: Delete + - id: bmodel + label: Battery Model Access + acls: + - id: bmodel.menu + label: Menu + - id: bmodel.list + label: List + - id: bmodel.add + label: Add + - id: bmodel.update + label: Update + - id: bmodel.delete + label: Delete + - id: bsize + label: Battery Size Access + acls: + - id: bsize.menu + label: Menu + - id: bsize.list + label: List + - id: bsize.add + label: Add + - id: bsize.update + label: Update + - id: bsize.delete + label: Delete + - id: vehicle + label: Vehicle Access + acls: + - id: vehicle.menu + label: Menu + - id: vehicle.list + label: List + - id: vehicle.add + label: Add + - id: vehicle.update + label: Update + - id: vehicle.delete + label: Delete + - id: vmfg + label: Vehicle Manufacturer Access + acls: + - id: vmfg.menu + label: Menu + - id: vmfg.list + label: List + - id: vmfg.add + label: Add + - id: vmfg.update + label: Update + - id: vmfg.delete + label: Delete + - id: customer + label: Customer Access + acls: + - id: customer.menu + label: Menu + - id: customer.list + label: List + - id: customer.add + label: Add + - id: customer.update + label: Update + - id: customer.delete + label: Delete + - id: customer.dpa + label: Display DPA + + + - id: location + label: Location Access + acls: + - id: location.menu + label: Menu + - id: outlet + label: Outlet Access + acls: + - id: outlet.menu + label: Menu + - id: outlet.list + label: List + - id: outlet.add + label: Add + - id: outlet.update + label: Update + - id: outlet.delete + label: Delete + - id: hub + label: Hub Access + acls: + - id: hub.menu + label: Menu + - id: hub.list + label: List + - id: hub.add + label: Add + - id: hub.update + label: Update + - id: hub.delete + label: Delete + - id: geofence + label: Geofence + acls: + - id: geofence.menu + label: Menu + - id: geofence.list + label: List + - id: geofence.add + label: Add + - id: geofence.delete + label: Delete + + - id: rider + label: Rider Access + acls: + - id: rider.menu + label: Menu + - id: rider.list + label: List + - id: rider.add + label: Add + - id: rider.update + label: Update + - id: rider.delete + label: Delete + + - id: servicecharge + label: Service Charge + acls: + - id: service_charge.menu + label: Menu + - id: service_charge.list + label: List + - id: service_charge.add + label: Add + - id: service_charge.update + label: Update + - id: service_charge.delete + label: Delete + + - id: joborder + label: Job Order + acls: + - id: joborder.menu + label: Menu + - id: jo_in.list + label: Incoming + - id: jo_proc.list + label: Dispatch + - id: jo_proc.unlock + label: Dispatch Unlock + - id: jo_assign.list + label: Rider Assignment + - id: jo_assign.unlock + label: Rider Assignment Unlock + - id: jo_fulfill.list + label: Fulfillment + - id: jo_open.list + label: Open + - id: jo_all.list + label: View All + - id: jo_pdf.list + label: PDF + - id: jo_open.edit + label: Edit + - id: joborder.cancel + label: Cancel + - id: jo_onestep.form + label: One-step Process + - id: jo_onestep.edit + label: One-step Process Edit + - id: jo_walkin.form + label: Walk-in + - id: jo_walkin.edit + label: Walk-in Edit + - id: jo_autoassign.test + label: Autoassign Test + - id: jo_hub.list + label: Hub View + - id: jo_cancel.fulfill + label: Fulfill Cancelled JO + - id: jo_resq_proc.list + label: RESQ Dispatch + + - id: support + label: Customer Support Access + acls: + - id: support.menu + label: Menu + - id: general.search + label: Search + - id: warranty.search + label: Customer Battery Search + - id: warranty.upload + label: Warranty Upload + + - id: ticket + label: Ticket Access + acls: + - id: ticket.menu + label: Menu + - id: ticket.list + label: List + - id: ticket.add + label: Add + - id: ticket.update + label: Update + - id: ticket.delete + label: Delete + + - id: promo + label: Promo Access + acls: + - id: promo.menu + label: Menu + - id: promo.list + label: List + - id: promo.add + label: Add + - id: promo.update + label: Update + - id: promo.delete + label: Delete + + - id: report + label: Reports + acls: + - id: report.menu + label: Menu + - id: report.reject + label: Rejection Report + - id: report.battery.conflict + label: Battery Conflict Report + - id: report.popapp.comparison + label: Popapp Comparison Report + - id: report.meh.customer + label: RESQ MEH Customer Report + - id: report.warranty.class + label: Warranty Class Report + - id: report.vehicle.battery.compatibility + label: Vehicle Battery Compatibility Report + - id: report.warranty.details + label: Warranty Details Report + - id: report.jo.details + label: Job Order Details Report + - id: report.jo_events + label: Job Order Events Report + - id: report.sms_messages + label: SMS Messages Report + - id: report.jo.auto_assign + label: Auto Assigned Job Order Report + - id: report.jo.advance_order + label: Advance Order Job Order Report + - id: report.customer.source + label: Customer Source Report + - id: report.hub.filter + label: Hub Filter Report + - id: report.warranty.raffle + label: Warranty Raffle Report + - id: report.jo.raffle + label: JO Raffle Report + + - id: service + label: Other Services + acls: + - id: service.menu + label: Menu + - id: service.list + label: List + - id: service.add + label: Add + - id: service.update + label: Update + - id: service.delete + label: Delete + + - id: partner + label: Partners + acls: + - id: partner.menu + label: Menu + - id: partner.list + label: List + - id: partner.add + label: Add + - id: partner.update + label: Update + - id: partner.delete + label: Delete + + - id: motolite_event + label: Motolite Events + acls: + - id: motolite_event.menu + label: Menu + - id: motolite_event.list + label: List + - id: motolite_event.add + label: Add + - id: motolite_event.update + label: Update + - id: motolite_event.delete + label: Delete + + - id: review + label: Reviews + acls: + - id: review.menu + label: Menu + - id: review.list + label: List + - id: review.view + label: View + - id: review.delete + label: Delete + + - id: privacypolicy + label: Privacy Policy + acls: + - id: privacy_policy.menu + label: Menu + - id: privacy_policy.list + label: List + - id: privacy_policy.add + label: Add + - id: privacy_policy.update + label: Update + - id: privacy_policy.delete + label: Delete + + - id: warranty + label: Warranty + acls: + - id: warranty.menu + label: Menu + - id: warranty.list + label: List + - id: warranty.add + label: Add + - id: warranty.update + label: Update + + - id: staticcontent + label: Static Content + acls: + - id: static_content.menu + label: Menu + - id: static_content.list + label: List + - id: static_content.add + label: Add + - id: static_content.update + label: Update + - id: static_content.delete + label: Delete + + - id: analytics + label: Analytics + acls: + - id: analytics.menu + label: Menu + - id: analytics.forecast + label: Forecasting + + - id: sap_battery + label: SAP Battery Access + acls: + - id: sap_battery.menu + label: Menu + - id: sap_battery.list + label: List + - id: sap_battery.add + label: Add + - id: sap_battery.update + label: Update + - id: sap_battery.delete + label: Delete + + - id: sap_brand + label: SAP Battery Brand Access + acls: + - id: sap_brand.menu + label: Menu + - id: sap_brand.list + label: List + - id: sap_brand.add + label: Add + - id: sap_brand.update + label: Update + - id: sap_brand.delete + label: Delete + + - id: sap_bsize + label: SAP Battery Size Access + acls: + - id: sap_bsize.menu + label: Menu + - id: sap_bsize.list + label: List + - id: sap_bsize.add + label: Add + - id: sap_bsize.update + label: Update + - id: sap_bsize.delete + label: Delete + + - id: sap_csize + label: SAP Battery Container Size Access + acls: + - id: sap_csize.menu + label: Menu + - id: sap_csize.list + label: List + - id: sap_csize.add + label: Add + - id: sap_csize.update + label: Update + - id: sap_csize.delete + label: Delete + + - id: customer_tag + label: Customer Tags Access + acls: + - id: customer_tag.menu + label: Menu + - id: customer_tag.list + label: List + - id: customer_tag.add + label: Add + - id: customer_tag.update + label: Update + - id: customer_tag.delete + label: Delete + + - id: review_tag + label: Review Tags Access + acls: + - id: review_tag.menu + label: Menu + - id: review_tag.list + label: List + - id: review_tag.add + label: Add + - id: review_tag.update + label: Update + - id: review_tag.delete + label: Delete + + - id: dealer + label: Dealer Access + acls: + - id: dealer.menu + label: Menu + - id: dealer.list + label: List + - id: dealer.add + label: Add + - id: dealer.update + label: Update + - id: dealer.delete + label: Delete + + - id: database + label: Database Access + acls: + - id: database.menu + label: Menu + + - id: ticket_type + label: Ticket Type Access + acls: + - id: ticket_type.menu + label: Menu + - id: ticket_type.list + label: List + - id: ticket_type.add + label: Add + - id: ticket_type.update + label: Update + - id: ticket_type.delete + label: Delete + + - id: subticket_type + label: Sub Ticket Type Access + acls: + - id: subticket_type.menu + label: Menu + - id: subticket_type.list + label: List + - id: subticket_type.add + label: Add + - id: subticket_type.update + label: Update + - id: subticket_type.delete + label: Delete + + - id: emergency_type + label: Emergency Type Access + acls: + - id: emergency_type.menu + label: Menu + - id: emergency_type.list + label: List + - id: emergency_type.add + label: Add + - id: emergency_type.update + label: Update + - id: emergency_type.delete + label: Delete + + - id: ownership_type + label: Ownership Type Access + acls: + - id: ownership_type.menu + label: Menu + - id: ownership_type.list + label: List + - id: ownership_type.add + label: Add + - id: ownership_type.update + label: Update + - id: ownership_type.delete + label: Delete + + api: + user_entity: "App\\Entity\\ApiUser" + acl_data: + - id: warranty + label: Warranty Access + acls: + - id: warranty.list + label: List + - id: warranty.find.serial + label: Find by Serial + - id: warranty.find.platenumber + label: Find by Plate Number + - id: warranty.register.battery + label: Register Battery + - id: warranty.claim + label: Claim + - id: warranty.update + label: Update + - id: warranty.cancel + label: Cancel + - id: warranty.delete + label: Delete + - id: warranty.set.privacypolicy + label: Set Privacy Policy + - id: warranty.list.serial + label: List by Serial + - id: batterybrand + label: Battery Brand Access + acls: + - id: batterybrand.list + label: List + - id: batterysize + label: Battery Size Access + acls: + - id: batterysize.list + label: List + - id: battery + label: Battery Access + acls: + - id: battery.list + label: List + - id: vmanufacturer + label: Vehicle Manufacturer Access + acls: + - id: vmanufacturer.list + label: List + - id: vehicle + label: Vehicle Access + acls: + - id: vehicle.list + label: List + - id: privacypolicy + label: Privacy Policy + acls: + - id: privacypolicy.find + label: Find Privacy Policy + - id: customer + label: Customer + acls: + - id: customer.register + label: Register Customer + - id: customer.verify + label: Verify Customer + - id: municipality + label: Municipality + acls: + - id: municipality.list + label: List + - id: dealer + label: Dealer + acls: + - id: dealer.list + label: List + - id: warrantyserial + label: Warranty Serial + acls: + - id: warrantyserial.upload + label: Upload + + - id: tapi_vmanufacturer + label: Third Party Vehicle Manufacturer Access + acls: + - id: tapi_vmanufacturer.list + label: List Third Party Vehicle Manufacturers + - id: tapi_vehicle + label: Third Party Vehicle Make Access + acls: + - id: tapi_vehicle.list + label: List Third Party Vehicles + - id: tapi_promo + label: Third Party Promo Access + acls: + - id: tapi_promo.list + label: List Third Party Promos + - id: tapi_battery + label: Third Party Battery Access + acls: + - id: tapi_battery_compatible.list + label: List Third Party Compatible Batteries + - id: tapi_jo + label: Third Party Job Order Access + acls: + - id: tapi_jo.request + label: Third Party Request Job Order + - id: tapi_jo.get.estimate + label: Third Party Get Estimate + - id: tapi_jo.get.ongoing + label: Third Party Get Ongoing Job Order + - id: tapi_jo.cancel + label: Third Party Cancel Job Order + - id: tapi_jo.get.invoice + label: Third Party Get Job Order Invoice + - id: tapi_jo.location.support + label: Third Party Check Location Support + - id: tapi_jo.nearest_hub.get + label: Third Party Get Nearest Hub and Slots + - id: tapi_jo.schedule_option.status + label: Third Party Schedule Option Status + - id: tapi_jo.get.info + label: Third Party Get Job Order Info + - id: tapi_service + label: Third Party Service Access + acls: + - id: tapi_service.list + label: List Third Party Services + + cust_api_v2: + user_entity: "App\\Entity\\CustomerUser" + acl_data: + - id: cust_api_v2.auth + label: Authentication + acls: + - id: cust_api_v2.auth.register + label: Register + - id: cust_api_v2.auth.confirm + label: Confirm Number + - id: cust_api_v2.auth.validate + label: Validate Code + - id: cust_api_v2.auth.resend_code + label: Resend Code + - id: cust_api_v2.customer + label: Customer + acls: + - id: cust_api_v2.customer.info + label: Info + - id: cust_api_v2.customer.update + label: Update + - id: cust_api_v2.customer.status + label: Status + - id: cust_api_v2.customer.hash + label: Hash + - id: cust_api_v2.device + label: Device + acls: + - id: cust_api_v2.device.id + label: Update + - id: cust_api_v2.invoice + label: Invoice + acls: + - id: cust_api_v2.invoice.estimate + label: Estimate + - id: cust_api_v2.jo + label: Job Order + acls: + - id: cust_api_v2.jo.ongoing + label: List Ongoing + - id: cust_api_v2.jo.invoice + label: Get Invoice + - id: cust_api_v2.jo.cancel + label: Cancel + - id: cust_api_v2.jo.info + label: Info + - id: cust_api_v2.jo.history + label: History + - id: cust_api_v2.jo.latest + label: Latest + - id: cust_api_v2.jo.all_ongoing + label: List All Ongoing + - id: cust_api_v2.jo.ongoing_count + label: List Ongoing Count + - id: cust_api_v2.jo.create + label: Create + - id: cust_api_v2.jo.request + label: Request + - id: cust_api_v2.jo.completed + label: List Completed + - id: cust_api_v2.location + label: Location + acls: + - id: cust_api_v2.location.support + label: Get Support Status + - id: cust_api_v2.location.nearest_hub_and_slots + label: List Nearest Hub and Slots + - id: cust_api_v2.location.create + label: Create + - id: cust_api_v2.location.list + label: List + - id: cust_api_v2.partner + label: Partner + acls: + - id: cust_api_v2.partner.info + label: Info + - id: cust_api_v2.partner.closest + label: List Closest Partners + - id: cust_api_v2.partner.review + label: Review + - id: cust_api_v2.privacy + label: Privacy + acls: + - id: cust_api_v2.privacy.settings + label: Get Privacy Settings + - id: cust_api_v2.promo + label: Promo + acls: + - id: cust_api_v2.promo.list + label: Get Promos + - id: cust_api_v2.rider + label: Rider + acls: + - id: cust_api_v2.rider.status + label: Status + - id: cust_api_v2.rider.rating + label: Rate + - id: cust_api_v2.schedule + label: Schedule + acls: + - id: cust_api_v2.schedule.status + label: Get Schedule Option Status + - id: cust_api_v2.service + label: Service + acls: + - id: cust_api_v2.service.list + label: List + - id: cust_api_v2.vehicle + label: Vehicle + acls: + - id: cust_api_v2.vehicle.mfgs + label: List Manufacturers + - id: cust_api_v2.vehicle.makes + label: List Makes + - id: cust_api_v2.vehicle.create + label: Add + - id: cust_api_v2.vehicle.update + label: Update + - id: cust_api_v2.vehicle.list + label: List + - id: cust_api_v2.vehicle.batteries + label: Compatible Batteries + - id: cust_api_v2.vehicle.delete + label: Delete + - id: cust_api_v2.warranty + label: Warranty + acls: + - id: cust_api_v2.warranty.activate + label: Activate + - id: cust_api_v2.warranty.check + label: Check Status + - id: cust_api_v2.warranty.register + label: Register \ No newline at end of file diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml new file mode 100644 index 00000000..48947331 --- /dev/null +++ b/config/packages/catalyst_menu.yaml @@ -0,0 +1,282 @@ +catalyst_menu: + main: + - id: home + acl: dashboard.menu + label: '[menu.dashboard]' + icon: flaticon-line-graph + order: 1 + + + - id: user + acl: user.menu + label: '[menu.user]' + icon: flaticon-users + order: 2 + - id: user_list + acl: user.list + label: '[menu.user.users]' + parent: user + - id: role_list + acl: role.list + label: '[menu.user.roles]' + parent: user + + - id: apiuser + acl: apiuser.menu + label: '[menu.apiuser]' + icon: flaticon-users + order: 3 + - id: api_user_list + acl: apiuser.list + label: '[menu.apiuser.users]' + parent: apiuser + - id: api_role_list + acl: apirole.list + label: '[menu.apiuser.roles]' + parent: apiuser + + - id: logistics + acl: logistics.menu + label: '[menu.logistics]' + icon: fa fa-truck + order: 4 + - id: rider_list + acl: rider.list + label: '[menu.logistics.riders]' + parent: logistics + + - id: battery + acl: battery.menu + label: '[menu.battery]' + icon: fa fa-battery-3 + order: 5 + - id: battery_list + acl: battery.list + label: '[menu.battery.batteries]' + parent: battery + - id: bmfg_list + acl: bmfg.list + label: '[menu.battery.manufacturers]' + parent: battery + - id: bmodel_list + acl: bmodel.list + label: '[menu.battery.models]' + parent: battery + - id: bsize_list + acl: bsize.list + label: '[menu.battery.sizes]' + parent: battery + - id: promo_list + acl: promo.list + label: '[menu.battery.promos]' + parent: battery + + - id: sapbattery + acl: sap_battery.menu + label: '[menu.sapbattery]' + icon: fa fa-battery + order: 6 + - id: sapbattery_list + acl: sap_battery.list + label: '[menu.sapbattery.batteries]' + parent: sapbattery + - id: sapbrand_list + acl: sap_brand.list + label: '[menu.sapbattery.brands]' + parent: sapbattery + - id: sapbsize_list + acl: sap_bsize.list + label: '[menu.sapbattery.sizes]' + parent: sapbattery + - id: sapcsize_list + acl: sap_csize.list + label: '[menu.sapbattery.csizes]' + parent: sapbattery + + + - id: vehicle + acl: vehicle.menu + label: '[menu.vehicle]' + icon: fa fa-car + order: 7 + - id: vehicle_list + acl: vehicle.list + label: '[menu.vehicle.vehicles]' + parent: vehicle + - id: vmfg_list + acl: vmfg.list + label: '[menu.vehicle.manufacturers]' + parent: vehicle + + - id: location + acl: location.menu + label: '[menu.location]' + icon: fa fa-home + order: 8 + - id: outlet_list + acl: outlet.menu + label: '[menu.location.outlets]' + parent: location + - id: hub_list + acl: hub.menu + label: '[menu.location.hubs]' + parent: location + - id: dealer_list + acl: dealer.list + label: '[menu.location.dealers]' + parent: location + - id: geofence_list + acl: geofence.menu + label: '[menu.location.geofence]' + parent: location + + + - id: joborder + acl: joborder.menu + label: '[menu.joborder]' + icon: flaticon-calendar-3 + order: 9 + - id: jo_in + acl: jo_in.list + label: '[menu.joborder.incoming]' + parent: joborder + - id: jo_proc + acl: jo_proc.list + label: '[menu.joborder.dispatch]' + parent: joborder + - id: jo_resq_proc + acl: jo_resq_proc.list + label: '[menu.joborder.resqdispatch]' + parent: joborder + - id: jo_assign + acl: jo_assign.list + label: '[menu.joborder.assignment]' + parent: joborder + - id: jo_fulfill + acl: jo_fulfill.list + label: '[menu.joborder.fulfillment]' + parent: joborder + - id: jo_open + acl: jo_open.list + label: '[menu.joborder.open]' + parent: joborder + - id: jo_all + acl: jo_all.list + label: '[menu.joborder.viewall]' + parent: joborder + - id: jo_hub_view + acl: jo_hub.list + label: '[menu.joborder.hubview]' + parent: joborder + + - id: support + acl: support.menu + label: '[menu.support]' + icon: flaticon-support + order: 10 + - id: customer_list + acl: customer.list + label: '[menu.support.customers]' + parent: support + - id: ticket_list + acl: ticket.list + label: '[menu.support.tickets]' + parent: support + - id: general_search + acl: general.search + label: '[menu.support.search]' + parent: support + - id: warranty_search + acl: warranty.search + label: '[menu.support.warrantysearch]' + parent: support + - id: privacy_policy_list + acl: privacy_policy.list + label: '[menu.support.privacypolicy]' + parent: support + - id: warranty_list + acl: warranty.list + label: '[menu.support.warranty]' + parent: support + - id: warranty_upload + acl: warranty.upload + label: '[menu.support.warrantyupload]' + parent: support + - id: static_content_list + acl: static_content.list + label: '[menu.support.staticcontent]' + parent: support + - id: customertag_list + acl: customer_tag.list + label: '[menu.support.customertags]' + parent: support + - id: reviewtag_list + acl: review_tag.list + label: '[menu.support.reviewtags]' + parent: support + + - id: service + acl: service.menu + label: '[menu.service]' + icon: flaticon-squares + order: 11 + - id: service_list + acl: service.list + label: '[menu.service.services]' + parent: service + + - id: partner + acl: partner.menu + label: '[menu.partner]' + icon: flaticon-network + order: 12 + - id: partner_list + acl: partner.list + label: '[menu.partner.partners]' + parent: partner + - id: review_list + acl: review.list + label: '[menu.partner.reviews]' + parent: partner + + - id: motolite_event + acl: motolite_event.menu + label: '[menu.motolite_event]' + icon: flaticon-event-calendar-symbol + order: 13 + - id: motolite_event_list + acl: motolite_event.list + label: '[menu.motolite_event.events]' + parent: motolite_event + + - id: analytics + acl: analytics.menu + label: '[menu.analytics]' + icon: flaticon-graphic + order: 14 + - id: analytics_forecast_form + acl: analytics.forecast + label: '[menu.analytics.forecasting]' + parent: analytics + + - id: database + acl: database.menu + label: '[menu.database]' + icon: fa fa-database + order: 15 + - id: ticket_type_list + acl: ticket_type.menu + label: '[menu.database.tickettypes]' + parent: database + - id: subticket_type_list + acl: subticket_type.menu + label: '[menu.database.subtickettypes]' + parent: database + - id: emergency_type_list + acl: emergency_type.menu + label: '[menu.database.emergencytypes]' + parent: database + - id: ownership_type_list + acl: ownership_type.menu + label: '[menu.database.ownershiptypes]' + parent: database \ No newline at end of file diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 1b0f6824..b6ca81a0 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -9,8 +9,14 @@ security: entity: class: App\Entity\User property: username - api_key_user_provider: - id: Catalyst\APIBundle\Security\APIKeyUserProvider + api_provider: + entity: + class: App\Entity\ApiUser + property: api_key + api_v2_provider: + entity: + class: App\Entity\CustomerUser + property: api_key firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ @@ -47,29 +53,45 @@ security: pattern: ^\/test_capi\/ security: false + cust_api_v2: + pattern: ^\/apiv2\/(?!register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/) + provider: api_v2_provider + access_denied_handler: Catalyst\ApiBundle\Service\AccessDeniedHandler + stateless: true + guard: + authenticators: + - Catalyst\ApiBundle\Security\Authenticator + + cust_api_v2_guest: + pattern: ^\/apiv2\/(register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/) + security: false + warranty_api: pattern: ^\/capi\/ + provider: api_provider + access_denied_handler: Catalyst\ApiBundle\Service\AccessDeniedHandler stateless: true - simple_preauth: - authenticator: Catalyst\APIBundle\Security\APIKeyAuthenticator - provider: api_key_user_provider - user_checker: Catalyst\AuthBundle\Service\UserChecker + guard: + authenticators: + - Catalyst\ApiBundle\Security\Authenticator new_rider_api: pattern: ^\/rider_api\/ + provider: api_provider + access_denied_handler: Catalyst\ApiBundle\Service\AccessDeniedHandler stateless: true - simple_preauth: - authenticator: Catalyst\APIBundle\Security\APIKeyAuthenticator - provider: api_key_user_provider - user_checker: Catalyst\AuthBundle\Service\UserChecker + guard: + authenticators: + - Catalyst\ApiBundle\Security\Authenticator third_party_api: pattern: ^\/tapi\/ + provider: api_provider + access_denied_handler: Catalyst\ApiBundle\Service\AccessDeniedHandler stateless: true - simple_preauth: - authenticator: Catalyst\APIBundle\Security\APIKeyAuthenticator - provider: api_key_user_provider - user_checker: Catalyst\AuthBundle\Service\UserChecker + guard: + authenticators: + - Catalyst\ApiBundle\Security\Authenticator main: provider: user_provider @@ -84,6 +106,7 @@ security: lifetime: 604800 path: / user_checker: Catalyst\AuthBundle\Service\UserChecker + switch_user: { role: ROLE_SUPER_ADMIN } # activate different ways to authenticate diff --git a/config/resq.services.yaml b/config/resq.services.yaml index 82eb4cc5..177d68b5 100644 --- a/config/resq.services.yaml +++ b/config/resq.services.yaml @@ -43,20 +43,6 @@ services: $cache_dir: "%kernel.cache_dir%" $config_dir: "%kernel.root_dir%/../config" - Catalyst\AuthBundle\Service\ACLGenerator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%app_acl_file%" - - Catalyst\AuthBundle\Service\ACLVoter: - arguments: - $user_class: "App\\Entity\\User" - tags: ['security.voter'] - - Catalyst\AuthBundle\Service\UserChecker: - App\Service\FileUploader: arguments: $target_dir: '%image_upload_directory%' @@ -115,50 +101,6 @@ services: arguments: $redis_client: "@App\\Service\\RedisClientProvider" - Catalyst\APIBundle\Security\APIKeyUserProvider: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Security\APIKeyAuthenticator: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Command\UserCreateCommand: - arguments: - $em: "@doctrine.orm.entity_manager" - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestCommand: - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestAPICommand: - tags: ['console.command'] - - Catalyst\APIBundle\Access\Voter: - arguments: - $acl_gen: "@Catalyst\\APIBundle\\Access\\Generator" - $user_class: "Catalyst\\APIBundle\\Entity\\User" - tags: ['security.voter'] - - Catalyst\APIBundle\Access\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%api_acl_file%" - - Catalyst\MenuBundle\Menu\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - - Catalyst\MenuBundle\Listener\MenuAnnotationListener: - arguments: - $menu_name: "main_menu" - tags: - - { name: kernel.event_listener, event: kernel.controller, method: onKernelController } - # invoice generator App\Service\InvoiceGenerator\ResqInvoiceGenerator: ~ diff --git a/config/routes/apiv2.yaml b/config/routes/apiv2.yaml new file mode 100644 index 00000000..d9abd0a2 --- /dev/null +++ b/config/routes/apiv2.yaml @@ -0,0 +1,247 @@ +# api + +apiv2_register: + path: /apiv2/register + controller: App\Controller\CustomerAppAPI\AuthController::register + methods: [POST] + +apiv2_confirm: + path: /apiv2/number_confirm + controller: App\Controller\CustomerAppAPI\AuthController::confirmNumber + methods: [POST] + +apiv2_validate: + path: /apiv2/code_validate + controller: App\Controller\CustomerAppAPI\AuthController::validateCode + methods: [POST] + +apiv2_info_get: + path: /apiv2/info + controller: App\Controller\CustomerAppAPI\CustomerController::getInfo + methods: [GET] + +apiv2_info_update: + path: /apiv2/info + controller: App\Controller\CustomerAppAPI\CustomerController::updateInfo + methods: [POST] + +apiv2_status: + path: /apiv2/status + controller: App\Controller\CustomerAppAPI\CustomerController::getStatus + methods: [GET] + +apiv2_vehicle_mfg_list: + path: /apiv2/vehicle/mfgs + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicleManufacturers + methods: [GET] + +apiv2_vehicle_make_list: + path: /apiv2/vehicle/mfgs/{mfg_id}/makes + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicleMakes + methods: [GET] + +apiv2_cust_vehicle_add: + path: /apiv2/vehicles + controller: App\Controller\CustomerAppAPI\VehicleController::addVehicle + methods: [POST] + +apiv2_cust_vehicle_update: + path: /apiv2/vehicles/{id} + controller: App\Controller\CustomerAppAPI\VehicleController::updateVehicle + methods: [POST] + +apiv2_cust_vehicle_list: + path: /apiv2/vehicles + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicles + methods: [GET] + +apiv2_promo_list: + path: /apiv2/promos + controller: App\Controller\CustomerAppAPI\PromoController::listPromos + methods: [GET] + +apiv2_battery_list: + path: /apiv2/vehicles/{vid}/compatible_batteries + controller: App\Controller\CustomerAppAPI\VehicleController::getCompatibleBatteries + methods: [GET] + +apiv2_jo_request: + path: /apiv2/job_order + controller: App\Controller\CustomerAppAPI\JobOrderController::requestJobOrder + methods: [POST] + +apiv2_estimate: + path: /apiv2/estimate + controller: App\Controller\CustomerAppAPI\InvoiceController::getEstimate + methods: [POST] + +apiv2_ongoing: + path: /apiv2/job_order/ongoing + controller: App\Controller\CustomerAppAPI\JobOrderController::getOngoing + methods: [GET] + +apiv2_rider_status: + path: /apiv2/rider + controller: App\Controller\CustomerAppAPI\RiderController::getRiderStatus + methods: [GET] + +apiv2_rider_rating_add: + path: /apiv2/rider_rating + controller: App\Controller\CustomerAppAPI\RiderController::addRiderRating + methods: [POST] + +apiv2_jo_cancel: + path: /apiv2/job_order/cancel + controller: App\Controller\CustomerAppAPI\JobOrderController:cancelJobOrder + methods: [POST] + +apiv2_jo_history: + path: /apiv2/job_order/history + controller: App\Controller\CustomerAppAPI\JobOrderController:getJOHistory + methods: [GET] + +apiv2_jo_invoice: + path: /apiv2/job_order/invoice + controller: App\Controller\CustomerAppAPI\JobOrderController:getJOInvoice + methods: [GET] + +apiv2_device_id: + path: /apiv2/device_id + controller: App\Controller\CustomerAppAPI\DeviceController:updateDeviceID + methods: [POST] + +apiv2_privacy: + path: /apiv2/privacy + controller: App\Controller\CustomerAppAPI\PrivacyController:privacySettings + methods: [POST] + +apiv2_resend_code: + path: /apiv2/resend_code + controller: App\Controller\CustomerAppAPI\AuthController:resendCode + methods: [POST] + +apiv2_location_support: + path: /apiv2/location_support + controller: App\Controller\CustomerAppAPI\LocationController:locationSupport + methods: [GET] + +apiv2_activate_warranty: + path: /apiv2/activate_warranty + controller: App\Controller\CustomerAppAPI\WarrantyController:activateWarranty + methods: [POST] + +apiv2_service_list: + path: /apiv2/services + controller: App\Controller\CustomerAppAPI\ServiceController:listServices + methods: [GET] + +apiv2_partner_info: + path: /apiv2/partners/{pid} + controller: App\Controller\CustomerAppAPI\PartnerController:getPartnerInformation + methods: [GET] + +apiv2_partner: + path: /apiv2/partners + controller: App\Controller\CustomerAppAPI\PartnerController:getClosestPartners + methods: [GET] + +apiv2_partner_review: + path: /apiv2/partners/{pid}/review + controller: App\Controller\CustomerAppAPI\PartnerController:reviewPartner + methods: [POST] + +apiv2_nearest_hub_slots: + path: /apiv2/hub_slots + controller: App\Controller\CustomerAppAPI\LocationController::getNearestHubAndSlots + methods: [GET] + +apiv2_new_jo_request: + path: /apiv2/new_job_order + controller: App\Controller\CustomerAppAPI\JobOrderController::newRequestJobOrder + methods: [POST] + +apiv2_version_check: + path: /apiv2/version_check + controller: App\Controller\CustomerAppAPI\AppController::versionCheck + methods: [GET] + +apiv2_schedule_option_status: + path: /apiv2/schedule_option_status + controller: App\Controller\CustomerAppAPI\ScheduleController::scheduleOptionStatus + methods: [GET] + +# paperless warranty / qr code +apiv2_warr_serial_check: + path: /apiv2/warranty/{serial} + controller: App\Controller\CustomerAppAPI\WarrantyController::warrantyCheck + methods: [GET] + +apiv2_warr_serial_register: + path: /apiv2/warranty/{serial} + controller: App\Controller\CustomerAppAPI\WarrantyController::warrantyRegister + methods: [POST] + +apiv2_jo_info: + path: /apiv2/job_order/{id}/info + controller: App\Controller\CustomerAppAPI\JobOrderController::getJobOrderInfo + methods: [GET] + +apiv2_ongoing_job_orders: + path: /apiv2/job_orders/ongoing + controller: App\Controller\CustomerAppAPI\JobOrderController::getAllOngoingJobOrders + methods: [GET] + +apiv2_ongoing_jo_count: + path: /apiv2/job_orders/ongoing/count + controller: App\Controller\CustomerAppAPI\JobOrderController::getOngoingJobOrderCount + methods: [GET] + +apiv2_new_location: + path: /apiv2/new_location + controller: App\Controller\CustomerAppAPI\LocationController::addLocation + methods: [POST] + +apiv2_locations: + path: /apiv2/locations + controller: App\Controller\CustomerAppAPI\LocationController::getLocations + methods: [GET] + +apiv2_location_remove: + path: /apiv2/locations/{id}/remove + controller: App\Controller\CustomerAppAPI\LocationController::removeLocation + methods: [POST] + +apiv2_cust_vehicle_remove: + path: /apiv2/vehicles/{id}/remove + controller: App\Controller\CustomerAppAPI\VehicleController::removeVehicle + methods: [POST] + +apiv2_latest_job_order: + path: /apiv2/job_order/latest + controller: App\Controller\CustomerAppAPI\JobOrderController::getLatestJobOrder + methods: [GET] + +apiv2_customer_hash_get: + path: /apiv2/customer_hash + controller: App\Controller\CustomerAppAPI\CustomerController::getCustomerHash + methods: [GET] + +#apiv2_completed_job_orders: +# path: /apiv2/job_orders/completed +# controller: App\Controller\CustomerAppAPI\JobOrderController::getCompletedJobOrders +# methods: [GET] + +# motolite events +apiv2_motolite_events: + path: /apiv2/motolite_events + controller: App\Controller\CustomerAppAPI\MotoliteEventController::getEvents + methods: [GET] + +# review tags +apiv2_partner_review_tags: + path: /apiv2/review_tags/partner + controller: App\Controller\CustomerAppAPI\ReviewTagController::getPartnerReviewTags + +apiv2_rider_review_tags: + path: /apiv2/review_tags/rider + controller: App\Controller\CustomerAppAPI\ReviewTagController::getRiderReviewTags \ No newline at end of file diff --git a/config/routes/customer_api.yaml b/config/routes/customer_api.yaml new file mode 100644 index 00000000..86aae804 --- /dev/null +++ b/config/routes/customer_api.yaml @@ -0,0 +1,227 @@ +# api + +cust_api_register: + path: /apiv2/register + controller: App\Controller\CustomerAppAPI\AuthController::register + methods: [POST] + +cust_api_confirm: + path: /apiv2/number_confirm + controller: App\Controller\CustomerAppAPI\AuthController::confirmNumber + methods: [POST] + +cust_api_validate: + path: /apiv2/code_validate + controller: App\Controller\CustomerAppAPI\AuthController::validateCode + methods: [POST] + +cust_api_info_get: + path: /apiv2/info + controller: App\Controller\CustomerAppAPI\CustomerController::getInfo + methods: [GET] + +cust_api_info_update: + path: /apiv2/info + controller: App\Controller\CustomerAppAPI\CustomerController::updateInfo + methods: [POST] + +cust_api_status: + path: /apiv2/status + controller: App\Controller\CustomerAppAPI\CustomerController::getStatus + methods: [GET] + +cust_api_vehicle_mfg_list: + path: /apiv2/vehicle/mfgs + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicleManufacturers + methods: [GET] + +cust_api_vehicle_make_list: + path: /apiv2/vehicle/mfgs/{mfg_id}/makes + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicleMakes + methods: [GET] + +cust_api_cust_vehicle_add: + path: /apiv2/vehicles + controller: App\Controller\CustomerAppAPI\VehicleController::addVehicle + methods: [POST] + +cust_api_cust_vehicle_update: + path: /apiv2/vehicles/{id} + controller: App\Controller\CustomerAppAPI\VehicleController::updateVehicle + methods: [POST] + +cust_api_cust_vehicle_list: + path: /apiv2/vehicles + controller: App\Controller\CustomerAppAPI\VehicleController::listVehicles + methods: [GET] + +cust_api_promo_list: + path: /apiv2/promos + controller: App\Controller\CustomerAppAPI\PromoController::listPromos + methods: [GET] + +cust_api_battery_list: + path: /apiv2/vehicles/{vid}/compatible_batteries + controller: App\Controller\CustomerAppAPI\VehicleController::getCompatibleBatteries + methods: [GET] + +cust_api_jo_request: + path: /apiv2/job_order + controller: App\Controller\CustomerAppAPI\JobOrderController::requestJobOrder + methods: [POST] + +cust_api_estimate: + path: /apiv2/estimate + controller: App\Controller\CustomerAppAPI\EstimateController::getEstimate + methods: [POST] + +cust_api_ongoing: + path: /apiv2/job_order/ongoing + controller: App\Controller\CustomerAppAPI\JobOrderController::getOngoing + methods: [GET] + +cust_api_rider_status: + path: /apiv2/rider + controller: App\Controller\CustomerAppAPI\RiderController::getRiderStatus + methods: [GET] + +cust_api_rider_rating_add: + path: /apiv2/rider_rating + controller: App\Controller\CustomerAppAPI\RiderController::addRiderRating + methods: [POST] + +cust_api_jo_cancel: + path: /apiv2/job_order/cancel + controller: App\Controller\CustomerAppAPI\JobOrderController:cancelJobOrder + methods: [POST] + +cust_api_jo_history: + path: /apiv2/job_order/history + controller: App\Controller\CustomerAppAPI\JobOrderController:getJOHistory + methods: [GET] + +cust_api_jo_invoice: + path: /apiv2/job_order/invoice + controller: App\Controller\CustomerAppAPI\JobOrderController:getJOInvoice + methods: [GET] + +cust_api_device_id: + path: /apiv2/device_id + controller: App\Controller\CustomerAppAPI\DeviceController:updateDeviceID + methods: [POST] + +cust_api_privacy: + path: /apiv2/privacy + controller: App\Controller\CustomerAppAPI\PrivacyController:privacySettings + methods: [POST] + +cust_api_resend_code: + path: /apiv2/resend_code + controller: App\Controller\CustomerAppAPI\AuthController:resendCode + methods: [POST] + +cust_api_location_support: + path: /apiv2/location_support + controller: App\Controller\CustomerAppAPI\LocationController:locationSupport + methods: [GET] + +cust_api_activate_warranty: + path: /apiv2/activate_warranty + controller: App\Controller\CustomerAppAPI\WarrantyController:activateWarranty + methods: [POST] + +cust_api_service_list: + path: /apiv2/services + controller: App\Controller\CustomerAppAPI\ServiceController:listServices + methods: [GET] + +cust_api_partner_info: + path: /apiv2/partners/{pid} + controller: App\Controller\CustomerAppAPI\PartnerController:getPartnerInformation + methods: [GET] + +cust_api_partner: + path: /apiv2/partners + controller: App\Controller\CustomerAppAPI\PartnerController:getClosestPartners + methods: [GET] + +cust_api_partner_review: + path: /apiv2/partners/{pid}/review + controller: App\Controller\CustomerAppAPI\PartnerController:reviewPartner + methods: [POST] + +cust_api_nearest_hub_slots: + path: /apiv2/hub_slots + controller: App\Controller\CustomerAppAPI\LocationController::getNearestHubAndSlots + methods: [GET] + +cust_api_new_jo_request: + path: /apiv2/new_job_order + controller: App\Controller\CustomerAppAPI\JobOrderController::newRequestJobOrder + methods: [POST] + +cust_api_version_check: + path: /apiv2/version_check + controller: App\Controller\CustomerAppAPI\AppController::versionCheck + methods: [GET] + +cust_api_schedule_option_status: + path: /apiv2/schedule_option_status + controller: App\Controller\CustomerAppAPI\ScheduleController::scheduleOptionStatus + methods: [GET] + +# paperless warranty / qr code +cust_api_warr_serial_check: + path: /apiv2/warranty/{serial} + controller: App\Controller\CustomerAppAPI\WarrantyController::warrantyCheck + methods: [GET] + +cust_api_warr_serial_register: + path: /apiv2/warranty/{serial} + controller: App\Controller\CustomerAppAPI\WarrantyController::warrantyRegister + methods: [POST] + +cust_api_jo_info: + path: /apiv2/job_order/{id}/info + controller: App\Controller\CustomerAppAPI\JobOrderController::getJobOrderInfo + methods: [GET] + +cust_api_ongoing_job_orders: + path: /apiv2/job_orders/ongoing + controller: App\Controller\CustomerAppAPI\JobOrderController::getAllOngoingJobOrders + methods: [GET] + +cust_api_ongoing_jo_count: + path: /apiv2/job_orders/ongoing/count + controller: App\Controller\CustomerAppAPI\JobOrderController::getOngoingJobOrderCount + methods: [GET] + +cust_api_new_location: + path: /apiv2/new_location + controller: App\Controller\CustomerAppAPI\LocationController::addLocation + methods: [POST] + +cust_api_locations: + path: /apiv2/locations + controller: App\Controller\CustomerAppAPI\LocationController::getLocations + methods: [GET] + +cust_api_cust_vehicle_remove: + path: /apiv2/vehicles/{id}/remove + controller: App\Controller\CustomerAppAPI\VehicleController::removeVehicle + methods: [POST] + +cust_api_latest_job_order: + path: /apiv2/job_order/latest + controller: App\Controller\CustomerAppAPI\JobOrderController::getLatestJobOrder + methods: [GET] + +cust_api_customer_hash_get: + path: /apiv2/customer_hash + controller: App\Controller\CustomerAppAPI\CustomerController::getCustomerHash + methods: [GET] + +#cust_api_completed_job_orders: +# path: /apiv2/job_orders/completed +# controller: App\Controller\CustomerAppAPI\JobOrderController::getCompletedJobOrders +# methods: [GET] diff --git a/config/routes/insurance.yaml b/config/routes/insurance.yaml new file mode 100644 index 00000000..bf3e3814 --- /dev/null +++ b/config/routes/insurance.yaml @@ -0,0 +1,6 @@ +# insurance + +insurance_listener: + path: /api/insurance/listen + controller: App\Controller\InsuranceController::listen + methods: [POST] diff --git a/config/routes/motolite_event.yaml b/config/routes/motolite_event.yaml new file mode 100644 index 00000000..865a6162 --- /dev/null +++ b/config/routes/motolite_event.yaml @@ -0,0 +1,38 @@ +motolite_event_list: + path: /motolite_events + controller: App\Controller\MotoliteEventController::index + +motolite_event_rows: + path: /motolite_events/rows + controller: App\Controller\MotoliteEventController::rows + methods: [POST] + +motolite_event_create: + path: /motolite_events/create + controller: App\Controller\MotoliteEventController::addForm + methods: [GET] + +motolite_event_create_submit: + path: /motolite_events/create + controller: App\Controller\MotoliteEventController::addSubmit + methods: [POST] + +motolite_event_upload_image: + path: /motolite_events/upload + controller: App\Controller\MotoliteEventController::uploadImage + methods: [POST] + +motolite_event_update: + path: /motolite_events/{id} + controller: App\Controller\MotoliteEventController::updateForm + methods: [GET] + +motolite_event_update_submit: + path: /motolite_events/{id} + controller: App\Controller\MotoliteEventController::updateSubmit + methods: [POST] + +motolite_event_delete: + path: /motolite_events/{id} + controller: App\Controller\MotoliteEventController::destroy + methods: [DELETE] diff --git a/config/routes/review_tag.yaml b/config/routes/review_tag.yaml new file mode 100644 index 00000000..85964581 --- /dev/null +++ b/config/routes/review_tag.yaml @@ -0,0 +1,33 @@ +reviewtag_list: + path: /review_tags + controller: App\Controller\ReviewTagController::index + +reviewtag_rows: + path: /review_tags/rows + controller: App\Controller\ReviewTagController::rows + methods: [POST] + +reviewtag_create: + path: /review_tags/create + controller: App\Controller\ReviewTagController::addForm + methods: [GET] + +reviewtag_create_submit: + path: /review_tags/create + controller: App\Controller\ReviewTagController::addSubmit + methods: [POST] + +reviewtag_update: + path: /review_tags/{id} + controller: App\Controller\ReviewTagController::updateForm + methods: [GET] + +reviewtag_update_submit: + path: /review_tags/{id} + controller: App\Controller\ReviewTagController::updateSubmit + methods: [POST] + +reviewtag_delete: + path: /review_tags/{id} + controller: App\Controller\ReviewTagController::destroy + methods: [DELETE] diff --git a/config/services.yaml b/config/services.yaml index d707b465..38d3aa23 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -43,20 +43,6 @@ services: $cache_dir: "%kernel.cache_dir%" $config_dir: "%kernel.root_dir%/../config" - Catalyst\AuthBundle\Service\ACLGenerator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%app_acl_file%" - - Catalyst\AuthBundle\Service\ACLVoter: - arguments: - $user_class: "App\\Entity\\User" - tags: ['security.voter'] - - Catalyst\AuthBundle\Service\UserChecker: - App\Service\FileUploader: arguments: $target_dir: '%image_upload_directory%' @@ -81,6 +67,11 @@ services: $redis_client: "@App\\Service\\RedisClientProvider" $key: "mqtt_events" + App\Service\MQTTClientApiv2: + arguments: + $redis_client: "@App\\Service\\RedisClientProvider" + $key: "mqtt_events" + App\Service\APNSClient: arguments: $redis_client: "@App\\Service\\RedisClientProvider" @@ -120,50 +111,6 @@ services: arguments: $redis_client: "@App\\Service\\RedisClientProvider" - Catalyst\APIBundle\Security\APIKeyUserProvider: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Security\APIKeyAuthenticator: - arguments: - $em: "@doctrine.orm.entity_manager" - - Catalyst\APIBundle\Command\UserCreateCommand: - arguments: - $em: "@doctrine.orm.entity_manager" - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestCommand: - tags: ['console.command'] - - Catalyst\APIBundle\Command\TestAPICommand: - tags: ['console.command'] - - Catalyst\APIBundle\Access\Voter: - arguments: - $acl_gen: "@Catalyst\\APIBundle\\Access\\Generator" - $user_class: "Catalyst\\APIBundle\\Entity\\User" - tags: ['security.voter'] - - Catalyst\APIBundle\Access\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - $acl_file: "%api_acl_file%" - - Catalyst\MenuBundle\Menu\Generator: - arguments: - $router: "@router.default" - $cache_dir: "%kernel.cache_dir%" - $config_dir: "%kernel.root_dir%/../config" - - Catalyst\MenuBundle\Listener\MenuAnnotationListener: - arguments: - $menu_name: "main_menu" - tags: - - { name: kernel.event_listener, event: kernel.controller, method: onKernelController } - # invoice generator App\Service\InvoiceGenerator\ResqInvoiceGenerator: ~ @@ -260,6 +207,13 @@ services: $sub_key: "%env(MOTIV_KEY)%" $token: "%env(MOTIV_TOKEN)%" + # insurance connector + App\Service\InsuranceConnector: + arguments: + $base_url: "%env(INSURANCE_BASE_URL)%" + $username: "%env(INSURANCE_USERNAME)%" + $password: "%env(INSURANCE_PASSWORD)%" + # entity listener for customer vehicle warranty code history App\EntityListener\CustomerVehicleSerialListener: arguments: @@ -331,3 +285,9 @@ services: App\Service\WarrantySerialLoadLogger: arguments: $em: "@doctrine.orm.entity_manager" + + # FCM sender + App\Service\FCMSender: + arguments: + $server_key: "%env(FCM_SERVER_KEY)%" + $sender_id: "%env(FCM_SENDER_ID)%" diff --git a/public/assets/images/image.gif b/public/assets/images/image.gif new file mode 100755 index 00000000..c32e7886 Binary files /dev/null and b/public/assets/images/image.gif differ diff --git a/src/Command/CreateRiderAPIUserCommand.php b/src/Command/CreateRiderAPIUserCommand.php index 96508fd8..1f60b668 100644 --- a/src/Command/CreateRiderAPIUserCommand.php +++ b/src/Command/CreateRiderAPIUserCommand.php @@ -10,8 +10,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Entity\User as APIUser; -use Catalyst\APIBundle\Entity\Role as APIRole; +use App\Entity\ApiUser as APIUser; +use Catalyst\ApiBundle\Entity\Role as APIRole; use App\Entity\Rider; diff --git a/src/Command/UpdateUnacceptedJobOrdersCommand.php b/src/Command/UpdateUnacceptedJobOrdersCommand.php index 2a9ba2c6..b7bfeb0c 100644 --- a/src/Command/UpdateUnacceptedJobOrdersCommand.php +++ b/src/Command/UpdateUnacceptedJobOrdersCommand.php @@ -10,6 +10,8 @@ use Symfony\Component\Console\Output\OutputInterface; use Doctrine\ORM\EntityManagerInterface; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Entity\JobOrder; use App\Entity\Rider; @@ -21,11 +23,19 @@ class UpdateUnacceptedJobOrdersCommand extends Command protected $em; protected $mclient; - public function __construct(EntityManagerInterface $em, MQTTClient $mclient) + // NOTE: for resq2 app + protected $mclientv2; + protected $fcmclient; + + public function __construct(EntityManagerInterface $em, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { $this->em = $em; $this->mclient = $mclient; + // NOTE: for resq2 app + $this->mclientv2 = $mclientv2; + $this->fcmclient = $fcmclient; + parent::__construct(); } @@ -41,6 +51,10 @@ class UpdateUnacceptedJobOrdersCommand extends Command $em = $this->em; $mclient = $this->mclient; + // NOTE: for resq2 app + $mclientv2 = $this->mclientv2; + $fcmclient = $this->fcmclient; + // TODO: get the timeout limit from .env $timeout = 3; $current_status = 'assigned'; @@ -107,6 +121,10 @@ class UpdateUnacceptedJobOrdersCommand extends Command 'jo_id' => $id, ]; $mclient->sendEvent($jo, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); } $rider = $jo->getRider(); diff --git a/src/Controller/APIRoleController.php b/src/Controller/APIRoleController.php index f347d890..4c60b4cd 100644 --- a/src/Controller/APIRoleController.php +++ b/src/Controller/APIRoleController.php @@ -2,8 +2,8 @@ namespace App\Controller; -use Catalyst\APIBundle\Entity\Role as APIRole; -use Catalyst\APIBundle\Access\Generator as APIACLGenerator; +use Catalyst\ApiBundle\Entity\Role as APIRole; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,7 +19,7 @@ class APIRoleController extends Controller { protected $api_acl_gen; - public function __construct(APIACLGenerator $api_acl_gen) + public function __construct(ACLGenerator $api_acl_gen) { $this->api_acl_gen = $api_acl_gen; } diff --git a/src/Controller/APIUserController.php b/src/Controller/APIUserController.php index 122d3830..d707e32c 100644 --- a/src/Controller/APIUserController.php +++ b/src/Controller/APIUserController.php @@ -2,8 +2,8 @@ namespace App\Controller; -use Catalyst\APIBundle\Entity\User as APIUser; -use Catalyst\APIBundle\Entity\Role as APIRole; +use App\Entity\ApiUser as APIUser; +use Catalyst\ApiBundle\Entity\Role as APIRole; use Doctrine\ORM\Query; use Symfony\Component\HttpFoundation\Request; diff --git a/src/Controller/CAPI/BatteryController.php b/src/Controller/CAPI/BatteryController.php index 5a03c379..b61d39b8 100644 --- a/src/Controller/CAPI/BatteryController.php +++ b/src/Controller/CAPI/BatteryController.php @@ -6,14 +6,14 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\SAPBattery; use App\Entity\SAPBatterySize; use App\Entity\SAPBatteryBrand; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class BatteryController extends APIController { diff --git a/src/Controller/CAPI/CustomerController.php b/src/Controller/CAPI/CustomerController.php index 912e0235..dc1505b3 100644 --- a/src/Controller/CAPI/CustomerController.php +++ b/src/Controller/CAPI/CustomerController.php @@ -8,8 +8,9 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +//use Catalyst\ApiBundle\Response\APIResponse; +use Catalyst\ApiBundle\Component\Response as APIResponse; use App\Entity\Customer; use App\Entity\CustomerVehicle; @@ -17,7 +18,7 @@ use App\Entity\Vehicle; use App\Service\HashGenerator; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class CustomerController extends APIController { diff --git a/src/Controller/CAPI/CustomerWarrantyController.php b/src/Controller/CAPI/CustomerWarrantyController.php index c5562d40..4482bbd1 100644 --- a/src/Controller/CAPI/CustomerWarrantyController.php +++ b/src/Controller/CAPI/CustomerWarrantyController.php @@ -10,8 +10,8 @@ use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Service\RisingTideGateway; use App\Service\WarrantyAPILogger; @@ -37,7 +37,7 @@ use App\Ramcar\WarrantySource; use DateTime; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; // third party API class CustomerWarrantyController extends APIController diff --git a/src/Controller/CAPI/DealerController.php b/src/Controller/CAPI/DealerController.php index c59e4a54..798898a4 100644 --- a/src/Controller/CAPI/DealerController.php +++ b/src/Controller/CAPI/DealerController.php @@ -6,12 +6,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Dealer; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class DealerController extends APIController { diff --git a/src/Controller/CAPI/MunicipalityController.php b/src/Controller/CAPI/MunicipalityController.php index 8345cd45..6ad82ebf 100644 --- a/src/Controller/CAPI/MunicipalityController.php +++ b/src/Controller/CAPI/MunicipalityController.php @@ -6,12 +6,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Municipality; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class MunicipalityController extends APIController { diff --git a/src/Controller/CAPI/PrivacyPolicyController.php b/src/Controller/CAPI/PrivacyPolicyController.php index 034d12ff..80d8e167 100644 --- a/src/Controller/CAPI/PrivacyPolicyController.php +++ b/src/Controller/CAPI/PrivacyPolicyController.php @@ -7,12 +7,12 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\PrivacyPolicy; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; // third party API class PrivacyPolicyController extends APIController diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 6a6d3d91..7aa5650d 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -11,8 +11,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Component\Response as APIResponse; use App\Entity\Rider; use App\Entity\JOEvent; @@ -22,11 +22,13 @@ use App\Entity\BatteryModel; use App\Entity\BatterySize; use App\Entity\RiderAPISession; use App\Entity\User; -use Catalyst\APIBundle\Entity\User as APIUser; +use App\Entity\ApiUser as APIUser; use App\Service\RedisClientProvider; use App\Service\RiderCache; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\WarrantyHandler; use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; @@ -437,7 +439,7 @@ class RiderAppController extends APIController } - public function cancelJobOrder(Request $req, EntityManagerInterface $em, MQTTClient $mclient) + public function cancelJobOrder(Request $req, EntityManagerInterface $em, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { $required_params = ['jo_id']; @@ -483,6 +485,10 @@ class RiderAppController extends APIController ]; $mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + $data = []; return new APIResponse(true, 'Job order requeued.', $data); } @@ -648,7 +654,7 @@ class RiderAppController extends APIController } - public function arrive(Request $req, EntityManagerInterface $em, MQTTClient $mclient) + public function arrive(Request $req, EntityManagerInterface $em, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { $required_params = ['jo_id']; @@ -698,6 +704,10 @@ class RiderAppController extends APIController ]; $mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_driver_arrived", "jo_fcm_body_driver_arrived"); + $data = []; return new APIResponse(true, 'Rider arrived at customer location.', $data); } @@ -749,7 +759,7 @@ class RiderAppController extends APIController } public function payment(Request $req, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler, - RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, TranslatorInterface $translator) + RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, TranslatorInterface $translator) { $required_params = ['jo_id']; @@ -871,6 +881,10 @@ class RiderAppController extends APIController ]; $mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_fulfilled", "jo_fcm_body_fulfilled"); + $data = []; return new APIResponse(true, 'Job order paid and fulfilled.', $data); } diff --git a/src/Controller/CAPI/TestController.php b/src/Controller/CAPI/TestController.php index 9604c056..0db0754b 100644 --- a/src/Controller/CAPI/TestController.php +++ b/src/Controller/CAPI/TestController.php @@ -5,8 +5,8 @@ namespace App\Controller\CAPI; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; class TestController extends APIController { diff --git a/src/Controller/CAPI/VehicleController.php b/src/Controller/CAPI/VehicleController.php index 1f3b13b4..e0aec499 100644 --- a/src/Controller/CAPI/VehicleController.php +++ b/src/Controller/CAPI/VehicleController.php @@ -6,12 +6,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Vehicle; use App\Entity\VehicleManufacturer; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class VehicleController extends APIController { diff --git a/src/Controller/CAPI/WarrantyController.php b/src/Controller/CAPI/WarrantyController.php index 3d9ab97b..63fe972b 100644 --- a/src/Controller/CAPI/WarrantyController.php +++ b/src/Controller/CAPI/WarrantyController.php @@ -7,8 +7,8 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Warranty; use App\Entity\BatteryModel; @@ -33,7 +33,7 @@ use App\Ramcar\WarrantySource; use DateTime; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; // third party API class WarrantyController extends APIController diff --git a/src/Controller/CAPI/WarrantySerialController.php b/src/Controller/CAPI/WarrantySerialController.php index c845e367..675eabc7 100644 --- a/src/Controller/CAPI/WarrantySerialController.php +++ b/src/Controller/CAPI/WarrantySerialController.php @@ -10,8 +10,8 @@ use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\WarrantySerialQueue; @@ -19,7 +19,7 @@ use App\Service\WarrantySerialUploadLogger; use DateTime; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; // third party API class WarrantySerialController extends APIController diff --git a/src/Controller/CustomerAppAPI/ApiController.php b/src/Controller/CustomerAppAPI/ApiController.php new file mode 100644 index 00000000..cc742d19 --- /dev/null +++ b/src/Controller/CustomerAppAPI/ApiController.php @@ -0,0 +1,166 @@ +session = new CustomerSession; // NOTE: original was null + $this->em = $em; + + // load env file + $dotenv = new Dotenv(); + $dotenv->loadEnv($kernel->getProjectDir() . '/.env'); + } + + protected function debugRequest(Request $req) + { + $all = $req->request->all(); + error_log(print_r($all, true)); + } + + protected function hasMissingParams(Request $req, $params = []) + { + return $this->checkRequiredParameters($req, $params); + } + + protected function validateSession($session_key) + { + // check if the session exists + $session = $this->em->getRepository(CustomerSession::class)->find($session_key); + if ($session === null) { + return false; + } + + $this->session = $session; + return true; + } + + protected function validateRequest(Request $req, $params = []) + { + $error = $this->hasMissingParams($req, $params); + $session_key = $req->query->get('session_key'); + + if (!$error) { + if (empty($session_key) || !$this->validateSession($session_key)) { + $error = 'Invalid session key.'; + } + } + + return [ + 'is_valid' => !$error, + 'error' => $error, + ]; + } + + protected function findWarranty($plate_number) + { + // NOTE: Modify the search for the latest warranty. This seems hacky. + // get latest warranty using plate number + $warranty_results = $this->em->getRepository(Warranty::class)->findBy( + ['plate_number' => $plate_number], + ['date_create' => 'desc'] + ); + + $warr = []; + + // check if warranty_results is empty + if (empty($warranty_results)) { + /* + $res->setError(true) + ->setErrorMessage('No warranty found for plate number'); + return $res->getReturnResponse(); + */ + + return $warr; + } + + // get first entry + $warranty = current($warranty_results); + + // check for null values for battery and date claim and date expire + $batt_model = ''; + $batt_size = ''; + $sap_batt = ''; + $claim_date = ''; + $expiry_date = ''; + + if (!(is_null($warranty->getBatteryModel()))) { + $batt_model = $warranty->getBatteryModel()->getName(); + } + if (!(is_null($warranty->getBatterySize()))) { + $batt_size = $warranty->getBatterySize()->getName(); + } + if (!(is_null($warranty->getSAPBattery()))) { + $sap_batt = $warranty->getSAPBattery()->getID(); + } + if (!(is_null($warranty->getDateClaim()))) { + $claim_date = $warranty->getDateClaim()->format("d M Y"); + } + if (!(is_null($warranty->getDateExpire()))) { + $expiry_date = $warranty->getDateExpire()->format("d M Y"); + } + + $warr[] = [ + 'id' => $warranty->getID(), + 'serial' => $warranty->getSerial(), + 'warranty_class' => $warranty->getWarrantyClass(), + 'plate_number' => $warranty->getPlateNumber(), + 'first_name' => $warranty->getFirstName(), + 'last_name' => $warranty->getLastName(), + 'mobile_number' => $warranty->getMobileNumber(), + 'battery_model' => $batt_model, + 'battery_size' => $batt_size, + 'sap_battery' => $sap_batt, + 'status' => $warranty->getStatus(), + 'date_create' => $warranty->getDateCreate()->format("d M Y g:i A"), + 'date_purchase' => $warranty->getDatePurchase()->format("d M Y"), + 'date_expire' => $expiry_date, + 'date_claim' => $claim_date, + 'claim_from' => $warranty->getClaimedFrom(), + 'is_activated' => $warranty->isActivated() ? 1 : 0, + ]; + + return $warr; + } + + protected function getBatteryImageURL($req, $batt) + { + // TODO: workaround for now, we get static image of battery based on model name + $filename = trim(strtolower($batt->getModel()->getName())) . '_mobile.jpg'; + $file_path = $req->getSchemeAndHttpHost() . $this->generateUrl('static_battery_image') . '/' . $filename; + + return $file_path; + } + + protected function getOngoingJobOrders($cust) + { + $ongoing_jos = $this->em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::IN_TRANSIT, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], + ], ['date_schedule' => 'desc']); + + return $ongoing_jos; + } + + protected function getGeoErrorMessage() + { + return 'Oops! Our service is limited to some areas in Metro Manila, Laguna, Cavite, Pampanga and Baguio only. We will update you as soon as we are able to cover your area'; + } +} diff --git a/src/Controller/CustomerAppAPI/AppController.php b/src/Controller/CustomerAppAPI/AppController.php new file mode 100644 index 00000000..c78eba43 --- /dev/null +++ b/src/Controller/CustomerAppAPI/AppController.php @@ -0,0 +1,49 @@ +hasMissingParams($req, [ + 'version', + ]); + + if ($missing) { + return new ApiResponse(false, $missing); + } + + $need_update = false; + $msg = 'Version is up to date.'; + + $api_version = $this->getParameter('api_version'); + + $app_version = $req->query->get('version'); + // putting this in for the future, in case we have diverging versions + $os = $req->query->get('os'); + $platform = $req->query->get('platform'); + + $api_v = explode('.', $api_version); + $app_v = explode('.', $app_version); + + if ($api_v[0] < $app_v[0]) { + return new ApiResponse(false, 'Invalid application version: ' . $app_version); + } + + if ($api_v[0] > $app_v[0]) { + $need_update = true; + $msg = 'Your version is outdated and needs an update to use the latest features RES-Q has to offer.'; + } + + // response + return new ApiResponse(true, '', [ + 'need_update' => $need_update, + 'message' => $msg, + ]); + } +} diff --git a/src/Controller/CustomerAppAPI/AuthController.php b/src/Controller/CustomerAppAPI/AuthController.php new file mode 100644 index 00000000..128de8a8 --- /dev/null +++ b/src/Controller/CustomerAppAPI/AuthController.php @@ -0,0 +1,290 @@ +hasMissingParams($req, [ + 'phone_model', + 'os_type', + 'os_version', + 'phone_id', + ]); + + if ($missing) { + return new ApiResponse(false, $missing); + } + + // retry until we get a unique id + while (true) { + try { + // instantiate session + $sess = new CustomerSession(); + $sess->setPhoneModel($req->request->get('phone_model')) + ->setOSType($req->request->get('os_type')) + ->setOSVersion($req->request->get('os_version')) + ->setPhoneID($req->request->get('phone_id')); + + // reopen in case we get an exception + if (!$this->em->isOpen()) { + $this->em = $this->em->create( + $this->em->getConnection(), + $this->em->getConfiguration() + ); + } + + // save + $this->em->persist($sess); + $this->em->flush(); + } catch (DBALException $e) { + error_log($e->getMessage()); + // delay one second and try again + sleep(1); + continue; + } + + break; + } + + // return data + return new ApiResponse(true, '', [ + 'session_key' => $sess->getID(), + ]); + } + + public function confirmNumber(RisingTideGateway $rt, Request $req, TranslatorInterface $translator) + { + // validate request + $validity = $this->validateRequest($req, [ + 'phone_number' + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // phone number + $phone_number = $req->request->get('phone_number'); + + // get otp_mode from .env + $otp_mode = $_ENV['OTP_MODE']; + + // check for hardcoded phone number for app store testing + if ($phone_number == '639221111111') { + $code = '123456'; + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $this->em->flush(); + + return new ApiResponse(); + } + + // check if otp_mode is test + if ($otp_mode == 'test') { + $code = '123456'; + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $this->em->flush(); + + return new ApiResponse(); + } + + // TODO: spam protection + + // TODO: validate phone number + + // generate code and save + $code = $this->generateConfirmCode(); + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $this->em->flush(); + + if ($otp_mode != 'test') { + // send sms to number + $this->sendConfirmationCode($rt, $phone_number, $code, $translator); + } + + // response + return new ApiResponse(); + } + + public function validateCode(Request $req) + { + // validate request + $validity = $this->validateRequest($req, [ + 'code', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // already confirmed + if ($this->session->isConfirmed()) { + return new ApiResponse(false, 'User is already confirmed.'); + } + + // code is wrong + $code = $req->request->get('code'); + if ($this->session->getConfirmCode() != $code) { + return new ApiResponse(false, 'Wrong confirm code.'); + } + + // set confirm date + $date = new DateTime(); + $this->session->setDateConfirmed($date) + ->setConfirmed(); + + // figure out if we have customer and customer user already + $customer_user = false; + + // TODO: check if we have the number registered before and merge + $dupe_sess = $this->findNumberSession($this->session->getPhoneNumber()); + if ($dupe_sess != null) { + error_log("Found existing customer session for " . $this->session->getPhoneNumber()); + $dupe_cust = $dupe_sess->getCustomer(); + $this->session->setCustomer($dupe_cust); + + // set customer user if it exists + $customer_user = $dupe_sess->getCustomerUser() ?? $dupe_cust->getCustomerUser(); + } + + // TODO: check if mobile matches mobile of customer + $customer = $this->findCustomerByNumber($this->session->getPhoneNumber()); + if ($customer != null) { + // TODO: if there is a dupe_sess, do we need to check if + // dupe_cust is the same as the customer we found? + $this->session->setCustomer($customer); + } + + if (!$customer_user) { + error_log("We don't have a customer user for session " . $this->session->getID()); + + $customer_user = $this->findCustomerUserByNumber($this->session->getPhoneNumber()); + + if ($customer_user === null) { + error_log("Creating a new customer user for " . $this->session->getPhoneNumber()); + $customer_user = new CustomerUser(); + $customer_user->setCustomer($this->session->getCustomer()) + ->setPhoneNumber($this->session->getPhoneNumber()); + + // save + $this->em->persist($customer_user); + $this->em->flush(); + } else { + error_log("Found existing customer user for " . $this->session->getPhoneNumber()); + } + } + + error_log("Customer user ID is " . $customer_user->getID()); + + // set session customer user + $this->session->setCustomerUser($customer_user); + $this->em->flush(); + + // response + return new ApiResponse(true, '', [ + 'api_key' => $customer_user->getApiKey(), + 'secret_key'=> $customer_user->getSecretKey(), + ]); + } + + public function resendCode(Request $req, RisingTideGateway $rt, TranslatorInterface $translator) + { + // validate request + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // already confirmed + if ($this->session->isConfirmed()) { + return new ApiResponse(false, 'User is already confirmed.'); + } + + // have sent code before + if ($this->session->getDateCodeSent() != null) { + return new ApiResponse(false, 'Can only send confirm code every 5 mins.'); + } + + // TODO: send via sms + $phone_number = $this->session->getPhoneNumber(); + $code = $this->session->getConfirmCode(); + $this->sendConfirmationCode($rt, $phone_number, $code, $translator); + + // response + return new ApiResponse(); + } + + protected function generateConfirmCode() + { + return sprintf("%06d", mt_rand(100000, 999999)); + } + + protected function sendConfirmationCode(RisingTideGateway $rt, $phone_number, $code, TranslatorInterface $translator) + { + // send sms to number + $message = $translator->trans('message.confirmation_code') . ' ' . $code; + $rt->sendSMS($phone_number, $translator->trans('message.battery_brand_allcaps'), $message); + } + + // TODO: find session customer by phone number + protected function findNumberSession($number) + { + $query = $this->em->getRepository(CustomerSession::class)->createQueryBuilder('s') + ->where('s.phone_number = :number') + ->andWhere('s.customer is not null') + ->andWhere('s.customer_user is not null') + ->andWhere('s.confirm_flag = 1') + ->setParameter('number', $number) + ->setMaxResults(1) + ->getQuery(); + + // we just need one + $res = $query->getOneOrNullResult(); + + return $res; + } + + protected function findCustomerByNumber($number) + { + $customers = $this->em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]); + + // find the customer with the most number of cars + $car_count = 0; + $cust = null; + + foreach ($customers as $customer) { + $vehicles = $customer->getVehicles(); + if (count($vehicles) > $car_count) { + $car_count = count($vehicles); + + // "save" customer object + $cust = $customer; + } + } + + return $cust; + } + + protected function findCustomerUserByNumber($number) + { + return $this->em->getRepository(CustomerUser::class)->findOneBy(['phone_number' => $number]); + } +} diff --git a/src/Controller/CustomerAppAPI/CustomerController.php b/src/Controller/CustomerAppAPI/CustomerController.php new file mode 100644 index 00000000..4ba7279c --- /dev/null +++ b/src/Controller/CustomerAppAPI/CustomerController.php @@ -0,0 +1,145 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // if no customer found + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(true, '', [ + 'first_name' => '', + 'last_name' => '', + 'priv_third_party' => (bool) false, + 'priv_promo' => (bool) false, + ]); + } + + // send back customer details + return new ApiResponse(true, '', [ + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'priv_third_party' => (bool) $cust->getPrivacyThirdParty(), + 'priv_promo' => (bool) $cust->getPrivacyPromo(), + ]); + } + + public function updateInfo(Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'first_name', + 'last_name', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $cust = $this->updateCustomerInfo($req); + + $policy_mobile_id = $_ENV['POLICY_MOBILE']; + $mobile_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_mobile_id); + + // set policy id + if ($mobile_policy != null) { + $cust->setPrivacyPolicyMobile($mobile_policy); + } + + $this->em->flush(); + + // response + return new ApiResponse(); + } + + public function getStatus(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // set data + $data = []; + if ($this->session->isConfirmed()) { + $data['status'] = 'confirmed'; + } else { + $data['status'] = 'unconfirmed'; + } + + return new ApiResponse(true, '', $data); + } + + public function getCustomerHash(Request $req, HashGenerator $hash) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // hash customer id + $hashed_id = $hash->getHash($cust->getID()); + + // response + return new ApiResponse(true, '', [ + 'cust_hash' => $hashed_id, + ]); + } + + protected function updateCustomerInfo(Request $req) + { + // create new customer if it's not there + $cust = $this->session->getCustomer(); + if ($cust == null) { + $cust = new Customer(); + + // set customer source + $cust->setCreateSource(CustomerSource::MOBILE); + $this->em->persist($cust); + + $this->session->setCustomer($cust); + } + + $cust->setFirstName($req->request->get('first_name')) + ->setLastName($req->request->get('last_name')) + ->setEmail($req->request->get('email', '')) + ->setConfirmed($this->session->isConfirmed()); + + // if customer user isn't set, set it now + if ($cust->getCustomerUser() == null) { + $cust->setCustomerUser($this->session->getCustomerUser()); + } + + // update mobile phone of customer + $cust->setPhoneMobile($this->session->getPhoneNumber()); + + return $cust; + } +} diff --git a/src/Controller/CustomerAppAPI/DeviceController.php b/src/Controller/CustomerAppAPI/DeviceController.php new file mode 100644 index 00000000..b09acf18 --- /dev/null +++ b/src/Controller/CustomerAppAPI/DeviceController.php @@ -0,0 +1,29 @@ +validateRequest($req, [ + 'device_id', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $device_id = $req->request->get('device_id'); + $this->session->setDevicePushID($device_id); + + $this->em->flush(); + + // response + return new ApiResponse(); + } +} diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php new file mode 100644 index 00000000..1c8ab6c6 --- /dev/null +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -0,0 +1,132 @@ +debugRequest($req); + + // validate params + $validity = $this->validateRequest($req, [ + 'service_type', + 'cv_id', + // 'batt_id', + 'trade_in', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // make invoice criteria + $icrit = new InvoiceCriteria(); + $icrit->setServiceType($req->request->get('service_type')); + + // check promo + $promo_id = $req->request->get('promo_id'); + if (!empty($promo_id)) { + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) { + return new ApiResponse(false, 'Invalid promo id.'); + } + + // put in criteria + $icrit->addPromo($promo); + } + + // check customer vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); + if ($cv == null) { + return new ApiResponse(false, 'Invalid customer vehicle id.'); + } + $icrit->setCustomerVehicle($cv); + + // check if customer owns vehicle + if ($cust->getID() != $cv->getCustomer()->getID()) { + return new ApiResponse(false, 'Customer does not own vehicle.'); + } + + // check battery + $batt_id = $req->request->get('batt_id'); + if ($batt_id != null) { + $batt = $this->em->getRepository(Battery::class)->find($batt_id); + if ($batt == null) { + return new ApiResponse(false, 'Invalid battery id.'); + } + } else + $batt = null; + + /* + // put battery in criteria + $icrit->addBattery($batt); + */ + + // check trade-in + // only allow motolite, other, none + $trade_in = $req->request->get('trade_in'); + switch ($trade_in) { + case TradeInType::MOTOLITE: + case TradeInType::OTHER: + break; + + default: + $trade_in = ''; + break; + } + + $icrit->addEntry($batt, $trade_in, 1); + + // send to invoice generator + $invoice = $ic->generateInvoice($icrit); + + // make invoice json data + $data = [ + 'total_price' => (float) $invoice->getTotalPrice(), + 'vat_ex_price' => (float) $invoice->getVATExclusivePrice(), + 'vat' => (float) $invoice->getVAT(), + 'discount' => (float) $invoice->getDiscount(), + 'trade_in' => (float) $invoice->getTradeIn(), + ]; + $items = $invoice->getItems(); + $items_data = []; + foreach ($items as $item) { + $my_data = [ + 'title' => $item->getTitle(), + 'qty' => (int) $item->getQuantity() + 0, + 'price' => (float) $item->getPrice() + 0.0, + ]; + + $item_batt = $item->getBattery(); + if ($item_batt != null) { + $my_data['image_url'] = $this->getBatteryImageURL($req, $item_batt); + } + + $items_data[] = $my_data; + } + + $data['items'] = $items_data; + + // error_log(print_r($data, true)); + + // response + return new ApiResponse(true, '', $data); + } +} diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php new file mode 100644 index 00000000..4ddb40ee --- /dev/null +++ b/src/Controller/CustomerAppAPI/JobOrderController.php @@ -0,0 +1,1670 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + /* + // check if we have an ongoing job order + $ongoing_jos = $this->em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::IN_TRANSIT, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], + ]); + */ + $ongoing_jos = $this->getOngoingJobOrders($cust); + + // initialize data + $data = []; + + // no ongoing + if (count($ongoing_jos) <= 0) { + $data = [ + 'has_ongoing' => false, + ]; + } else { + $data = [ + 'has_ongoing' => true, + ]; + } + + // response + return new ApiResponse(true, '', $data); + } + + public function getJOInvoice(Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'jo_id', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get job order + $jo_id = $req->query->get('jo_id'); + $jo = $this->em->getRepository(JobOrder::class)->find($jo_id); + if ($jo == null) { + return new ApiResponse(false, 'No job order found.'); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // check that the customer owns the job order + $jo_cust = $jo->getCustomer(); + if ($jo_cust->getID() != $cust->getID()) { + return new ApiResponse(false, 'Job order was not initiated by customer.'); + } + + $invoice = $jo->getInvoice(); + + // make invoice json data + $data = [ + 'total_price' => (float) $invoice->getTotalPrice(), + 'vat_ex_price' => (float) $invoice->getVATExclusivePrice(), + 'vat' => (float) $invoice->getVAT(), + 'discount' => (float) $invoice->getDiscount(), + 'trade_in' => (float) $invoice->getTradeIn(), + ]; + $items = $invoice->getItems(); + $items_data = []; + foreach ($items as $item) { + $my_data = [ + 'title' => $item->getTitle(), + 'qty' => (int) $item->getQuantity() + 0, + 'price' => (float) $item->getPrice() + 0.0, + ]; + + $item_batt = $item->getBattery(); + if ($item_batt != null) { + $my_data['image_url'] = $this->getBatteryImageURL($req, $item_batt); + } + + $items_data[] = $my_data; + } + + $data['items'] = $items_data; + + /* + // invoice items + $inv_items = []; + foreach ($inv->getItems() as $item) + { + $item_batt = $item->getBattery(); + if ($item_batt == null) + $batt_id = null; + else + $batt_id = $item_batt->getID(); + + $inv_items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + 'batt_id' => $batt_id, + ]; + } + + $data = [ + 'invoice' => [ + 'discount' => $inv->getDiscount(), + 'trade_in' => $inv->getTradeIn(), + 'total_price' => $inv->getTotalPrice(), + 'vat' => $inv->getVat(), + 'items' => $inv_items, + ], + ]; + + */ + + // response + return new ApiResponse(true, '', $data); + } + + public function cancelJobOrder(Request $req, MQTTClient $mclient) + { + // validate params + $validity = $this->validateRequest($req, [ + 'jo_id', + 'reason', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get job order + $jo_id = $req->request->get('jo_id'); + $jo = $this->em->getRepository(JobOrder::class)->find($jo_id); + if ($jo == null) { + return new ApiResponse(false, 'No job order found.'); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // check that the customer owns the job order + $jo_cust = $jo->getCustomer(); + if ($jo_cust->getID() != $cust->getID()) { + return new ApiResponse(false, 'Job order was not initiated by customer.'); + } + + // TODO: check job order status, if it's cancellable + $cancel_reason = $req->request->get('reason'); + + $jo->cancel($cancel_reason); + + // add event log + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::CANCEL) + ->setJobOrder($jo); + $this->em->persist($event); + + $this->em->flush(); + + // send mobile app event + $payload = [ + 'event' => 'cancelled', + 'reason' => $cancel_reason, + 'jo_id' => $jo->getID(), + ]; + // $mclient->sendEvent($jo, $payload); + $mclient->sendRiderEvent($jo, $payload); + + // response + return new ApiResponse(); + } + + // we can't use param converter for now because we want to output the proper 404 + public function getJobOrderInfo($id, Request $req, RiderTracker $rt) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get job order data + $jo = $this->em->getRepository(JobOrder::class)->find($id); + if ($jo == null) { + return new ApiResponse(false, 'No job order information found.'); + } + + // check if job order belongs to customer / user + if ($cust->getID() != $jo->getCustomer()->getID()) { + return new ApiResponse(false, 'No job order information found.'); + } + + // put into job order data array + $jo_data = $this->generateJobOrderData($req, $jo, $rt); + + // response + return new ApiResponse(true, '', [ + 'job_order' => $jo_data, + ]); + } + + public function getJOHistory(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get job orders + $all_jo_data = []; + // $jos = $cust->getJobOrders(); + // get the fulfilled and cancelled job orders, since ongoing jos are not yet part of history + $jos = $this->em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::CANCELLED, JOStatus::FULFILLED] + ], ['date_schedule' => 'DESC']); + foreach ($jos as $jo) { + // NOTE: use generateJobOrderData method, maybe? + $status = $jo->getStatus(); + + $jo_data = [ + 'id' => $jo->getID(), + 'date_create' => $jo->getDateCreate()->format('M d, Y'), + 'service_type' => $jo->getServiceType(), + 'status' => $status, + ]; + + // customer vehicle and warranty + $cv = $jo->getCustomerVehicle(); + + // get latest warranty using plate number + $warranty = $this->findWarranty($cv->getPlateNumber()); + + $jo_data['customer_vehicle'] = [ + 'id' => $cv->getID(), + 'plate_number' => $cv->getPlateNumber(), + 'warranty' => $warranty, + ]; + + // rider + $rider = $jo->getRider(); + + // check if jo has rider rating set to true + $has_rider_rating = $jo->hasRiderRating(); + $rating = 0; + $comment = ''; + if ($rider != null) { + $jo_data['rider'] = $rider->getFullName(); + + // find the rider rating if any + if ($has_rider_rating) { + $jo_rating = $jo->getRating(); + if ($jo_rating != null) { + $rating = $jo_rating->getRating(); + + // get comment + $comment = $jo_rating->getComment(); + } + } + } + + // rider rating for jo + $jo_data['has_rider_rating'] = $has_rider_rating; + $jo_data['rider_rating'] = $rating; + $jo_data['comment'] = $comment; + + // invoice items + $items = []; + $jo_items = $jo->getInvoice()->getItems(); + foreach ($jo_items as $item) { + $items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + ]; + } + + $jo_data['items'] = $items; + + // dates depending on status + switch ($status) { + case JOStatus::FULFILLED: + if ($jo->getDateFulfill() == null) + $jo_data['date_fulfilled'] = ''; + else + $jo_data['date_fulfilled'] = $jo->getDateFulfill()->format('M d, Y'); + break; + case JOStatus::CANCELLED: + $date_cancel = $jo->getDateCancel(); + if ($date_cancel == null) + $date_cancel = new DateTime(); + $jo_data['date_cancelled'] = $date_cancel->format('M d, Y'); + break; + } + + $all_jo_data[] = $jo_data; + } + + // response + return new ApiResponse(true, '', [ + 'job_orders' => $all_jo_data, + ]); + } + + public function getLatestJobOrder(Request $req, RiderTracker $rt) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get the latest job order for customer + $latest_jo = $this->em->getRepository(JobOrder::class)->findOneBy(['customer' => $cust], ['id' => 'DESC']); + + $jo_data = null; + if ($latest_jo != null) { + // TODO: clean the response up to just return what is needed + $jo_data = $this->generateLatestJobOrderData($req, $latest_jo, $rt); + } + + // response + return new ApiResponse(true, '', [ + 'latest_job_order' => $jo_data, + ]); + } + + public function getAllOngoingJobOrders(Request $req, RiderTracker $rt) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + $ongoing_jos = $this->getOngoingJobOrders($cust); + + // initialize data + $jo_data = []; + foreach ($ongoing_jos as $jo) { + $jo_data[] = $this->generateJobOrderData($req, $jo, $rt); + } + + // response + return new ApiResponse(true, '', [ + 'ongoing_job_orders' => $jo_data, + ]); + } + + public function getOngoingJobOrderCount(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + $ongoing_jos = $this->getOngoingJobOrders($cust); + + // response + return new ApiResponse(true, '', [ + 'ongoing_job_order_count' => count($ongoing_jos), + ]); + } + + public function newRequestJobOrder( + Request $req, + InvoiceGeneratorInterface $ic, + GeofenceTracker $geo, + MapTools $map_tools, + InventoryManager $im, + MQTTClientApiv2 $mclientv2, + FCMSender $fcmclient, + RiderAssignmentHandlerInterface $rah, + PromoLogger $promo_logger, + HubSelector $hub_select, + HubDistributor $hub_dist, + HubFilterLogger $hub_filter_logger, + HubFilteringGeoChecker $hub_geofence + ) { + // validate params + $validity = $this->validateRequest($req, [ + 'service_type', + 'cv_id', + 'trade_in', + 'long', + 'lat', + 'warranty', + 'mode_of_payment', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // trade in type + $trade_in = $req->request->get('trade_in'); + + // address + $address = $req->request->get('delivery_address', 'Set by mobile application'); + + // instructions + $instructions = $req->request->get('delivery_instructions', ''); + + // landmark + $landmark = $req->request->get('landmark', ''); + + // longitude and latitude + $long = $req->request->get('long'); + $lat = $req->request->get('lat'); + + // NOTE: had to move this up so we can check for promo before geofence + // customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + $is_covered = false; + // check if customer still has promo + if (($cust->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) || + ($cust->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO')) + ) { + // if has customer tag, customer has not availed of promo + $is_covered = true; + } else { + // geofence + $is_covered = $geo->isCovered($long, $lat); + } + + if (!$is_covered) { + // TODO: put geofence error message in config file somewhere + return new ApiResponse(false, $this->getGeoErrorMessage()); + } + + $hub = null; + $hub_id = $req->request->get('hub_id'); + // check if hub_id is -1 which means user clicked Book Now before 5 PM + // but confirmed the order after 5 PM + if ($hub_id == -1) { + return new ApiResponse(false, 'Book Now no longer available.'); + } + if (strlen($hub_id) > 0) + $hub = $this->em->getRepository(Hub::class)->find($hub_id); + + $schedule_date = $req->request->get('date_schedule'); + $slot_id = $req->request->get('slot_id'); + + // process the jo date schedule + $date_schedule = null; + if ((strlen($schedule_date) > 0) && (strlen($slot_id) > 0)) { + $time_schedule = $this->getTimeFromSlot($slot_id); + if (!empty($time_schedule)) { + $s_date = $schedule_date . ' ' . $time_schedule; + $date_schedule = DateTime::createFromFormat('Y-m-d H:i', $s_date); + // error_log($date_schedule->format('Y-m-d H:i')); + } + } + + $advance_order = $req->request->get('flag_advance_order'); + // check for 'false' text + if ($advance_order === false || $advance_order === 0 || $advance_order === '0' || $advance_order == 'false') + $flag_advance_order = false; + else + $flag_advance_order = true; + // $flag_advance_order = $advance_order ? true : false; + + $jo = new JobOrder(); + $jo->setSource(TransactionOrigin::MOBILE_APP) + ->setStatus(JOStatus::PENDING) + ->setDeliveryInstructions('') + ->setTier1Notes('') + ->setTier2Notes('') + ->setDeliveryAddress($address) + ->setTradeInType($trade_in) + ->setDeliveryInstructions($instructions) + // TODO: error check for valid mode of payment + ->setModeOfPayment($req->request->get('mode_of_payment')) + ->setAdvanceOrder($flag_advance_order) + ->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED) + ->setLandmark($landmark); + + // customer + // $cust = $this->session->getCustomer(); + // if ($cust == null) + // { + // $res->setError(true) + // ->setErrorMessage('No customer information found'); + // return $res->getReturnResponse(); + // } + $jo->setCustomer($cust); + + // validate service type + $stype = $req->request->get('service_type'); + if (!ServiceType::validate($stype)) { + return new ApiResponse(false, 'Invalid service type.'); + } + $jo->setServiceType($stype); + + // validate warranty + $warr = $req->request->get('warranty'); + if (!WarrantyClass::validate($warr)) { + return new ApiResponse(false, 'Invalid warranty class.'); + } + $jo->setWarrantyClass($warr); + + // set coordinates + $point = new Point($long, $lat); + $jo->setCoordinates($point); + + // make invoice criteria + $icrit = new InvoiceCriteria(); + $icrit->setServiceType($stype); + + // check promo + $promo_id = $req->request->get('promo_id'); + if (!empty($promo_id)) { + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) { + return new ApiResponse(false, 'Invalid promo id.'); + } + + // put in criteria + $icrit->addPromo($promo); + } + + // check customer vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); + if ($cv == null) { + return new ApiResponse(false, 'Invalid customer vehicle id.'); + } + $icrit->setCustomerVehicle($cv); + $jo->setCustomerVehicle($cv); + + // check if customer owns vehicle + if ($cust->getID() != $cv->getCustomer()->getID()) { + return new ApiResponse(false, 'Customer does not own vehicle.'); + } + + // check battery + $batt_id = $req->request->get('batt_id'); + if ($batt_id != null) { + $batt = $this->em->getRepository(Battery::class)->find($batt_id); + if ($batt == null) { + return new ApiResponse(false, 'Invalid battery id.'); + } + } else + $batt = null; + + /* + // put battery in criteria + $icrit->addBattery($batt); + */ + + // check trade-in + // only allow motolite, other, none + switch ($trade_in) { + case TradeInType::MOTOLITE: + case TradeInType::OTHER: + break; + + default: + $trade_in = ''; + break; + } + + $icrit->addEntry($batt, $trade_in, 1); + + // send to invoice generator + $invoice = $ic->generateInvoice($icrit); + $jo->setInvoice($invoice); + + // assign hub and rider + // check if hub is null + if ($hub == null) { + // TODO: need to factor out the setting of HubCriteria fields + $hub_criteria = new HubCriteria(); + $hub_criteria->setPoint($jo->getCoordinates()); + + // get distance limit for mobile from env + // get value of hub_filter_enable from env + $limit_distance = $_ENV['CUST_DISTANCE_LIMIT']; + $hub_filter_enabled = $_ENV['HUB_FILTER_ENABLE']; + + // set distance limit + $hub_criteria->setLimitDistance($limit_distance); + + // check if hub filter is enabled. If not, use default values + // for the rest of the HubCriteria fields + if ($hub_filter_enabled == 'true') { + // error_log('hub filter is enabled'); + // check if customer location is in hub filter area + if ($hub_geofence->isCovered($long, $lat)) { + // if true, set other values for HubCriteria + // TODO: set this properly, since the other flags + // are on default values + // error_log('Area is covered by hub filtering'); + $hub_criteria->setJoType($jo->getServiceType()) + ->setPaymentMethod($jo->getModeOfPayment()) + ->setRoundRobin(true); + } + } + + // check if batt is null + if ($batt != null) { + // add battery to items + $sku = $batt->getSAPCode(); + if (!empty($sku)) + $hub_criteria->addItem($batt->getSAPCode(), 1); + } + + // get customer id. No JO id at this point + $customer_id = $cust->getID(); + + $hub_criteria->setCustomerId($customer_id); + + // find nearest hubs + $nearest_hubs = $hub_select->find($hub_criteria); + + if (!empty($nearest_hubs)) { + // go through the hub list, find the nearest hub + // with an available rider + // error_log('found nearest hub ' . $nearest_hub->getID()); + foreach ($nearest_hubs as $nearest_hub) { + // check if hub can be auto assigned + // if not, move on to the next hub in the list + if (($nearest_hub['hub']->isHubAutoAssign())) { + // check if hub has riders that can be auto assigned + // if not, move on to the next hub + if (($nearest_hub['hub']->isRiderAutoAssign())) { + $available_riders = $nearest_hub['hub']->getAvailableRiders(); + if (count($available_riders) >= 1) { + $assigned_rider = null; + if (count($available_riders) == 1) { + $assigned_rider = $available_riders[0]; + } else { + // TODO: the setting of riders into an array + // will no longer be necessary when the contents + // of randomizeRider changes + $riders = []; + foreach ($available_riders as $rider) { + $riders[] = $rider; + } + + $assigned_rider = $this->randomizeRider($riders); + } + + $jo->setHub($nearest_hub['hub']); + $jo->setRider($assigned_rider); + $jo->setStatus(JOStatus::ASSIGNED); + $jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED); + $jo->setDeliveryStatus(DeliveryStatus::RIDER_ASSIGN); + + // set date_assigned for job order + $jo->setDateAssign(new DateTime()); + + $assigned_rider->setAvailable(false); + + // set rider's current job order + $assigned_rider->setCurrentJobOrder($jo); + + // update redis hub_jo_count for hub + $hub_dist->incrementJoCountForHub($nearest_hub['hub']); + + // break out of loop + break; + } else { + // we just create the JO and let admin panel handle the hub assignment + // log hub into hub_filter_log + $hub_filter_logger->logFilteredHub($nearest_hub['hub'], 'no_available_rider', null, $cust->getID()); + // continue to go through list to find hub with an available rider + } + } else { + // TODO: log hub as cannot be auto rider assigned somewhere + // assign hub + // error_log('Rider cannot be auto assigned ' . $nearest_hub['hub']->getID()); + $jo->setHub($nearest_hub['hub']); + $jo->setStatus(JOStatus::RIDER_ASSIGN); + $jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED); + + // update redis hub_jo_count for hub + $hub_dist->incrementJoCountForHub($nearest_hub['hub']); + + break; + } + } else { + // TODO: log hub as cannot be auto assigned somewhere + // move to next hub + error_log('Hub cannot be auto-assigned ' . $nearest_hub['hub']->getID()); + continue; + } + } + } + } else { + $jo->setHub($hub); + $jo->setStatus(JOStatus::RIDER_ASSIGN); + $jo->setStatusAutoAssign(AutoAssignStatus::HUB_ASSIGNED); + + if ($date_schedule != null) + $jo->setDateSchedule($date_schedule); + + // update redis hub_jo_count for hub + $hub_dist->incrementJoCountForHub($hub); + } + + $this->em->persist($jo); + $this->em->persist($invoice); + + // add event log for JO + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::CREATE) + ->setJobOrder($jo); + $this->em->persist($event); + + $this->em->flush(); + + // check JO status + if ($jo->getStatus() == JOStatus::ASSIGNED) { + // add event logs for hub and rider assignments + $hub_assign_event = new JOEvent(); + $hub_assign_event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::HUB_ASSIGN) + ->setJobOrder($jo); + + $this->em->persist($hub_assign_event); + + $rider_assign_event = new JOEvent(); + $rider_assign_event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ASSIGN) + ->setJobOrder($jo); + + $this->em->persist($rider_assign_event); + + // user mqtt event + $payload = [ + 'event' => 'outlet_assign', + ]; + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + + $rah->assignJobOrder($jo, $jo->getRider()); + } + + if ($jo->getStatus() == JOStatus::RIDER_ASSIGN) { + // add event logs for hub assignments + $hub_assign_event = new JOEvent(); + $hub_assign_event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::HUB_ASSIGN) + ->setJobOrder($jo); + + $this->em->persist($hub_assign_event); + + // user mqtt event + $payload = [ + 'event' => 'outlet_assign', + ]; + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + } + + $this->em->flush(); + + // make invoice json data + $invoice_data = [ + 'total_price' => $invoice->getTotalPrice(), + 'vat_ex_price' => (float) $invoice->getVATExclusivePrice(), + 'vat' => $invoice->getVAT(), + 'discount' => $invoice->getDiscount(), + 'trade_in' => $invoice->getTradeIn(), + ]; + $items = $invoice->getItems(); + $items_data = []; + foreach ($items as $item) { + $items_data[] = [ + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity() + 0, + 'price' => $item->getPrice() + 0.0, + ]; + } + $invoice_data['items'] = $items_data; + + // need to check for customer tag/promo + // check service type + if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) { + $customer = $cv->getCustomer(); + $customer_tags = $customer->getCustomerTagObjects(); + if (!empty($customer_tags)) { + foreach ($customer_tags as $customer_tag) { + // TODO: not too comfy with this being hardcoded + if ($customer_tag->getID() == $invoice->getUsedCustomerTagId()) { + // remove associated entity + $customer->removeCustomerTag($customer_tag); + + // log the availment of promo from customer + $created_by = $req->query->get('session_key'); + $cust_id = $jo->getCustomer()->getID(); + $cust_fname = $jo->getCustomer()->getFirstName(); + $cust_lname = $jo->getCustomer()->getLastName(); + $jo_id = $jo->getID(); + $invoice_id = $jo->getInvoice()->getID(); + // TODO: check if we store total price of invoice or just the discounted amount + $amount = $jo->getInvoice()->getTotalPrice(); + $promo_logger->logPromoInfo( + $created_by, + $cust_id, + $cust_fname, + $cust_lname, + $jo_id, + $invoice_id, + $amount + ); + } + } + } + } + + // response + return new ApiResponse(true, '', [ + 'jo_id' => $jo->getID(), + 'invoice' => $invoice_data, + ]); + } + + // TODO: remove later + // mobile app no longer calls this + public function requestJobOrder( + Request $req, + InvoiceGeneratorInterface $ic, + GeofenceTracker $geo, + MapTools $map_tools, + InventoryManager $im, + MQTTClientApiv2 $mclientv2, + FCMSender $fcmclient, + RiderAssignmentHandlerInterface $rah, + PromoLogger $promo_logger, + HubSelector $hub_select, + HubDistributor $hub_dist, + HubFilterLogger $hub_filter_logger, + HubFilteringGeoChecker $hub_geofence + ) { + // validate params + $validity = $this->validateRequest($req, [ + 'service_type', + 'cv_id', + // 'batt_id', + 'trade_in', + 'long', + 'lat', + 'warranty', + 'mode_of_payment', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // trade in type + $trade_in = $req->request->get('trade_in'); + + // address + $address = $req->request->get('delivery_address', 'Set by mobile application'); + + // instructions + $instructions = $req->request->get('delivery_instructions', ''); + + // longitude and latitude + $long = $req->request->get('long'); + $lat = $req->request->get('lat'); + + // geofence + $is_covered = $geo->isCovered($long, $lat); + if (!$is_covered) { + // TODO: put geofence error message in config file somewhere + return new ApiResponse(false, $this->getGeoErrorMessage()); + } + + $jo = new JobOrder(); + $jo->setSource(TransactionOrigin::MOBILE_APP) + ->setStatus(JOStatus::PENDING) + ->setDeliveryInstructions('') + ->setTier1Notes('') + ->setTier2Notes('') + ->setDeliveryAddress($address) + ->setTradeInType($trade_in) + ->setDeliveryInstructions($instructions) + // TODO: error check for valid mode of payment + ->setModeOfPayment($req->request->get('mode_of_payment')); + + // customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + $jo->setCustomer($cust); + + // validate service type + $stype = $req->request->get('service_type'); + if (!ServiceType::validate($stype)) { + return new ApiResponse(false, 'Invalid service type.'); + } + $jo->setServiceType($stype); + + // validate warranty + $warr = $req->request->get('warranty'); + if (!WarrantyClass::validate($warr)) { + return new ApiResponse(false, 'Invalid warranty class.'); + } + $jo->setWarrantyClass($warr); + + // set coordinates + $point = new Point($long, $lat); + $jo->setCoordinates($point); + + // make invoice criteria + $icrit = new InvoiceCriteria(); + $icrit->setServiceType($stype); + + // check promo + $promo_id = $req->request->get('promo_id'); + if (!empty($promo_id)) { + $promo = $this->em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) { + return new ApiResponse(false, 'Invalid promo id.'); + } + + // put in criteria + $icrit->addPromo($promo); + } + + // check customer vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->find($req->request->get('cv_id')); + if ($cv == null) { + return new ApiResponse(false, 'Invalid customer vehicle id.'); + } + $icrit->setCustomerVehicle($cv); + $jo->setCustomerVehicle($cv); + + // check if customer owns vehicle + if ($cust->getID() != $cv->getCustomer()->getID()) { + return new ApiResponse(false, 'Customer does not own vehicle.'); + } + + // check battery + $batt_id = $req->request->get('batt_id'); + if ($batt_id != null) { + $batt = $this->em->getRepository(Battery::class)->find($batt_id); + if ($batt == null) { + return new ApiResponse(false, 'Invalid battery id.'); + } + } else + $batt = null; + + /* + // put battery in criteria + $icrit->addBattery($batt); + */ + + // check trade-in + // only allow motolite, other, none + switch ($trade_in) { + case TradeInType::MOTOLITE: + case TradeInType::OTHER: + break; + + default: + $trade_in = ''; + break; + } + + $icrit->addEntry($batt, $trade_in, 1); + + // send to invoice generator + $invoice = $ic->generateInvoice($icrit); + $jo->setInvoice($invoice); + + // set more hub criteria fields + $hub_criteria = new HubCriteria(); + $hub_criteria->setPoint($jo->getCoordinates()); + + // get distance limit for mobile from env + $limit_distance = $_ENV['CUST_DISTANCE_LIMIT']; + + // set distance limit + $hub_criteria->setLimitDistance($limit_distance); + + if ($hub_geofence->isCovered($long, $lat)) { + // TODO: set this properly, since the other flags + // are on default values. + // if true, set other values for HubCriteria + // error_log('Area is covered by hub filtering'); + $hub_criteria->setJoType($jo->getServiceType()) + ->setPaymentMethod($jo->getModeOfPayment()) + ->setRoundRobin(true); + } + + // add battery to items + $sku = $batt->getSAPCode(); + if (!empty($sku)) + $hub_criteria->addItem($batt->getSAPCode(), 1); + + // get customer id. No JO id at this point + $customer_id = $cust->getID(); + + $hub_criteria->setCustomerId($customer_id); + + // find nearest hubs + $nearest_hubs = $hub_select->find($hub_criteria); + + $assigned_rider = null; + if (!empty($nearest_hubs)) { + // go through the hub list, find the nearest hub + // with an available rider + //error_log('found nearest hub ' . $nearest_hub->getID()); + foreach ($nearest_hubs as $nearest_hub) { + $available_riders = $nearest_hub['hub']->getAvailableRiders(); + if (count($available_riders) >= 1) { + if (count($available_riders) == 1) { + $assigned_rider = $available_riders[0]; + } else { + // TODO: the setting of riders into an array + // will no longer be necessary when the contents + // of randomizeRider changes + $riders = []; + foreach ($available_riders as $rider) { + $riders[] = $rider; + } + + $assigned_rider = $this->randomizeRider($riders); + } + + $jo->setHub($nearest_hub['hub']); + $jo->setRider($assigned_rider); + $jo->setStatus(JOStatus::ASSIGNED); + $jo->setStatusAutoAssign(AutoAssignStatus::HUB_AND_RIDER_ASSIGNED); + + $assigned_rider->setAvailable(false); + + // set rider's current job order + $assigned_rider->setCurrentJobOrder($jo); + + // update redis hub_jo_count for hub + $hub_dist->incrementJoCountForHub($nearest_hub['hub']); + + // break out of loop + break; + } else { + // log hub into hub_filter_log + $hub_filter_logger->logFilteredHub($nearest_hub['hub'], 'no_available_rider', null, $cust->getID()); + // continue to go through list to find hub with an available rider + } + } + } + + $this->em->persist($jo); + $this->em->persist($invoice); + + // add event log for JO + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::CREATE) + ->setJobOrder($jo); + $this->em->persist($event); + + // check JO status + if ($jo->getStatus() == JOStatus::ASSIGNED) { + // add event logs for hub and rider assignments + $hub_assign_event = new JOEvent(); + $hub_assign_event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::HUB_ASSIGN) + ->setJobOrder($jo); + + $this->em->persist($hub_assign_event); + + $rider_assign_event = new JOEvent(); + $rider_assign_event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_ASSIGN) + ->setJobOrder($jo); + + $this->em->persist($rider_assign_event); + + // user mqtt event + $payload = [ + 'event' => 'outlet_assign', + ]; + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + + $rah->assignJobOrder($jo, $jo->getRider()); + } + + $this->em->flush(); + + // make invoice json data + $invoice_data = [ + 'total_price' => $invoice->getTotalPrice(), + 'vat_ex_price' => (float) $invoice->getVATExclusivePrice(), + 'vat' => $invoice->getVAT(), + 'discount' => $invoice->getDiscount(), + 'trade_in' => $invoice->getTradeIn(), + ]; + $items = $invoice->getItems(); + $items_data = []; + foreach ($items as $item) { + $items_data[] = [ + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity() + 0, + 'price' => $item->getPrice() + 0.0, + ]; + } + $invoice_data['items'] = $items_data; + + // check service type + if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) { + $customer = $cv->getCustomer(); + $customer_tags = $customer->getCustomerTagObjects(); + if (!empty($customer_tags)) { + foreach ($customer_tags as $customer_tag) { + // TODO: not too comfy with this being hardcoded + if ($customer_tag->getID() == $invoice->getUsedCustomerTagId()) { + // remove associated entity + $customer->removeCustomerTag($customer_tag); + + // log the availment of promo from customer + $created_by = $req->query->get('session_key'); + $cust_id = $jo->getCustomer()->getID(); + $cust_fname = $jo->getCustomer()->getFirstName(); + $cust_lname = $jo->getCustomer()->getLastName(); + $jo_id = $jo->getID(); + $invoice_id = $jo->getInvoice()->getID(); + // TODO: check if we store total price of invoice or just the discounted amount + $amount = $jo->getInvoice()->getTotalPrice(); + $promo_logger->logPromoInfo( + $created_by, + $cust_id, + $cust_fname, + $cust_lname, + $jo_id, + $invoice_id, + $amount + ); + } + } + } + } + + // response + return new ApiResponse(true, '', [ + 'jo_id' => $jo->getID(), + 'invoice' => $invoice_data, + ]); + } + + // commenting it out. Modify the getJOHistory instead to just get the fulfilled + // and cancelled job orders, since ongoing is not yet part of history + /* + public function getCompletedJobOrders(Request $req, EntityManagerInterface $em, RiderTracker $rt) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) + { + return new ApiResponse(false, 'No customer information found.'); + } + + $completed_jos = $this->getCompletedJOs($cust); + + // initialize data + $jo_data = []; + foreach ($completed_jos as $jo) + { + $jo_data[] = $this->generateJobOrderData($req, $jo, $rt); + } + + // response + return new ApiResponse(true, '', [ + 'completed_job_orders' => $jo_data, + ]); + } + + protected function getCompletedJOs($cust) + { + $completed_jos = $this->em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::CANCELLED, JOStatus::FULFILLED], + ], ['date_schedule' => 'desc']); + + return $completed_jos; + } + */ + + protected function generateJobOrderData($req, $jo, $rt) + { + $status = $jo->getStatus(); + + $dest = $jo->getCoordinates(); + + $jo_data = [ + 'id' => $jo->getID(), + 'date_create' => $jo->getDateCreate()->format('M d, Y'), + 'date_schedule' => $jo->getDateSchedule()->format('M d, Y H:i'), + 'service_type' => $jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $jo->getDeliveryAddress(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'landmark' => $jo->getLandmark(), + 'jo_status' => $status, + 'status' => $this->generateAPIRiderStatus($status), + ]; + + // customer vehicle and warranty + $cv = $jo->getCustomerVehicle(); + + // get latest warranty using plate number + $warranty = $this->findWarranty($cv->getPlateNumber()); + + $jo_data['customer_vehicle'] = [ + 'id' => $cv->getID(), + 'plate_number' => $cv->getPlateNumber(), + 'warranty' => $warranty, + ]; + + // customer information + $customer = $jo->getCustomer(); + $jo_data['customer'] = [ + 'first_name' => $customer->getFirstName(), + 'last_name' => $customer->getLastName(), + 'mobile_number' => $customer->getPhoneMobile(), + ]; + + // rider + $rider = $jo->getRider(); + if ($rider != null) { + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $url_prefix . '/uploads/' . $rider->getImageFile(); + + $coord = $rt->getRiderLocation($rider->getID()); + + $jo_data['rider'] = [ + 'id' => $rider->getID(), + 'name' => $rider->getFullName(), + 'plate_num' => $rider->getPlateNumber(), + 'contact_num' => $rider->getContactNumber(), + 'curr_rating' => $rider->getCurrentRating(), + 'image_url' => $image_url, + 'location' => [ + 'long' => $coord->getLongitude(), + 'lat' => $coord->getLatitude() + ] + ]; + + // check if jo has rider rating set to true + $has_rider_rating = $jo->hasRiderRating(); + $rating = 0; + $comment = ''; + if ($rider != null) { + // find the rider rating if any + if ($has_rider_rating) { + $jo_rating = $jo->getRating(); + if ($jo_rating != null) { + $rating = $jo_rating->getRating(); + + // get comment + $comment = $jo_rating->getComment(); + } + } + } + + // rider rating for jo + $jo_data['has_rider_rating'] = $has_rider_rating; + $jo_data['rider_rating'] = $rating; + $jo_data['comment'] = $comment; + } else { + $jo_data['rider'] = null; + $jo_data['has_rider_rating'] = null; + $jo_data['rider_rating'] = null; + $jo_data['comment'] = null; + } + + // invoice items + $items = []; + $jo_items = $jo->getInvoice()->getItems(); + foreach ($jo_items as $item) { + $items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + ]; + } + + $jo_data['items'] = $items; + + + // dates depending on status + switch ($status) { + case JOStatus::FULFILLED: + if ($jo->getDateFulfill() == null) + $jo_data['date_fulfilled'] = ''; + else + $jo_data['date_fulfilled'] = $jo->getDateFulfill()->format('M d, Y'); + break; + case JOStatus::CANCELLED: + $date_cancel = $jo->getDateCancel(); + if ($date_cancel == null) + $date_cancel = new DateTime(); + $jo_data['date_cancelled'] = $date_cancel->format('M d, Y'); + break; + } + + return $jo_data; + } + + protected function generateAPIRiderStatus($status) + { + switch ($status) { + case JOStatus::PENDING: + return APIRiderStatus::OUTLET_ASSIGN; + case JOStatus::RIDER_ASSIGN: + return APIRiderStatus::RIDER_ASSIGN; + case JOStatus::ASSIGNED: + case JOStatus::IN_TRANSIT: + case JOStatus::IN_PROGRESS: + return APIRiderStatus::RIDER_PICK_UP; + } + return 'unknown'; + } + + protected function generateLatestJobOrderData($req, $jo, $rt) + { + $status = $jo->getStatus(); + + $dest = $jo->getCoordinates(); + + $jo_data = [ + 'id' => $jo->getID(), + 'date_create' => $jo->getDateCreate()->format('M d, Y'), + 'service_type' => $jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $jo->getDeliveryAddress(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'jo_status' => $status, + 'status' => $this->generateAPIRiderStatus($status), + 'landmark' => $jo->getLandmark(), + ]; + + // customer vehicle and warranty + $cv = $jo->getCustomerVehicle(); + + // get latest warranty using plate number + $warranty = $this->findWarranty($cv->getPlateNumber()); + + $jo_data['customer_vehicle'] = [ + 'id' => $cv->getID(), + 'plate_number' => $cv->getPlateNumber(), + 'warranty' => $warranty, + ]; + + // customer information + $customer = $jo->getCustomer(); + $jo_data['customer'] = [ + 'first_name' => $customer->getFirstName(), + 'last_name' => $customer->getLastName(), + 'mobile_number' => $customer->getPhoneMobile(), + ]; + + // rider + $rider = $jo->getRider(); + if ($rider != null) { + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $url_prefix . '/uploads/' . $rider->getImageFile(); + + $coord = $rt->getRiderLocation($rider->getID()); + + $jo_data['rider'] = [ + 'id' => $rider->getID(), + 'name' => $rider->getFullName(), + 'plate_num' => $rider->getPlateNumber(), + 'contact_num' => $rider->getContactNumber(), + 'image_url' => $image_url, + 'location' => [ + 'long' => $coord->getLongitude(), + 'lat' => $coord->getLatitude() + ] + ]; + } else { + $jo_data['rider'] = null; + } + + // invoice items + $items = []; + $jo_items = $jo->getInvoice()->getItems(); + foreach ($jo_items as $item) { + $items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + ]; + } + + $jo_data['items'] = $items; + + + // dates depending on status + switch ($status) { + case JOStatus::FULFILLED: + if ($jo->getDateFulfill() == null) + $jo_data['date_fulfilled'] = ''; + else + $jo_data['date_fulfilled'] = $jo->getDateFulfill()->format('M d, Y'); + break; + case JOStatus::CANCELLED: + $date_cancel = $jo->getDateCancel(); + if ($date_cancel == null) + $date_cancel = new DateTime(); + $jo_data['date_cancelled'] = $date_cancel->format('M d, Y'); + break; + } + + return $jo_data; + } + + protected function findWarranty($plate_number) + { + // NOTE: Modify the search for the latest warranty. This seems hacky. + // get latest warranty using plate number + $warranty_results = $this->em->getRepository(Warranty::class)->findBy( + ['plate_number' => $plate_number], + ['date_create' => 'desc'] + ); + + $warr = []; + + // check if warranty_results is empty + if (empty($warranty_results)) { + /* + $res->setError(true) + ->setErrorMessage('No warranty found for plate number'); + return $res->getReturnResponse(); + */ + + return $warr; + } + + // get first entry + $warranty = current($warranty_results); + + // check for null values for battery and date claim and date expire + $batt_model = ''; + $batt_size = ''; + $sap_batt = ''; + $claim_date = ''; + $expiry_date = ''; + + if (!(is_null($warranty->getBatteryModel()))) { + $batt_model = $warranty->getBatteryModel()->getName(); + } + if (!(is_null($warranty->getBatterySize()))) { + $batt_size = $warranty->getBatterySize()->getName(); + } + if (!(is_null($warranty->getSAPBattery()))) { + $sap_batt = $warranty->getSAPBattery()->getID(); + } + if (!(is_null($warranty->getDateClaim()))) { + $claim_date = $warranty->getDateClaim()->format("d M Y"); + } + if (!(is_null($warranty->getDateExpire()))) { + $expiry_date = $warranty->getDateExpire()->format("d M Y"); + } + + $warr[] = [ + 'id' => $warranty->getID(), + 'serial' => $warranty->getSerial(), + 'warranty_class' => $warranty->getWarrantyClass(), + 'plate_number' => $warranty->getPlateNumber(), + 'first_name' => $warranty->getFirstName(), + 'last_name' => $warranty->getLastName(), + 'mobile_number' => $warranty->getMobileNumber(), + 'battery_model' => $batt_model, + 'battery_size' => $batt_size, + 'sap_battery' => $sap_batt, + 'status' => $warranty->getStatus(), + 'date_create' => $warranty->getDateCreate()->format("d M Y g:i A"), + 'date_purchase' => $warranty->getDatePurchase()->format("d M Y"), + 'date_expire' => $expiry_date, + 'date_claim' => $claim_date, + 'claim_from' => $warranty->getClaimedFrom(), + 'is_activated' => $warranty->isActivated() ? 1 : 0, + ]; + + return $warr; + } + + protected function getTimeFromSlot($slot_id) + { + $time_selected = ''; + + switch ($slot_id) { + case '08_09': + $time_selected = AdvanceOrderSlot::_08_09; + break; + case '09_10': + $time_selected = AdvanceOrderSlot::_09_10; + break; + case '10_11': + $time_selected = AdvanceOrderSlot::_10_11; + break; + case '11_12': + $time_selected = AdvanceOrderSlot::_11_12; + break; + case '12_13': + $time_selected = AdvanceOrderSlot::_12_13; + break; + case '13_14': + $time_selected = AdvanceOrderSlot::_13_14; + break; + case '14_15': + $time_selected = AdvanceOrderSlot::_14_15; + break; + case '15_16': + $time_selected = AdvanceOrderSlot::_15_16; + break; + case '16_17': + $time_selected = AdvanceOrderSlot::_16_17; + break; + default: + error_log('Invalid slot id ' . $slot_id); + } + + return $time_selected; + } + + protected function randomizeRider($riders) + { + // TODO: get redis to track the sales per rider per day + // check the time they came in + // for now, randomize the rider + $selected_index = array_rand($riders); + + $selected_rider = $riders[$selected_index]; + + return $selected_rider; + } +} diff --git a/src/Controller/CustomerAppAPI/LocationController.php b/src/Controller/CustomerAppAPI/LocationController.php new file mode 100644 index 00000000..b3d3ecb3 --- /dev/null +++ b/src/Controller/CustomerAppAPI/LocationController.php @@ -0,0 +1,633 @@ +validateRequest($req, [ + 'longitude', + 'latitude', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $long = $req->query->get('longitude'); + $lat = $req->query->get('latitude'); + + // NOTE: had to add this for promo tag + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + $is_covered = false; + // check if customer still has promo + if (($cust->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) || + ($cust->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO')) + ) { + // if has customer tag, customer has not availed of promo + $is_covered = true; + } else { + // geofence + $is_covered = $geo->isCovered($long, $lat); + } + + // geofence + // $is_covered = $geo->isCovered($long, $lat); + + $data = [ + 'longitude' => $long, + 'latitude' => $lat, + 'supported' => $is_covered, + ]; + + // check if is_covered is false. If so, we need to set the error part in the response + if (!$is_covered) { + return new ApiResponse(false, $this->getGeoErrorMessage(), $data); + } + + // response + return new ApiResponse(true, '', $data); + } + + public function getNearestHubAndSlots( + Request $req, + MapTools $map_tools + ) { + // validate params + $validity = $this->validateRequest($req, [ + 'longitude', + 'latitude', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $coordinates = new Point($req->query->get('longitude'), $req->query->get('latitude')); + + // add checking if customer has a pre-registered hub + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // check if customer has customer tag promo + if (($cust->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) || + ($cust->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO')) + ) { + // if has customer tag, customer has not availed of promo, get the hub where customer is pre-registered + $car_club_cust_hub = $cust->getCarClubCustomerHub(); + if ($car_club_cust_hub != null) { + // need to get the rider slots for the pre-registered hub + $hub = $car_club_cust_hub->getHub(); + $nearest_hub_slots = $this->findAdvanceNearestHubAndSlots($coordinates, $map_tools, $hub); + } else { + $nearest_hub_slots = $this->findAdvanceNearestHubAndSlots($coordinates, $map_tools); + + if (empty($nearest_hub_slots['hub'])) { + return new ApiResponse(false, 'Thank you for reaching out to us. Please expect a call from us and we will assist you with your request. Thank you and stay safe!'); + } + } + } else { + $nearest_hub_slots = $this->findAdvanceNearestHubAndSlots($coordinates, $map_tools); + + if (empty($nearest_hub_slots['hub'])) { + return new ApiResponse(false, 'Thank you for reaching out to us. Please expect a call from us and we will assist you with your request. Thank you and stay safe!'); + } + } + + // response + return new ApiResponse(true, '', [ + 'hub_id' => $nearest_hub_slots['hub']->getID(), + 'hub_slots' => $nearest_hub_slots['slots'], + ]); + } + + public function addLocation(Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'name', + 'address', + 'longitude', + 'latitude', + 'landmark', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get the information + $name = $req->request->get('name'); + $address = $req->request->get('address'); + $lng = $req->request->get('longitude'); + $lat = $req->request->get('latitude'); + $landmark = $req->request->get('landmark'); + + $loc_info = [ + 'address' => $address, + 'longitude' => $lng, + 'latitude' => $lat, + 'landmark' => $landmark, + ]; + + // check if customer already has existing metadata + $c_meta = $this->em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($c_meta == null) { + // create new customer meta + $cust_meta = new CustomerMetadata(); + $cust_meta->setCustomer($cust); + $cust_meta->addMetaInfo($name, $loc_info); + + $this->em->persist($cust_meta); + } else { + // limit locations to 6. If more than 6, pop the first one out + // add location to existing customer meta + $meta_count = count($c_meta->getAllMetaInfo()); + + if ($meta_count >= 6) + $c_meta->popMetaInfo(); + + $c_meta->addMetaInfo($name, $loc_info); + } + + $this->em->flush(); + + // response + return new ApiResponse(); + } + + public function removeLocation($id, Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // find customer metadata and delete entry if present + $cv = $this->em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($cv != null) { + $cv->deleteMetadataInfo(base64_decode($id)); + } + + $this->em->flush(); + + // response + return new ApiResponse(); + } + + public function getLocations(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get the customer meta for customer + $locations = []; + $cust_meta = $this->em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($cust_meta != null) { + $locations = $cust_meta->getAllMetaInfo(); + } + + $data = [ + 'locations' => $locations, + ]; + + // response + return new ApiResponse(true, '', $data); + } + + protected function findAdvanceNearestHubAndSlots(Point $coordinates, MapTools $map_tools, $hub = null) + { + $hub_data = []; + + if ($hub != null) { + // get the slots of hub + $hub_slots = $this->getHubRiderSlots($hub); + + $slots = $hub_slots['slot_data']; + + $hub_data = [ + 'hub' => $hub, + 'slots' => $slots, + ]; + return $hub_data; + } + + // get the nearest 10 hubs + $nearest_hubs_with_distance = []; + $hubs = $map_tools->getClosestOpenHubs($coordinates, 10); + + foreach ($hubs as $hub) { + $nearest_hubs_with_distance[] = $hub; + // TODO: insert checking for branch code here when inventory manager is up + } + + $nearest = null; + $hub_slots = []; + $slot_found = false; + // find the nearest hub + if (!empty($nearest_hubs_with_distance)) { + // get slots of nearest hub right after getting nearest hub. + // then check if hub has available slots. If not, get next nearest hub. + foreach ($nearest_hubs_with_distance as $nhd) { + if (empty($nearest)) { + // get the slots for the hub to check if hub is available for assignment + $hub_slots = $this->getHubRiderSlots($nhd['hub']); + + $flag_hub_available = $hub_slots['flag_hub_available']; + if ($flag_hub_available == true) { + $nearest = $nhd; + } + } else { + if ($nhd['distance'] < $nearest['distance']) { + // get the slots for nearest which is nhd right now + $hub_slots = $this->getHubRiderSlots($nhd['hub']); + + $flag_hub_available = $hub_slots['flag_hub_available']; + + // if hub is available, set hub to nearest + if ($flag_hub_available == true) { + $nearest = $nhd; + } + } + } + } + } + + if ($nearest != null) { + // set hub data to what is in nearest + $hub_data = [ + 'hub' => $nearest['hub'], + 'slots' => $hub_slots['slot_data'], + ]; + } + + return $hub_data; + } + + protected function getHubRiderSlots(Hub $hub) + { + // check hub's advance orders for the day + + /* + // get number of advance orders for the next day if request came in before midnight + // or for current day if request came in after midnight + // check request_time + $request_time = time(); + $midnight = strtotime('00:00'); + */ + $start_date = new DateTime(); + $end_date = new DateTime(); + + // to keep things simple, just start on next day regardless of midnight timer + $start_date->add(new DateInterval('P1D')); + $end_date->add(new DateInterval('P3D')); + + /* + if ($request_time < $midnight) + { + // add +1 to start date to get the next day + // add +3 to date to end date to get the advance orders for the next three days + $start_date->add(new DateInterval('P1D')); + $end_date->add(new DateInterval('P1D')); + } + $end_date->add(new DateInterval('P2D')); + */ + + // set time bounds for the start and end date + $start_date->setTime(0, 1); + $end_date->setTime(23, 59); + + // NOTE: get advance orders via query + // get JOs assigned to hub that are advance orders and scheduled for the next three days with + // for hub assignment status + $query = $this->em->createQuery('select jo from App\Entity\JobOrder jo where jo.hub = :hub and jo.flag_advance = true and + jo.date_schedule >= :date_start and jo.date_schedule <= :date_end and jo.status != :status_cancelled + and jo.status != :status_fulfilled'); + $jos_advance_orders = $query->setParameters([ + 'hub' => $hub, + 'date_start' => $start_date, + 'date_end' => $end_date, + 'status_cancelled' => JOStatus::CANCELLED, + 'status_fulfilled' => JOStatus::FULFILLED, + ]) + ->getResult(); + // check request_time + + // define slots + $slots = [ + '08_09' => '8:00 AM', + '09_10' => '9:00 AM', + '10_11' => '10:00 AM', + '11_12' => '11:00 AM', + '12_13' => '12:00 PM', + '13_14' => '1:00 PM', + '14_15' => '2:00 PM', + '15_16' => '3:00 PM', + '16_17' => '4:00 PM', + ]; + + + // get the dates for the next three days + $first_date = $start_date->format('Y-m-d'); + $second_date = $start_date->add(new DateInterval('P1D')); + $sec_date = $second_date->format('Y-m-d'); + $third_date = $end_date->format('Y-m-d'); + + // define days + $days = [ + $first_date => $first_date, + $sec_date => $sec_date, + $third_date => $third_date, + ]; + + // initialize hub rider slots + $hub_rider_slots = []; + foreach ($days as $day) { + foreach ($slots as $slot_key => $slot) { + $hub_rider_slots[$day][$slot_key] = $hub->getRiderSlots(); + } + } + + // check each JO's date_schedule, decrement rider_slots if date schedule falls in that slot + foreach ($jos_advance_orders as $jo) { + // get date key + $date_sched = $jo->getDateSchedule(); + $date_string = $date_sched->format('Y-m-d'); + $hour = $date_sched->format('H'); + $slot_id = sprintf('%02d_%02d', $hour, $hour + 1); + + // error_log("SLOT - $date_string - $slot_id"); + + // decrement rider slot + if (isset($hub_rider_slots[$date_string][$slot_id])) + $hub_rider_slots[$date_string][$slot_id]--; + + // check if it goes through next slot (10 min allowance) + $mins = $date_sched->format('i'); + if ($mins > 10) { + $next_slot_id = sprintf('%02d_%02d', $hour + 1, $hour + 2); + // error_log("NEXT SLOT - $date_string - $next_slot_id"); + // decrement rider slot + if (isset($hub_rider_slots[$date_string][$next_slot_id])) + $hub_rider_slots[$date_string][$next_slot_id]--; + } + } + + // error_log(print_r($hub_rider_slots, true)); + + $hub_slots = $this->generateHubSlots($hub_rider_slots, $slots); + + // error_log(print_r($hub_slots, true)); + + return $hub_slots; + } + + protected function generateHubSlots($rider_slots, $slots) + { + $data = []; + $total_rslots = 0; + $total_unavailable_rslots = 0; + foreach ($rider_slots as $day_id => $rslot) { + $data[$day_id] = []; + + foreach ($rslot as $slot_id => $avail_slots) { + // increment total rider slots + $total_rslots++; + + $slot_data = [ + 'id' => $slot_id, + 'label' => $slots[$slot_id], + 'available' => true, + ]; + + // mark unavailable ones + if ($avail_slots <= 0) { // increment total number of unavailable slots + $total_unavailable_rslots++; + $slot_data['available'] = false; + } + + // add to day data + $data[$day_id][] = $slot_data; + } + } + + // check if hub has available slots + $hub_available = true; + // error_log('total rider slots ' . $total_rslots); + // error_log('total unavailable slots ' . $total_unavailable_rslots); + if ($total_rslots == $total_unavailable_rslots) { + // error_log('hub has no available slots'); + $hub_available = false; + } + + $hs_data = [ + 'flag_hub_available' => $hub_available, + 'slot_data' => $data, + ]; + + return $hs_data; + } + + protected function findNearestHub($jo, MapTools $map_tools) + { + // get the nearest 10 hubs + $selected_hub = null; + $hubs = $map_tools->getClosestOpenHubs($jo->getCoordinates(), 10, date("H:i:s")); + + $nearest_hubs_with_distance = []; + $nearest_branch_codes = []; + foreach ($hubs as $hub) { + $nearest_hubs_with_distance[] = $hub; + //if (!empty($hub['hub']->getBranchCode())) + // $nearest_branch_codes[] = $hub['hub']->getBranchCode(); + } + + // check if nearest hubs have branch codes + //if (count($nearest_branch_codes) == 0) + // return $selected_hub; + + // assume all 10 have stock + // find the nearest hub with available riders + $nearest = null; + foreach ($nearest_hubs_with_distance as $nhd) { + // get number of available riders + $count_riders = count($nhd['hub']->getAvailableRiders()); + + // get number of advance orders in the next 3 hours + $time_now = new DateTime(); + $date_end = new DateTime(); + $date_end->add(new DateInterval('PT2H')); + + // NOTE: get advance orders via query + // get JOs assigned to hub that are advance orders and scheduled within X hours with + // for rider assignment status + $query = $this->em->createQuery('select count(jo) from App\Entity\JobOrder jo where jo.hub = :hub and jo.flag_advance = true and jo.date_schedule <= :date_end and jo.status = :status'); + $count_advance_orders = $query->setParameters([ + 'hub' => $nhd['hub'], + 'date_end' => $date_end, + 'status' => JOStatus::RIDER_ASSIGN, + ]) + ->setMaxResults(1) + ->getSingleScalarResult(); + + // error_log('HUB - ' . $nhd['hub']->getID()); + // error_log('RIDER COUNT - ' . $count_riders); + // error_log('ADVANCE ORDER COUNT - ' . $count_advance_orders); + + // if (count($nhd['hub']->getAvailableRiders()) > 0) + // if we have more riders than we have advance orders + if ($count_riders - $count_advance_orders > 0) { + if (empty($nearest)) + $nearest = $nhd; + else { + if ($nhd['distance'] < $nearest['distance']) + $nearest = $nhd; + } + } + } + + $selected_hub = $nearest['hub']; + + return $selected_hub; + } + + protected function findNearestHubWithInventory( + $jo, + Battery $batt, + MapTools $map_tools, + InventoryManager $im + ) { + // get the nearest 10 hubs + $selected_hub = null; + $hubs = $map_tools->getClosestOpenHubs($jo->getCoordinates(), 10, date("H:i:s")); + + $nearest_hubs_with_distance = []; + $nearest_branch_codes = []; + foreach ($hubs as $hub) { + $nearest_hubs_with_distance[] = $hub; + //if (!empty($hub['hub']->getBranchCode())) + // $nearest_branch_codes[] = $hub['hub']->getBranchCode(); + } + + // check if nearest hubs have branch codes + //if (count($nearest_branch_codes) == 0) + // return $selected_hub; + + // assume all 10 have stock + // find the nearest hub with available riders + $nearest = null; + foreach ($nearest_hubs_with_distance as $nhd) { + if (count($nhd['hub']->getAvailableRiders()) > 0) { + if (empty($nearest)) + $nearest = $nhd; + else { + if ($nhd['distance'] < $nearest['distance']) + $nearest = $nhd; + } + } + } + + $selected_hub = $nearest['hub']; + + // uncomment this snippet when inventory check becomes active + // get battery sku + /* + if ($batt != null) + { + $skus[] = $batt->getSAPCode(); + + // api call to check inventory + // pass the list of branch codes of nearest hubs and the skus + // go through returned list of branch codes + // bypass inventory check for now + // $hubs_with_inventory = $im->getBranchesInventory($nearest_branch_codes, $skus); + if (!empty($hubs_with_inventory)) + { + $nearest = []; + $flag_hub_found = false; + foreach ($hubs_with_inventory as $hub_with_inventory) + { + // find hub according to branch code + $found_hub = $this->em->getRepository(Hub::class)->findOneBy(['branch_code' => $hub_with_inventory['BranchCode']]); + if ($found_hub != null) + { + // check rider availability + if (count($found_hub->getAvailableRiders()) > 0) + { + // check against nearest hubs with distance + foreach ($nearest_hubs_with_distance as $nhd) + { + // get distance of hub from location, compare with $nearest. if less, replace nearest + if ($found_hub->getID() == $nhd['hub']->getID()) + { + if (empty($nearest)) + { + $nearest = $nhd; + $flag_hub_found = true; + } + else + { + if ($nhd['distance'] < $nearest['distance']) + { + $nearest = $nhd; + $flag_hub_found = true; + } + } + } + } + } + } + } + $selected_hub = $nearest['hub']; + } + } */ + return $selected_hub; + } +} diff --git a/src/Controller/CustomerAppAPI/MotoliteEventController.php b/src/Controller/CustomerAppAPI/MotoliteEventController.php new file mode 100644 index 00000000..9565f656 --- /dev/null +++ b/src/Controller/CustomerAppAPI/MotoliteEventController.php @@ -0,0 +1,51 @@ +validateRequest($req, [ + 'limit', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $limit = $req->query->get('limit'); + + // get all events + $results = $this->em->getRepository(MotoliteEvent::class) + ->findBy([], ['event_time' => 'asc'], $limit); + + if (empty($results)) { + return new ApiResponse(false, 'No events available.'); + } + + $events = []; + foreach ($results as $result) { + $events[] = [ + 'id' => $result->getID(), + 'name' => $result->getName(), + 'event_type' => MotoliteEventType::getName($result->getEventType()), + 'event_time' => $result->getEventTime()->format("d M Y g:i A"), + 'url' => $result->getUrl(), + 'image_file' => $result->getImageFile(), + ]; + } + + // response + return new ApiResponse(true, '', [ + 'events' => $events, + ]); + } +} diff --git a/src/Controller/CustomerAppAPI/PartnerController.php b/src/Controller/CustomerAppAPI/PartnerController.php new file mode 100644 index 00000000..77636b86 --- /dev/null +++ b/src/Controller/CustomerAppAPI/PartnerController.php @@ -0,0 +1,164 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get partner + $partner = $this->em->getRepository(Partner::class)->findOneBy(['id' => $pid]); + if ($partner == null) { + return new ApiResponse(false, 'No partner found.'); + } + + // get reviews for partner + $reviews = $this->em->getRepository(Review::class)->findBy(['partner' => $partner]); + + // get average rating for all reviews + $average_rating = 0; + if (!empty($reviews)) { + $rating = 0; + foreach ($reviews as $review) { + $rating = $rating + $review->getRating(); + } + + $average_rating = $rating / sizeof($reviews); + } + + $data = []; + $data['partner'] = [ + 'id' => $partner->getID(), + 'name' => $partner->getName(), + 'branch' => $partner->getBranch(), + 'address' => $partner->getAddress(), + 'contact_nums' => $partner->getContactNumbers(), + 'time_open' => $partner->getTimeOpen()->format("g:i A"), + 'time_close' => $partner->getTimeClose()->format("g:i A"), + 'longitude' => $partner->getCoordinates()->getLongitude(), + 'latitude' => $partner->getCoordinates()->getLatitude(), + 'average_rating' => $average_rating, + ]; + + // response + return new ApiResponse(true, '', $data); + } + + public function getClosestPartners(Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'longitude', + 'latitude', + 'service_id', + 'limit', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $long = $req->query->get('longitude'); + $lat = $req->query->get('latitude'); + $service_id = $req->query->get('service_id'); + $limit = $req->query->get('limit'); + + // get partners within range + $query = $this->em->createQuery('SELECT p, st_distance(p.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Partner p + JOIN App\Entity\Service s where s.id = :service_id ORDER BY dist') + ->setParameter('lat', $lat) + ->setParameter('lng', $long) + ->setParameter('service_id', $service_id); + + $query->setMaxResults($limit); + $result = $query->getResult(); + + $data = []; + $partners = []; + foreach ($result as $row) { + // get all the reviews for each partner and average the ratings + $partner_id = $row[0]->getID(); + $partner = $this->em->getRepository(Partner::class)->find($partner_id); + $partner_reviews = $this->em->getRepository(Review::class)->findBy(['partner' => $partner]); + + $average_rating = 0; + if (count($partner_reviews) > 0) { + $rating = 0; + foreach ($partner_reviews as $review) { + $rating = $rating + $review->getRating(); + } + + $average_rating = $rating / sizeof($partner_reviews); + } + + $partners[] = [ + 'id' => $row[0]->getID(), + 'name' => $row[0]->getName(), + 'branch' => $row[0]->getBranch(), + 'address' => $row[0]->getAddress(), + 'contact_nums' => $row[0]->getContactNumbers(), + 'time_open' => $row[0]->getTimeOpen()->format("g:i A"), + 'time_close' => $row[0]->getTimeClose()->format("g:i A"), + 'longitude' => $row[0]->getCoordinates()->getLongitude(), + 'latitude' => $row[0]->getCoordinates()->getLatitude(), + 'db_distance' => $row['dist'], + 'rating' => $average_rating, + ]; + } + + $data['partners'] = $partners; + + // response + return new ApiResponse(true, '', $data); + } + + public function reviewPartner($pid, Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'rating', + 'message', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $rating = $req->request->get('rating'); + $msg = $req->request->get('message'); + + // TODO: check rating if 1 - 5 + + // check if partner exists + $partner = $this->em->getRepository(Partner::class)->find($pid); + if ($partner == null) { + return new ApiResponse(false, 'No partner found.'); + } + + $rev = new Review(); + $rev->setRating($rating) + ->setMessage($msg) + ->setPartner($partner) + ->setCustomerSession($this->session); // NOTE: using new customer session entity + + // save to db + $this->em->persist($rev); + $this->em->flush(); + + // response + return new ApiResponse(); + } +} diff --git a/src/Controller/CustomerAppAPI/PrivacyController.php b/src/Controller/CustomerAppAPI/PrivacyController.php new file mode 100644 index 00000000..005ba097 --- /dev/null +++ b/src/Controller/CustomerAppAPI/PrivacyController.php @@ -0,0 +1,67 @@ +validateRequest($req, [ + 'priv_third_party', + // 'priv_promo', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // set privacy settings + $priv_promo = $req->request->get('priv_promo', false); + $priv_third_party = $req->request->get('priv_third_party'); + $cust->setPrivacyThirdParty($priv_third_party) + ->setPrivacyPromo($priv_promo); + + // get the policy ids from .env + $policy_promo_id = $_ENV['POLICY_PROMO']; + $policy_third_party_id = $_ENV['POLICY_THIRD_PARTY']; + + // check if privacy settings are true + // if true, set the private policy for the customer + if ($priv_promo) { + // find the promo policy + $policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_promo_id); + + // set policy id + if ($policy != null) { + $cust->setPrivacyPolicyPromo($policy); + } + } + + if ($priv_third_party) { + // find the third party policy + $policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_third_party_id); + + // set policy id + if ($policy != null) { + $cust->setPrivacyPolicyThirdParty($policy); + } + } + + $this->em->flush(); + + // response + return new ApiResponse(); + } +} diff --git a/src/Controller/CustomerAppAPI/PromoController.php b/src/Controller/CustomerAppAPI/PromoController.php new file mode 100644 index 00000000..7a5d9360 --- /dev/null +++ b/src/Controller/CustomerAppAPI/PromoController.php @@ -0,0 +1,22 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // response + return new ApiResponse(); + } +} diff --git a/src/Controller/CustomerAppAPI/ReviewTagController.php b/src/Controller/CustomerAppAPI/ReviewTagController.php new file mode 100644 index 00000000..76f68bef --- /dev/null +++ b/src/Controller/CustomerAppAPI/ReviewTagController.php @@ -0,0 +1,46 @@ +getTags($req, "partner"); + } + + public function getRiderReviewTags(Request $req) + { + return $this->getTags($req, "rider"); + } + + protected function getTags(Request $req, $tag_type) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get manufacturer list + $tags = $this->em->getRepository(ReviewTag::class)->findBy(['type' => $tag_type], ['name' => 'asc']); + $tag_list = []; + + foreach ($tags as $tag) { + $tag_list[] = [ + 'id' => $tag->getID(), + 'name' => $tag->getName(), + ]; + } + + return new ApiResponse(true, '', [ + 'tags' => $tag_list, + ]); + } +} diff --git a/src/Controller/CustomerAppAPI/RiderController.php b/src/Controller/CustomerAppAPI/RiderController.php new file mode 100644 index 00000000..96557a54 --- /dev/null +++ b/src/Controller/CustomerAppAPI/RiderController.php @@ -0,0 +1,241 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // check if we have an ongoing job order + /* + $ongoing_jos = $em->getRepository(JobOrder::class)->findBy([ + 'customer' => $cust, + 'status' => [JOStatus::PENDING, JOStatus::RIDER_ASSIGN, JOStatus::IN_TRANSIT, JOStatus::ASSIGNED, JOStatus::IN_PROGRESS], + ]); + */ + $ongoing_jos = $this->getOngoingJobOrders($cust); + + // $res->setData(['here' => count($ongoing_jos)]); + // return $res->getReturnResponse(); + if (count($ongoing_jos) <= 0) { + try { + // check if the latest fulfilled jo they have needs rider rating + $query = $this->em->createQuery('select jo from App\Entity\JobOrder jo where jo.customer = :cust and jo.status = :status order by jo.date_fulfill desc'); + $fulfill_jo = $query->setParameters([ + 'cust' => $cust, + 'status' => JOStatus::FULFILLED, + ]) + ->setMaxResults(1) + ->getSingleResult(); + } catch (Exception $e) { + // response + return new ApiResponse(true, '', [ + 'status' => APIRiderStatus::NO_PENDING_JO, + ]); + } + + // we got a recently fulfilled job order + if ($fulfill_jo) { + // check if the rider has been rated + if (!$fulfill_jo->hasRiderRating()) { + $dest = $fulfill_jo->getCoordinates(); + + $data = [ + 'jo_id' => $fulfill_jo->getID(), + 'service_type' => $fulfill_jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $fulfill_jo->getDeliveryAddress(), + 'delivery_instructions' => $fulfill_jo->getDeliveryInstructions(), + ]; + + $rider = $fulfill_jo->getRider(); + + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $url_prefix . '/uploads/' . $rider->getImageFile(); + + $data['status'] = APIRiderStatus::RIDER_RATING; + // default rider location to hub + $data['rider'] = [ + 'id' => $rider->getID(), + 'name' => $rider->getFullName(), + 'plate_num' => $rider->getPlateNumber(), + 'contact_num' => $rider->getContactNumber(), + 'image_url' => $image_url, + ]; + + // response + return new ApiResponse(true, '', $data); + } + } + + // response, no pending + return new ApiResponse(true, '', [ + 'status' => APIRiderStatus::NO_PENDING_JO, + ]); + } + + // get first jo that's pending + $jo = $ongoing_jos[0]; + $dest = $jo->getCoordinates(); + + $data = [ + 'jo_id' => $jo->getID(), + 'service_type' => $jo->getServiceType(), + 'destination' => [ + 'long' => $dest->getLongitude(), + 'lat' => $dest->getLatitude(), + ], + 'delivery_address' => $jo->getDeliveryAddress(), + 'delivery_instructions' => $jo->getDeliveryInstructions(), + ]; + + switch ($jo->getStatus()) { + case JOStatus::PENDING: + $data['status'] = APIRiderStatus::OUTLET_ASSIGN; + break; + case JOStatus::RIDER_ASSIGN: + $data['status'] = APIRiderStatus::RIDER_ASSIGN; + break; + case JOStatus::ASSIGNED: + case JOStatus::IN_TRANSIT: + case JOStatus::IN_PROGRESS: + $rider = $jo->getRider(); + // get rider coordinates from redis + $coord = $rt->getRiderLocation($rider->getID()); + + // default image url + $url_prefix = $req->getSchemeAndHttpHost(); + $image_url = $url_prefix . '/assets/images/user.gif'; + if ($rider->getImageFile() != null) + $image_url = $url_prefix . '/uploads/' . $rider->getImageFile(); + + $data['status'] = APIRiderStatus::RIDER_PICK_UP; + // TODO: fix this to actual location of rider + // default rider location to hub + $data['rider'] = [ + 'id' => $rider->getID(), + 'name' => $rider->getFullName(), + 'plate_num' => $rider->getPlateNumber(), + 'contact_num' => $rider->getContactNumber(), + 'image_url' => $image_url, + 'location' => [ + 'long' => $coord->getLongitude(), + 'lat' => $coord->getLatitude() + ] + ]; + + break; + } + + // response + return new ApiResponse(true, '', $data); + } + + public function addRiderRating(Request $req) + { + // validate params + $validity = $this->validateRequest($req, [ + 'jo_id', + 'rating', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // get job order + $jo_id = $req->request->get('jo_id'); + $jo = $this->em->getRepository(JobOrder::class)->find($jo_id); + if ($jo == null) { + return new ApiResponse(false, 'No job order found.'); + } + + // get rider + $rider = $jo->getRider(); + if ($rider == null) { + return new ApiResponse(false, 'No rider found.'); + } + + // check that the customer owns the job order + $jo_cust = $jo->getCustomer(); + if ($jo_cust->getID() != $cust->getID()) { + return new ApiResponse(false, 'Job order was not initiated by customer.'); + } + + // TODO: check job order status, if it's complete + + // add rider rating + $rating_num = $req->request->get('rating', -1); + + // if rating is -1 + if ($rating_num == -1) { + $jo->setHasRiderRating(); + $this->em->flush(); + + // response + return new ApiResponse(); + } + + + $rating = new RiderRating(); + $rating->setRider($rider) + ->setCustomer($cust) + ->setJobOrder($jo) + ->setRating($rating_num); + + // rider rating comment + $comment = $req->request->get('comment'); + if (!empty($comment)) + $rating->setComment($comment); + + // mark jo as rider rated already + $jo->setHasRiderRating(); + + $this->em->persist($rating); + $this->em->flush(); + + // TODO: preliminary rating computation on the entity for now + $rider->updateRatingAverage(); + $this->em->persist($rider); + $this->em->flush(); + + // response + return new ApiResponse(); + } +} diff --git a/src/Controller/CustomerAppAPI/ScheduleController.php b/src/Controller/CustomerAppAPI/ScheduleController.php new file mode 100644 index 00000000..6edf8a68 --- /dev/null +++ b/src/Controller/CustomerAppAPI/ScheduleController.php @@ -0,0 +1,61 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $schedule_choice = true; + + // remove the time check after ECQ. This will then always return true + // get current time + $current_datetime = new DateTime(); + //$current_datetime = DateTime::createFromFormat('Y-m-d H:i', '2020-04-30 17:01'); + + // get the hour + $hour = $current_datetime->format('G'); + + // commenting out the time check since we can now book 24/7 + // this will get uncommented out if and when ECQ will kick in + //if (($hour < 8) || ($hour > 16)) + // $schedule_choice = false; + + // add checking if customer has a pre-registered hub + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + // check if customer has customer tag promo + if (($cust->getCustomerTag('TAG_CAR_CLUB_OFFICER_PROMO')) || + ($cust->getCustomerTag('TAG_CAR_CLUB_MEMBER_PROMO')) + ) { + // if has customer tag, customer has not availed of promo, get the hub where customer is pre-registered + $car_club_hub = $cust->getCarClubCustomerHub(); + if ($car_club_hub != null) { + $schedule_choice = false; + } + } + + // schedule_choice will always be true aka customer can opt to + // Book Now or Schedule Order EXCEPT if customer has customer tag promo + // or ECQ comes back + + // response + return new ApiResponse(true, '', [ + 'display_schedule_choice' => $schedule_choice, + ]); + } +} diff --git a/src/Controller/CustomerAppAPI/ServiceController.php b/src/Controller/CustomerAppAPI/ServiceController.php new file mode 100644 index 00000000..5e8abfdb --- /dev/null +++ b/src/Controller/CustomerAppAPI/ServiceController.php @@ -0,0 +1,60 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // services + $results = $this->em->getRepository(Service::class)->findAll(); + if (empty($results)) { + return new ApiResponse(false, 'No services available.'); + } + + $services = []; + foreach ($results as $result) { + /* + // get partners + $partners = []; + $service_partners = $result->getPartners(); + foreach($service_partners as $sp) + { + $partners[] = [ + 'id' => $sp->getID(), + 'name' => $sp->getName(), + 'branch' => $sp->getBranch(), + 'address' => $sp->getAddress(), + 'contact_nums' => $sp->getContactNumbers(), + 'time_open' => $sp->getTimeOpen()->format("g:i A"), + 'time_close' => $sp->getTimeClose()->format("g:i A"), + ]; + } + */ + + $services[] = [ + 'id' => $result->getID(), + 'name' => $result->getName(), + 'icon' => $result->getIcon(), + // 'partners' => $partners, + ]; + } + + // response + return new ApiResponse(true, '', [ + 'services' => $services, + ]); + } +} diff --git a/src/Controller/CustomerAppAPI/VehicleController.php b/src/Controller/CustomerAppAPI/VehicleController.php new file mode 100644 index 00000000..51a8ce80 --- /dev/null +++ b/src/Controller/CustomerAppAPI/VehicleController.php @@ -0,0 +1,375 @@ +validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get manufacturer list + $mfgs = $this->em->getRepository(VehicleManufacturer::class)->findBy(['flag_mobile' => true], ['name' => 'asc']); + $mfg_list = []; + + foreach ($mfgs as $mfg) { + $mfg_list[] = [ + 'id' => $mfg->getID(), + 'name' => $mfg->getName(), + ]; + } + + return new ApiResponse(true, '', [ + 'manufacturers' => $mfg_list, + ]); + } + + public function listVehicleMakes(Request $req, $mfg_id) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get manufacturer + $mfg = $this->em->getRepository(VehicleManufacturer::class)->find($mfg_id); + if ($mfg == null) { + // response + return new ApiResponse(false, 'Invalid vehicle manufacturer id.'); + } + + // get makes + $vehicles = $this->em->getRepository(Vehicle::class)->findBy( + [ + 'flag_mobile' => true, + 'manufacturer' => $mfg_id, + ], + ['make' => 'asc'] + ); + // $vehicles = $mfg->getVehicles(); + $vlist = []; + foreach ($vehicles as $v) { + $vlist[] = [ + 'id' => $v->getID(), + 'make' => trim($v->getMake() . ' ' . $v->getModelYearFormatted(false)), + // 'make' => $v->getMake() . ' ' . $v->getModelYearFrom() . '-' . $v->getModelYearTo(), + ]; + } + + // response + return new ApiResponse(true, '', [ + 'manufacturer' => [ + 'id' => $mfg->getID(), + 'name' => $mfg->getName(), + ], + 'makes' => $vlist, + ]); + } + + public function addVehicle(Request $req) + { + // check requirements + $validity = $this->checkVehicleRequirements($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // customer vehicle + $cv = new CustomerVehicle(); + + // set object + $res = $this->setCustomerVehicleObject($req, $cv); + if (!$res['success']) { + return new ApiResponse(false, $res['error']); + } + + // response + return new ApiResponse(true, '', [ + 'cv_id' => $res['cv_id'], + ]); + + } + + public function updateVehicle(Request $req, $id) + { + // check requirements + $validity = $this->checkVehicleRequirements($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->find($id); + + // check if it exists + if ($cv == null) { + return new ApiResponse(false, 'Vehicle does not exist.'); + } + + // check if it's owned by customer + if ($cv->getCustomer()->getID() != $this->session->getCustomer()->getID()) { + return new ApiResponse(false, 'Invalid vehicle.'); + } + + // set object + $res = $this->setCustomerVehicleObject($req, $cv); + if (!$res['success']) { + return new ApiResponse(false, $res['error']); + } + + // response + return new ApiResponse(true, '', [ + 'cv_id' => $res['cv_id'], + ]); + } + + public function listVehicles(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // vehicles + $cv_list = []; + // $cvs = $cust->getVehicles(); + // only get the customer's vehicles whose flag_active is true + $cvs = $this->em->getRepository(CustomerVehicle::class)->findBy(['flag_active' => true, 'customer' => $cust]); + foreach ($cvs as $cv) { + $battery_id = null; + if ($cv->getCurrentBattery() != null) + $battery_id = $cv->getCurrentBattery()->getID(); + + $wty_ex = null; + if ($cv->getWarrantyExpiration() != null) + $wty_ex = $cv->getWarrantyExpiration()->format('Y-m-d'); + + $warranty = $this->findWarranty($cv->getPlateNumber()); + + $cv_name = ''; + if ($cv->getName() != null) + $cv_name = $cv->getName(); + + $cv_list[] = [ + 'cv_id' => $cv->getID(), + 'mfg_id' => $cv->getVehicle()->getManufacturer()->getID(), + 'make_id' => $cv->getVehicle()->getID(), + 'name' => $cv_name, + 'plate_num' => $cv->getPlateNumber(), + 'model_year' => $cv->getModelYear(), + 'color' => $cv->getColor(), + 'condition' => $cv->getStatusCondition(), + 'fuel_type' => $cv->getFuelType(), + 'wty_code' => $cv->getWarrantyCode(), + 'wty_expire' => $wty_ex, + 'curr_batt_id' => $battery_id, + 'is_motolite' => $cv->hasMotoliteBattery() ? 1 : 0, + 'is_active' => $cv->isActive() ? 1 : 0, + 'warranty' => $warranty, + ]; + } + + // response + return new ApiResponse(true, '', [ + 'vehicles' => $cv_list, + ]); + } + + public function getCompatibleBatteries(Request $req, $vid) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get vehicle + $vehicle = $this->em->getRepository(Vehicle::class)->find($vid); + if ($vehicle == null) { + return new ApiResponse(false, 'Invalid vehicle.'); + } + + // batteries + $batt_list = []; + $batts = $vehicle->getBatteries(); + foreach ($batts as $batt) { + // TODO: Add warranty_tnv to battery information + $batt_list[] = [ + 'id' => $batt->getID(), + 'mfg_id' => $batt->getManufacturer()->getID(), + 'mfg_name' => $batt->getManufacturer()->getName(), + 'model_id' => $batt->getModel()->getID(), + 'model_name' => $batt->getModel()->getName(), + 'size_id' => $batt->getSize()->getID(), + 'size_name' => $batt->getSize()->getName(), + 'price' => $batt->getSellingPrice(), + 'wty_private' => $batt->getWarrantyPrivate(), + 'wty_commercial' => $batt->getWarrantyCommercial(), + 'image_url' => $this->getBatteryImageURL($req, $batt), + ]; + } + + // response + return new ApiResponse(true, '', [ + 'vehicle' => [ + 'id' => $vehicle->getID(), + 'mfg_id' => $vehicle->getManufacturer()->getID(), + 'mfg_name' => $vehicle->getManufacturer()->getName(), + 'make' => $vehicle->getMake(), + 'model_year_from' => $vehicle->getModelYearFrom(), + 'model_year_to' => $vehicle->getModelYearTo(), + ], + 'batteries' => $batt_list, + ]); + } + + public function removeVehicle($id, Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return new ApiResponse(false, 'No customer information found.'); + } + + // find customer vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->find($id); + if ($cv == null) { + return new ApiResponse(false, 'Invalid customer vehicle id.'); + } + + // confirm that customer vehicle belongs to customer + if ($cv->getCustomer()->getID() != $cust->getID()) { + return new ApiResponse(false, 'Vehicle does not belong to customer.'); + } + + // we cannot remove a vehicle from customer if customer vehicle has already has JOs for it. + // instead we set the customer vehicle's flag_active to false + $cv->setActive(false); + $this->em->flush(); + + // response + return new ApiResponse(); + } + + protected function checkVehicleRequirements(Request $req) + { + // validate params + return $this->validateRequest($req, [ + 'make_id', + 'name', + 'plate_num', + 'model_year', + 'color', + 'condition', + 'fuel_type', + ]); + + // TODO: check valid plate number + // TODO: check valid fuel type (gas / diesel) + // TODO: check current battery id + // TODO: check condition (brand new / second-hand) + // TODO: check is_motolite and is_active (1 or 0) + // TODO: check warranty expiration date (YYYYMMDD) + // TODO: check model year coverage if it fits in between + } + + protected function setCustomerVehicleObject(Request $req, CustomerVehicle $cv) + { + // check customer + $cust = $this->session->getCustomer(); + if ($cust == null) { + return [ + 'success' => false, + 'error' => 'No customer information found.', + ]; + } + + // get vehicle + $vehicle = $this->em->getRepository(Vehicle::class)->find($req->request->get('make_id')); + if ($vehicle == null) { + return [ + 'success' => false, + 'error' => 'Invalid vehicle make id.', + ]; + } + + $cv->setCustomer($cust) + ->setVehicle($vehicle) + ->setName($req->request->get('name')) + ->setPlateNumber($req->request->get('plate_num')) + ->setModelYear($req->request->get('model_year')) + ->setColor($req->request->get('color')) + ->setFuelType($this->normalizeString($req->request->get('fuel_type'))) + ->setStatusCondition($this->normalizeString($req->request->get('condition'))); + + // set warranty code and expiration + // TODO: check warranty requirements + if (!empty($req->request->get('wty_code'))) + $cv->setWarrantyCode($req->request->get('wty_code')); + if (!empty($req->request->get('wty_expire'))) + $cv->setWarrantyExpiration(new DateTime($req->request->get('wty_expire'))); + + // TODO: get current battery + + // is motolite + if ($req->request->get('is_motolite') == 0) + $cv->setHasMotoliteBattery(false); + else + $cv->setHasMotoliteBattery(true); + + // is active + if ($req->request->get('is_active') == 0) + $cv->setActive(false); + else + $cv->setActive(true); + + // save + $this->em->persist($cv); + $this->em->flush(); + + // response + return [ + 'success' => true, + 'cv_id' => $cv->getID(), + ]; + } + + protected function normalizeString($string) + { + return trim(strtolower($string)); + } +} diff --git a/src/Controller/CustomerAppAPI/WarrantyController.php b/src/Controller/CustomerAppAPI/WarrantyController.php new file mode 100644 index 00000000..ff1e9d81 --- /dev/null +++ b/src/Controller/CustomerAppAPI/WarrantyController.php @@ -0,0 +1,614 @@ +validateRequest($req, [ + 'plate_number', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + $plate_number = $req->request->get('plate_number'); + + // find warranty using plate number + $warranty_results = $this->em->getRepository(Warranty::class)->findBy( + ['plate_number' => $plate_number], + ['date_create' => 'desc'] + ); + + // check if warranty_results is empty + if (empty($warranty_results)) { + return new ApiResponse(false, 'No warranty found for plate number.'); + } + + // activate all entries + foreach ($warranty_results as $warranty) { + $warranty->setActivated(); + } + + $this->em->flush(); + + // response + return new ApiResponse(); + } + + public function warrantyCheck($serial, Request $req, WarrantyRaffleLogger $raffle_logger) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // check if warranty serial is there + $serial = $this->cleanSerial($serial); + $warr_serial = $this->em->getRepository(WarrantySerial::class)->find($serial); + $warr = $this->em->getRepository(Warranty::class)->findOneBy(['serial' => $serial]); + $batt = null; + $is_registered = false; + + if ($warr_serial == null) { + return new ApiResponse(false, 'Invalid warranty serial code.'); + } + + $today = new DateTime(); + + $user_id = $req->query->get('session_key'); + $raffle_data = [ + 'user_id' => $user_id, + 'serial' => $serial, + 'warranty_id' => null, + 'action' => '', + 'bmodel_name' => '', + 'bsize_name' => '', + 'first_name' => '', + 'last_name' => '', + 'plate_number' => '', + 'contact_num' => '', + 'email' => '', + 'address' => '', + ]; + + $data_sent = []; + + // if we have a warranty entry for the serial already + if ($warr != null) { + $warr_plate = $warr->getPlateNumber(); + $is_registered = true; + $is_customer_warranty = false; + + // check if the warranty is registered to a car owned by the customer + $cust = $this->session->getCustomer(); + $is_customer_warranty = $this->checkCustomerPlateNumber($warr_plate, $cust); + + // null mobile number should be blank string instead + if ($warr->getMobileNumber() == null) + $mobile_num = ''; + else + $mobile_num = $warr->getMobileNumber(); + + $can_edit = $is_customer_warranty; + + // if customer plate number matches the one registered on the warranty + if ($is_customer_warranty) { + // purchase date of customer + if ($warr->getDatePurchaseCustomer() != null) + $date_purchase_cust = $warr->getDatePurchaseCustomer()->format('Y-m-d'); + else + $date_purchase_cust = $today->format('Y-m-d'); + + + // invoice + if ($warr->getFileInvoice() != null) + $invoice_url = $req->getSchemeAndHttpHost() . '/warranty_uploads/' . $warr->getFileInvoice(); + else + $invoice_url = ''; + + // warranty card + if ($warr->getFileWarrantyCard() != null) + $warr_card_url = $req->getSchemeAndHttpHost() . '/warranty_uploads/' . $warr->getFileWarrantyCard(); + else + $warr_card_url = ''; + + $customer = [ + 'first_name' => $warr->getFirstName() ?? '', + 'last_name' => $warr->getLastName() ?? '', + 'mobile_number' => $mobile_num, + 'plate_number' => $warr_plate, + 'email' => $warr->getEmail() ?? '', + 'contact_num' => $warr->getContactNumber() ?? '', + 'address' => $warr->getCustomerAddress() ?? '', + ]; + $other_data = [ + 'odometer' => (int) $warr->getOdometer() ?? 0, + 'date_purchase' => $date_purchase_cust, + 'invoice' => $invoice_url, + 'warr_card' => $warr_card_url, + 'dealer_name' => $warr->getDealerName() ?? '', + 'dealer_address' => $warr->getDealerAddress() ?? '', + 'branch_code' => $warr->getDealerBranchCode() ?? '', + ]; + + // set customer info and action for raffle log + $raffle_data['action'] = 'serial_check_customer'; + $raffle_data['first_name'] = $customer['first_name']; + $raffle_data['last_name'] = $customer['last_name']; + $raffle_data['plate_number'] = $customer['plate_number']; + $raffle_data['email'] = $customer['email']; + $raffle_data['contact_num'] = $customer['contact_num']; + $raffle_data['address'] = $customer['address']; + $raffle_data['warranty_id'] = $warr->getID(); + } else { + // hide customer information if customer is not the one registered + $customer = [ + 'first_name' => '', + 'last_name' => '', + 'mobile_number' => '', + 'plate_number' => '', + 'email' => '', + 'contact_num' => '', + 'address' => '', + ]; + $other_data = [ + 'odometer' => 0, + 'date_purchase' => $today->format('Y-m-d'), + 'invoice' => '', + 'warr_card' => '', + 'dealer_name' => '', + 'dealer_address' => '', + 'branch_code' => '', + ]; + + // set action for raffle log + $raffle_data['action'] = 'serial_check_not_customer'; + } + } else { + $can_edit = true; + $customer = [ + 'first_name' => '', + 'last_name' => '', + 'mobile_number' => '', + 'plate_number' => '', + 'email' => '', + 'contact_num' => '', + 'address' => '', + ]; + $other_data = [ + 'odometer' => 0, + 'date_purchase' => $today->format('Y-m-d'), + 'invoice' => '', + 'warr_card' => '', + 'dealer_name' => '', + 'dealer_address' => '', + 'branch_code' => '', + ]; + + // set action for raffle log + $raffle_data['action'] = 'serial_check_customer'; + } + + $sku = $warr_serial->getSKU(); + $batt = null; + $cat_name = ''; + if ($sku != null) + $batt = $this->em->getRepository(SAPBattery::class)->find($sku); + else { + // get the category name of the serial + $cat_name = $warr_serial->getMetaInfo('category_name'); + } + + // TODO: put this in a config file + $image_url = $req->getSchemeAndHttpHost() . '/battery/generic.png'; + if ($batt != null) { + $battery = [ + 'brand' => $batt->getBrand()->getName(), + 'size' => $batt->getSize()->getName(), + 'image_url' => $image_url, + ]; + } else { + $battery = [ + 'brand' => $cat_name, + 'size' => '', + 'image_url' => '', + ]; + } + + // set the rest of the raffle log entry + $raffle_data['bmodel_name'] = $battery['brand']; + $raffle_data['bsize_name'] = $battery['size']; + + // log the raffle log + $raffle_logger->logRaffleInfo($data_sent, $raffle_data); + + // response + return new ApiResponse(true, '', [ + 'is_valid' => true, + 'is_registered' => $is_registered, + 'can_edit' => $can_edit, + 'customer' => $customer, + 'battery' => $battery, + 'odometer' => $other_data['odometer'], + 'invoice' => $other_data['invoice'], + 'warr_card' => $other_data['warr_card'], + 'date_purchase' => $other_data['date_purchase'], + 'dealer_name' => $other_data['dealer_name'], + 'dealer_address' => $other_data['dealer_address'], + 'branch_code' => $other_data['branch_code'], + 'message' => [ + 'register_error' => 'Warranty serial code has already been registered.', + 'edit_error' => 'Sorry, warranty is registered under another vehicle not in your list of vehicles.', + ], + ]); + } + + public function warrantyRegister( + $serial, + Request $req, + KernelInterface $kernel, + RisingTideGateway $rt, + TranslatorInterface $trans, + WarrantyRaffleLogger $raffle_logger, + WarrantyAPILogger $logger + ) { + // validate params + $validity = $this->validateRequest($req, [ + 'first_name', + 'last_name', + 'plate_number', + 'date_purchase', + ]); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // handle file uploads + $invoice = $req->files->get('invoice'); + $warr_card = $req->files->get('warr_card'); + + // normalize serial + $serial = $this->cleanSerial($serial); + // $serial = trim(strtoupper($serial)); + + // process picture uploads + $upload_dir = $kernel->getProjectDir() . '/public/warranty_uploads'; + $inv_filename = $this->handlePictureUpload($invoice, $upload_dir, $serial, 'invoice'); + $wcard_filename = $this->handlePictureUpload($warr_card, $upload_dir, $serial, 'wcard'); + + $user_id = $req->query->get('session_key'); + $log_data = [ + 'plate_number' => $req->request->get('plate_num'), + 'first_name' => $req->request->get('first_name'), + 'last_name' => $req->request->get('last_name'), + 'date_purchase' => $req->request->get('date_purchase'), + ]; + $action = 'create/update'; + $source = WarrantySource::MOBILE; + + // update customer information + // $cust = $this->updateCustomerInfo($req, $em); + + // update warranty + $res = $this->updateWarranty( + $rt, + $trans, + $req, + $serial, + $inv_filename, + $wcard_filename, + $logger, + $log_data, + $user_id, + $action, + $source, + $raffle_logger + ); + if (!$res['success']) { + return new ApiResponse(false, $res['error']); + } + + $this->em->flush(); + + return new ApiResponse(); + } + + protected function handlePictureUpload($file, $target_dir, $serial, $name) + { + // error_log("handling $name upload"); + // no file sent + if ($file == null) { + error_log("handling $name upload - no file"); + return null; + } + + // create target dir if it doesn't exist + if (!file_exists($target_dir)) { + if (!mkdir($target_dir, 0744, true)) { + error_log('failed to create folder for warranty pictures'); + return null; + } + } + + // move file + $filename = $name . '.' . $file->getClientOriginalExtension(); + $file->move($target_dir . '/' . $serial, $filename); + + // error_log("filename - $filename"); + // error_log($target_dir . '/' . $serial . '/' . $filename); + + return $serial . '/' . $filename; + } + + // TODO: put this in a service + protected function cleanSerial($serial) + { + // trim and make everything upper case + $clean_serial = trim(strtoupper($serial)); + + + // remove QR prefix if it exists + // $prefix = substr($clean_serial, 0, 2); + // if ($prefix == 'QR') + // $clean_serial = substr($clean_serial, 2); + + return $clean_serial; + } + + protected function checkCustomerPlateNumber($plate_number, $cust) + { + // strip spaces and make all caps + $plate_number = preg_replace('/\s+/', '', strtoupper($plate_number)); + + // if there's no customer linked to session + if ($cust != null) { + // check all the customer vehicles + $cvs = $cust->getVehicles(); + foreach ($cvs as $cv) { + $cv_plate = preg_replace('/\s+/', '', strtoupper($cv->getPlateNumber())); + + // did we find a match? + if ($cv_plate == $plate_number) { + return true; + } + } + } + + return false; + } + + protected function updateWarranty($rt, $trans, $req, $serial, $inv_filename = null, $wcard_filename = null, $logger, $log_data, $user_id, $action, $source, $raffle_logger) + { + // prepare raffle log entry + $raffle_data = [ + 'user_id' => $user_id, + 'serial' => $serial, + 'warranty_id' => null, + 'action' => '', + 'bmodel_name' => '', + 'bsize_name' => '', + 'first_name' => '', + 'last_name' => '', + 'plate_number' => '', + 'contact_num' => '', + 'email' => '', + 'address' => '', + ]; + + // get serial + $warr_serial = $this->em->getRepository(WarrantySerial::class)->find($serial); + if ($warr_serial == null) { + return [ + 'success' => false, + 'error' => 'Invalid warranty serial code.', + ]; + } + + // check if warranty exists already + $warr = $this->em->getRepository(Warranty::class)->findOneBy(['serial' => $serial]); + + // skip warranty if it already exists + if ($warr != null) { + /* + // NOTE: we could not update in the old version + $res->setError(true) + ->setErrorMessage('Warranty registration entry already exists.'); + return $res; + */ + + // check if warranty is registered to a serial owned by customer + $warr_plate = $warr->getPlateNumber(); + $cust = $this->session->getCustomer(); + $is_customer_warranty = $this->checkCustomerPlateNumber($warr_plate, $cust); + + if (!$is_customer_warranty) { + $error_msg = 'Warranty registered to a vehicle not in your list of vehicles.'; + + // set action to update + $action = 'update'; + $logger->logWarrantyInfo($log_data, $error_msg, $user_id, $action, $source); + + // response + return [ + 'success' => false, + 'error' => $error_msg, + ]; + } + + $sms_msg = $trans->trans('warranty_update_confirm'); + + // update raffle data action + $raffle_data['action'] = 'warranty_update'; + } else { + $warr = new Warranty(); + $sms_msg = $trans->trans('warranty_register_confirm'); + + // set warranty source + $warr->setCreateSource($source); + + // update raffle data action + $raffle_data['action'] = 'warranty_create'; + } + + // get sap battery + $sku = $warr_serial->getSKU(); + $sap_bty = null; + if ($sku != null) { + $sap_bty = $this->em->getRepository(SAPBattery::class)->find($sku); + if ($sap_bty == null) { + $error_msg = 'Could not find battery entry for warranty.'; + $logger->logWarrantyInfo($log_data, $error_msg, $user_id, $action, $source); + + // response + return [ + 'success' => false, + 'error' => $error_msg, + ]; + } + } + + // default date purchase to today + // NOTE: might need to change this later + $date_pur = new DateTime(); + + // get date purchase specified by customer + $date_pur_cust = DateTime::createFromFormat('Y-m-d', $req->request->get('date_purchase')); + if (!$date_pur_cust) { + $error_msg = 'Invalid date format for date of purchase.'; + $logger->logWarrantyInfo($log_data, $error_msg, $user_id, $action, $source); + + // response + return [ + 'success' => false, + 'error' => $error_msg, + ]; + } + + $customer = $this->session->getCustomer(); + if ($customer != null) { + $warr->setCustomer($customer); + // get customer vehicles + + $vehicle = $this->findCustomerVehicle($customer, $req->request->get('plate_number')); + if ($vehicle != null) + $warr->setVehicle($vehicle); + } + + // TODO: make a standard clean plate number service + // clean plate number + $plate = $req->request->get('plate_number'); + // upper case and remove spaces + $plate = strtoupper(str_replace(' ', '', $plate)); + // remove special characters + $plate = preg_replace('/[^A-Za-z0-9. -]/', '', $plate); + + // create or update warranty entry + $warr->setSerial($serial) + ->setFirstName($req->request->get('first_name')) + ->setLastName($req->request->get('last_name')) + ->setEmail($req->request->get('email')) + ->setPlateNumber($plate) + // TODO: figure out how to compute date of purchase + ->setDatePurchase($date_pur) + // TODO: set status + // ->setStatus() + // TODO: set battery model and size id + // ->setBatterySize() + // ->setBatteryModel() + ->setSAPBattery($sap_bty) + ->setMobileNumber(substr($this->session->getPhoneNumber(), 2)) + ->setActivated(true) + + // files + ->setFileInvoice($inv_filename) + ->setFileWarrantyCard($wcard_filename) + + // new fields + ->setOdometer($req->request->get('odometer', 0)) + ->setDatePurchaseCustomer($date_pur_cust) + ->setContactNumber($req->request->get('contact_num')) + ->setCustomerAddress($req->request->get('cust_address')) + ->setDealerName($req->request->get('dealer_name')) + ->setDealerAddress($req->request->get('dealer_address')) + ->setDealerBranchCode($req->request->get('branch_code')) + ->setValidated(false); + + // TODO: check for date purchase and date expire + + $this->em->persist($warr); + + // TODO: check if we need to do anyting else + $logger->logWarrantyInfo($log_data, '', $user_id, $action, $source); + + // send sms + // error_log('sending sms to - ' . $this->session->getPhoneNumber()); + $rt->sendSMS($this->session->getPhoneNumber(), $trans->trans('message.battery_brand_allcaps'), $sms_msg); + + // prepare the rest of the raffle log entry + $raffle_data['warranty_id'] = $warr->getID(); + $raffle_data['bmodel_name'] = $sap_bty->getBrand()->getName(); + $raffle_data['bsize_name'] = $sap_bty->getSize()->getName(); + $raffle_data['first_name'] = $req->request->get('first_name', ''); + $raffle_data['last_name'] = $req->request->get('last_name', ''); + $raffle_data['plate_number'] = $plate; + $raffle_data['contact_num'] = $req->request->get('contact_num', ''); + $raffle_data['email'] = $req->request->get('email', ''); + $raffle_data['address'] = $req->request->get('cust_address', ''); + + $data_sent = [ + 'plate_number' => $req->request->get('plate_number'), + 'first_name' => $req->request->get('first_name'), + 'last_name' => $req->request->get('last_name'), + 'date_purchase' => $req->request->get('date_purchase'), + 'address' => $req->request->get('cust_address', ''), + 'email' => $req->request->get('email', ''), + 'contact_num' => $req->request->get('contact_num', ''), + ]; + + // log raffle data + $raffle_logger->logRaffleInfo($data_sent, $raffle_data); + + // response + return [ + 'success' => true, + ]; + } + + protected function findCustomerVehicle($customer, $plate_number) + { + $clean_plate = Warranty::cleanPlateNumber($plate_number); + if ($clean_plate) { + // find the customer vehicle and get the vehicle + $cv = $this->em->getRepository(CustomerVehicle::class)->findOneBy(['plate_number' => $clean_plate, 'customer' => $customer]); + if ($cv != null) { + $vehicle = $cv->getVehicle(); + return $vehicle; + } + } + + return null; + } +} diff --git a/src/Controller/InsuranceController.php b/src/Controller/InsuranceController.php new file mode 100644 index 00000000..b720253e --- /dev/null +++ b/src/Controller/InsuranceController.php @@ -0,0 +1,23 @@ +request->all(); + error_log(print_r($payload, true)); + + return $this->json([ + 'success' => true, + 'payload' => $payload, + ]); + } +} diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index f3597173..30bc519c 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -21,6 +21,8 @@ use App\Service\JobOrderHandlerInterface; use App\Service\GISManagerInterface; use App\Service\MapTools; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Service\InventoryManager; use App\Service\HubSelector; @@ -29,7 +31,6 @@ use App\Service\RiderTracker; use App\Service\MotivConnector; use App\Service\GeofenceTracker; - use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -354,7 +355,7 @@ class JobOrderController extends Controller return $this->render($template, $params); } - public function processingSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, $id) + public function processingSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, $id) { $this->denyAccessUnlessGranted('jo_proc.list', null, 'No access.'); @@ -362,7 +363,7 @@ class JobOrderController extends Controller $error_array = []; try { - $error_array = $jo_handler->dispatchJobOrder($req, $id, $mclient); + $error_array = $jo_handler->dispatchJobOrder($req, $id, $mclient, $mclientv2, $fcmclient); } catch (AccessDeniedHttpException $e) { @@ -421,7 +422,7 @@ class JobOrderController extends Controller } - public function assigningSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTCLient $mclient, APNSClient $aclient, $id) + public function assigningSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTCLient $mclient, FCMSender $fcmclient, APNSClient $aclient, $id) { $this->denyAccessUnlessGranted('jo_assign.list', null, 'No access.'); @@ -481,7 +482,7 @@ class JobOrderController extends Controller return $this->render($template, $params); } - public function fulfillmentSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, $id) + public function fulfillmentSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, FCMSender $fcmclient, $id) { $this->denyAccessUnlessGranted('jo_fulfill.list', null, 'No access.'); @@ -540,7 +541,7 @@ class JobOrderController extends Controller return $this->render($template, $params); } - public function openHubSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, $id) + public function openHubSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, $id) { $this->denyAccessUnlessGranted('jo_open.list', null, 'No access.'); @@ -549,7 +550,7 @@ class JobOrderController extends Controller try { - $error_array = $jo_handler->setHub($req, $id, $mclient); + $error_array = $jo_handler->setHub($req, $id, $mclient, $mclientv2, $fcmclient); } catch (NotFoundHttpException $e) { @@ -598,7 +599,7 @@ class JobOrderController extends Controller return $this->render($template, $params); } - public function openRiderSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, $id) + public function openRiderSubmit(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, $id) { $this->denyAccessUnlessGranted('jo_open.list', null, 'No access.'); @@ -607,7 +608,7 @@ class JobOrderController extends Controller try { - $error_array = $jo_handler->setRider($req, $id, $mclient); + $error_array = $jo_handler->setRider($req, $id, $mclient, $mclientv2, $fcmclient); } catch (NotFoundHttpException $e) { @@ -681,7 +682,7 @@ class JobOrderController extends Controller ]); } - public function cancelJobOrder(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, $id) + public function cancelJobOrder(Request $req, JobOrderHandlerInterface $jo_handler, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, $id) { $this->denyAccessUnlessGranted('joborder.cancel', null, 'No access.'); @@ -698,7 +699,7 @@ class JobOrderController extends Controller try { - $jo_handler->cancelJobOrder($req, $id, $mclient); + $jo_handler->cancelJobOrder($req, $id, $mclient, $mclientv2, $fcmclient); } catch (NotFoundHttpException $e) { diff --git a/src/Controller/MotoliteEventController.php b/src/Controller/MotoliteEventController.php new file mode 100644 index 00000000..e0770b05 --- /dev/null +++ b/src/Controller/MotoliteEventController.php @@ -0,0 +1,304 @@ +denyAccessUnlessGranted('motolite_event.list', null, 'No access.'); + + return $this->render('motolite-event/list.html.twig'); + } + + public function rows(Request $req) + { + $this->denyAccessUnlessGranted('motolite_event.list', null, 'No access.'); + + // get query builder + $qb = $this->getDoctrine() + ->getRepository(MotoliteEvent::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.event_time', '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['name'] = $orow->getName(); + $row['event_type'] = MotoliteEventType::getName($orow->getEventType()); + $row['event_time'] = $orow->getEventTime()->format("d M Y g:i A"); + $row['url'] = 'Link'; + $row['image_file'] = $orow->getImageFile(); + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('motolite_event.update')) + $row['meta']['update_url'] = $this->generateUrl('motolite_event_update', ['id' => $row['id']]); + if ($this->isGranted('motolite_event.delete')) + $row['meta']['delete_url'] = $this->generateUrl('motolite_event_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + /** + * @Menu(selected="motolite_event_list") + */ + public function addForm() + { + $this->denyAccessUnlessGranted('motolite_event.add', null, 'No access.'); + + $params = []; + $params['obj'] = new MotoliteEvent(); + $params['mode'] = 'create'; + + $params['event_types'] = MotoliteEventType::getCollection(); + + $em = $this->getDoctrine()->getManager(); + + // response + return $this->render('motolite-event/form.html.twig', $params); + } + + public function addSubmit(Request $req, EncoderFactoryInterface $ef, ValidatorInterface $validator) + { + $this->denyAccessUnlessGranted('motolite_event.add', null, 'No access.'); + + // create new object + $em = $this->getDoctrine()->getManager(); + $obj = new MotoliteEvent(); + + $this->setObject($obj, $req); + + // validate + $errors = $validator->validate($obj); + + // 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($obj); + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @Menu(selected="motolite_event_list") + */ + public function updateForm($id) + { + $this->denyAccessUnlessGranted('motolite_event.update', null, 'No access.'); + + // get row data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(MotoliteEvent::class)->find($id); + + // make sure this row exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + $params = []; + $params['obj'] = $obj; + $params['mode'] = 'update'; + + $params['event_types'] = MotoliteEventType::getCollection(); + + // response + return $this->render('motolite-event/form.html.twig', $params); + } + + public function updateSubmit(Request $req, EncoderFactoryInterface $ef, ValidatorInterface $validator, $id) + { + $this->denyAccessUnlessGranted('motolite_event.update', null, 'No access.'); + + // get object data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(MotoliteEvent::class)->find($id); + + // make sure this object exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + $this->setObject($obj, $req); + + // validate + $errors = $validator->validate($obj); + + // 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!' + ]); + } + + public function destroy($id) + { + $this->denyAccessUnlessGranted('motolite_event.delete', null, 'No access.'); + + // get object data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(MotoliteEvent::class)->find($id); + + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + // delete this object + $em->remove($obj); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->orWhere('q.url LIKE :filter') + ->orWhere('q.event_type LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } + + protected function setObject(MotoliteEvent $obj, Request $req) + { + // times + $format = "Y-m-d\TH:i"; + $event_time = DateTime::createFromFormat($format, $req->request->get('event_time')); + + $event_type = $req->request->get('event_type'); + + // set and save values + $obj->setName($req->request->get('name')) + ->setEventType($event_type) + ->setEventTime($event_time) + ->setUrl($req->request->get('url')) + ->setImageFile($req->request->get('image_file')); + } + + public function uploadImage(Request $req, FileUploader $uploader) + { + // retrieve temporary info for file + $file = $req->files->get('image_file'); + + // upload the file + $filename = $uploader->upload($file); + + // return response + return $this->json([ + 'success' => true, + 'filename' => $filename + ]); + } +} diff --git a/src/Controller/ReviewController.php b/src/Controller/ReviewController.php index 7d6d6e7d..ba0024e8 100644 --- a/src/Controller/ReviewController.php +++ b/src/Controller/ReviewController.php @@ -82,12 +82,22 @@ class ReviewController extends Controller $rows = []; foreach ($obj_rows as $orow) { + // get appropriate mobile session + $mobile_number = ""; + $mobile_session = $orow->getMobileSession(); + + if (!empty($mobile_session)) { + $mobile_number = $mobile_session->getPhoneNumber(); + } else { + $mobile_number = $orow->getCustomerSession()->getPhoneNumber(); + } + // add row data $row['id'] = $orow->getID(); $row['partner'] = $orow->getPartner()->getName(); $row['rating'] = $orow->getRating(); $row['message'] = $orow->getMessage(); - $row['mobile_number'] = $orow->getMobileSession()->getPhoneNumber(); + $row['mobile_number'] = $mobile_number; // add row metadata $row['meta'] = [ diff --git a/src/Controller/ReviewTagController.php b/src/Controller/ReviewTagController.php new file mode 100644 index 00000000..b53b796c --- /dev/null +++ b/src/Controller/ReviewTagController.php @@ -0,0 +1,267 @@ +denyAccessUnlessGranted('review_tag.list', null, 'No access.'); + + return $this->render('review-tag/list.html.twig'); + } + + public function rows(Request $req) + { + $this->denyAccessUnlessGranted('review_tag.list', null, 'No access.'); + + // get query builder + $qb = $this->getDoctrine() + ->getRepository(ReviewTag::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['name'] = $orow->getName(); + $row['type'] = ucfirst($orow->getType()); + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('review_tag.update')) + $row['meta']['update_url'] = $this->generateUrl('reviewtag_update', ['id' => $row['id']]); + if ($this->isGranted('review_tag.delete')) + $row['meta']['delete_url'] = $this->generateUrl('reviewtag_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } + + /** + * @Menu(selected="review_tag_list") + */ + public function addForm() + { + $this->denyAccessUnlessGranted('review_tag.add', null, 'No access.'); + + $params['obj'] = new ReviewTag(); + $params['mode'] = 'create'; + + $params['types'] = ReviewTagType::getCollection(); + + // response + return $this->render('review-tag/form.html.twig', $params); + } + + public function addSubmit(Request $req, ValidatorInterface $validator) + { + $this->denyAccessUnlessGranted('review_tag.add', null, 'No access.'); + + // create new object + $em = $this->getDoctrine()->getManager(); + $obj = new ReviewTag(); + + $obj->setName($req->request->get('name')) + ->setType($req->request->get('type')); + + // validate + $errors = $validator->validate($obj); + + // 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); + } else { + // validated! save the entity + $em->persist($obj); + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + } + + /** + * @Menu(selected="review_tag_list") + */ + public function updateForm($id) + { + $this->denyAccessUnlessGranted('review_tag.update', null, 'No access.'); + + // get row data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(ReviewTag::class)->find($id); + + // make sure this row exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + $params['obj'] = $obj; + $params['mode'] = 'update'; + + $params['types'] = ReviewTagType::getCollection(); + + // response + return $this->render('review-tag/form.html.twig', $params); + } + + public function updateSubmit(Request $req, ValidatorInterface $validator, $id) + { + $this->denyAccessUnlessGranted('review_tag.update', null, 'No access.'); + + // get object data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(ReviewTag::class)->find($id); + + // make sure this object exists + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + $obj->setName($req->request->get('name')) + ->setType($req->request->get('type')); + + // validate + $errors = $validator->validate($obj); + + // 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!' + ]); + } + + public function destroy($id) + { + $this->denyAccessUnlessGranted('review_tag.delete', null, 'No access.'); + + // get object data + $em = $this->getDoctrine()->getManager(); + $obj = $em->getRepository(ReviewTag::class)->find($id); + + if (empty($obj)) + throw $this->createNotFoundException('The item does not exist'); + + // delete this object + $em->remove($obj); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } +} + diff --git a/src/Controller/RiderController.php b/src/Controller/RiderController.php index c53ac626..25e63a4c 100644 --- a/src/Controller/RiderController.php +++ b/src/Controller/RiderController.php @@ -25,8 +25,8 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Catalyst\MenuBundle\Annotation\Menu; -use Catalyst\APIBundle\Entity\User as APIUser; -use Catalyst\APIBundle\Entity\Role as APIRole; +use App\Entity\ApiUser as APIUser; +use Catalyst\ApiBundle\Entity\Role as APIRole; use DateTime; diff --git a/src/Controller/TAPI/BatteryController.php b/src/Controller/TAPI/BatteryController.php index 0874b792..96210605 100644 --- a/src/Controller/TAPI/BatteryController.php +++ b/src/Controller/TAPI/BatteryController.php @@ -8,13 +8,13 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Ramcar\APIResult; use App\Entity\Vehicle; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class BatteryController extends APIController { diff --git a/src/Controller/TAPI/JobOrderController.php b/src/Controller/TAPI/JobOrderController.php index 88e4b128..8275cbbd 100644 --- a/src/Controller/TAPI/JobOrderController.php +++ b/src/Controller/TAPI/JobOrderController.php @@ -11,8 +11,8 @@ use Doctrine\ORM\EntityManagerInterface; use CrEOF\Spatial\PHP\Types\Geometry\Point; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Ramcar\WarrantyClass; use App\Ramcar\JOStatus; @@ -33,6 +33,8 @@ use App\Ramcar\DeliveryStatus; use App\Service\InvoiceGeneratorInterface; use App\Service\RisingTideGateway; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\GeofenceTracker; use App\Service\InventoryManager; use App\Service\RiderAssignmentHandlerInterface; @@ -59,7 +61,7 @@ use App\Entity\Warranty; use DateTime; use DateInterval; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class JobOrderController extends APIController { @@ -72,7 +74,8 @@ class JobOrderController extends APIController // TODO: break this monolithic method down public function requestJobOrder(Request $req, InvoiceGeneratorInterface $ic, GeofenceTracker $geo, - InventoryManager $im, MQTTClient $mclient, + InventoryManager $im, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, + FCMSender $fcmclient, RiderAssignmentHandlerInterface $rah, PromoLogger $promo_logger, HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em) @@ -356,6 +359,10 @@ class JobOrderController extends APIController ]; $mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + $rah->assignJobOrder($jo, $jo->getRider()); } @@ -374,6 +381,10 @@ class JobOrderController extends APIController 'event' => 'outlet_assign' ]; $mclient->sendEvent($jo, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); } $em->flush(); diff --git a/src/Controller/TAPI/PromoController.php b/src/Controller/TAPI/PromoController.php index 90cbaf0a..9961b7ec 100644 --- a/src/Controller/TAPI/PromoController.php +++ b/src/Controller/TAPI/PromoController.php @@ -8,12 +8,12 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Promo; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class PromoController extends APIController { diff --git a/src/Controller/TAPI/ServiceController.php b/src/Controller/TAPI/ServiceController.php index 5f468cd8..3cf3f8da 100644 --- a/src/Controller/TAPI/ServiceController.php +++ b/src/Controller/TAPI/ServiceController.php @@ -8,12 +8,12 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\Service; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class ServiceController extends APIController { diff --git a/src/Controller/TAPI/VehicleController.php b/src/Controller/TAPI/VehicleController.php index 5e8bf122..d1ed822f 100644 --- a/src/Controller/TAPI/VehicleController.php +++ b/src/Controller/TAPI/VehicleController.php @@ -8,13 +8,13 @@ use Symfony\Component\HttpFoundation\Request; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; -use Catalyst\APIBundle\Controller\APIController; -use Catalyst\APIBundle\Response\APIResponse; +use Catalyst\ApiBundle\Controller\ApiController; +use Catalyst\ApiBundle\Response\APIResponse; use App\Entity\VehicleManufacturer; use App\Entity\Vehicle; -use Catalyst\APIBundle\Access\Generator as ACLGenerator; +use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; class VehicleController extends APIController { diff --git a/src/Entity/ApiUser.php b/src/Entity/ApiUser.php new file mode 100644 index 00000000..bb79df89 --- /dev/null +++ b/src/Entity/ApiUser.php @@ -0,0 +1,66 @@ +name = $name; + return $this; + } + + public function getName() + { + return $this->name; + } + + public function setMetadata($meta) + { + $this->metadata = $meta; + return $this; + } + + public function getMetadata() + { + if ($this->metadata == null) + return []; + + return $this->metadata; + } + + public function setRider($rider) + { + $this->rider = $rider; + return $this; + } + + public function getRider() + { + return $this->rider; + } +} diff --git a/src/Entity/CreditTransaction.php b/src/Entity/CreditTransaction.php new file mode 100644 index 00000000..599a4851 --- /dev/null +++ b/src/Entity/CreditTransaction.php @@ -0,0 +1,92 @@ +date_create = new DateTime(); + } + + public function getID() + { + return $this->id; + } + + public function setCustomer(Customer $customer) + { + $this->customer = $customer; + return $this; + } + + public function setType($transaction_type) + { + $this->transaction_type = $transaction_type; + return $this; + } + + public function getType() + { + return $this->transaction_type; + } + + public function setAmount($amount) + { + $this->amount = $amount; + return $this; + } + + public function getAmount() + { + return $this->amount; + } + + public function getCustomer() + { + return $this->customer; + } +} diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index de2cd92e..271ef95e 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -96,6 +96,13 @@ class Customer */ protected $sessions; + // link to customer user + /** + * @ORM\OneToOne(targetEntity="CustomerUser", inversedBy="customer") + * @ORM\JoinColumn(name="customer_user_id", referencedColumnName="id", nullable=true) + */ + protected $customer_user; + // vehicles linked to customer /** * @ORM\OneToMany(targetEntity="CustomerVehicle", mappedBy="customer", cascade={"persist"}) @@ -208,6 +215,11 @@ class Customer */ protected $create_source; + /** + * @ORM\Column(type="integer", options={"unsigned": true, "default":0}) + */ + protected $credits; + // customer tags /** * @ORM\ManyToMany(targetEntity="CustomerTag", inversedBy="customers", indexBy="id") @@ -267,6 +279,8 @@ class Customer $this->create_source = 'unknown'; $this->ratings = new ArrayCollection(); + + $this->credits = 0; } public function getID() @@ -682,4 +696,26 @@ class Customer { return $this->car_club_customer_hub; } + + public function setCustomerUser(CustomerUser $cust_user = null) + { + $this->customer_user = $cust_user; + return $this; + } + + public function getCustomerUser() + { + return $this->customer_user; + } + + public function modifyCredits($amount) + { + $this->credits = bcadd($this->credits, $amount); + return $this; + } + + public function getCredits() + { + return $this->credits; + } } diff --git a/src/Entity/CustomerMetadata.php b/src/Entity/CustomerMetadata.php index 5ef9d518..af0fc6a7 100644 --- a/src/Entity/CustomerMetadata.php +++ b/src/Entity/CustomerMetadata.php @@ -63,6 +63,12 @@ class CustomerMetadata return $this; } + public function deleteMetadataInfo($id) + { + unset($this->meta_info[$id]); + return $this; + } + public function getMetaInfo($id) { // return null if we don't have it diff --git a/src/Entity/CustomerSession.php b/src/Entity/CustomerSession.php new file mode 100644 index 00000000..77f453aa --- /dev/null +++ b/src/Entity/CustomerSession.php @@ -0,0 +1,273 @@ +id = $this->generateKeyID(); + $this->date_generated = new DateTime(); + $this->customer_user = null; + $this->confirm_flag = false; + $this->date_confirmed = null; + $this->date_code_sent = null; + $this->reviews = new ArrayCollection(); + } + + public function generateKeyID() + { + // use uniqid for now, since primary key dupes will trigger exceptions + return uniqid(); + } + + public function getID() + { + return $this->id; + } + + public function setPhoneNumber($num) + { + $this->phone_number = $num; + return $this; + } + + public function getPhoneNumber() + { + return $this->phone_number; + } + + public function setPhoneModel($model) + { + $this->phone_model = $model; + return $this; + } + + public function getPhoneModel() + { + return $this->phone_model; + } + + public function setOSType($type) + { + $this->os_type = $type; + return $this; + } + + public function getOSType() + { + return $this->os_type; + } + + public function setOSVersion($version) + { + $this->os_version = $version; + return $this; + } + + public function getOSVersion() + { + return $this->os_version; + } + + public function setPhoneID($id) + { + $this->phone_id = $id; + return $this; + } + + public function getPhoneID() + { + return $this->phone_id; + } + + public function setDevicePushID($id) + { + $this->device_push_id = $id; + return $this; + } + + public function getDevicePushID() + { + return $this->device_push_id; + } + + public function setCustomer(Customer $cust = null) + { + $this->customer = $cust; + return $this; + } + + public function getCustomer() + { + return $this->customer; + } + + public function setCustomerUser(CustomerUser $cust_user = null) + { + $this->customer_user = $cust_user; + return $this; + } + + public function getCustomerUser() + { + return $this->customer_user; + } + + public function getDateGenerated() + { + return $this->date_generated; + } + + public function setConfirmCode($code) + { + $this->confirm_code = $code; + return $this; + } + + public function getConfirmCode() + { + return $this->confirm_code; + } + + public function setConfirmed($flag = true) + { + $this->confirm_flag = $flag; + return $this; + } + + public function isConfirmed() + { + return $this->confirm_flag; + } + + public function setDateConfirmed(DateTime $date) + { + $this->date_confirmed = $date; + return $this; + } + + public function getDateConfirmed() + { + return $this->date_confirmed; + } + + public function setDateCodeSent(DateTime $date) + { + $this->date_code_sent = $date; + return $this; + } + + public function getDateCodeSent() + { + return $this->date_code_sent; + } + + public function getReviews() + { + return $this->reviews; + } +} diff --git a/src/Entity/CustomerUser.php b/src/Entity/CustomerUser.php new file mode 100644 index 00000000..3f8c3b6b --- /dev/null +++ b/src/Entity/CustomerUser.php @@ -0,0 +1,106 @@ +metadata = []; + $this->sessions = new ArrayCollection(); + } + + public function setMetadata($meta) + { + $this->metadata = $meta; + return $this; + } + + public function getMetadata() + { + if ($this->metadata == null) + return []; + + return $this->metadata; + } + + public function setPhoneNumber($num) + { + $this->phone_number = $num; + return $this; + } + + public function getPhoneNumber() + { + return $this->phone_number; + } + + public function addMobileSession(MobileSession $session) + { + $this->sessions->add($session); + return $this; + } + + public function clearMobileSessions() + { + $this->sessions->clear(); + return $this; + } + + public function getMobileSessions() + { + return $this->sessions; + } + + public function setCustomer(Customer $cust = null) + { + $this->customer = $cust; + return $this; + } + + public function getCustomer() + { + return $this->customer; + } +} diff --git a/src/Entity/MotoliteEvent.php b/src/Entity/MotoliteEvent.php new file mode 100644 index 00000000..ccdb367b --- /dev/null +++ b/src/Entity/MotoliteEvent.php @@ -0,0 +1,123 @@ +event_time = new DateTime('today noon'); + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getID() + { + return $this->id; + } + + public function setID($id) + { + $this->id = $id; + return $this; + } + + public function getName() + { + return $this->name; + } + + public function setEventType($event_type) + { + $this->event_type = $event_type; + return $this; + } + + public function getEventType() + { + return $this->event_type; + } + + public function setEventTime($event_time) + { + $this->event_time = $event_time; + return $this; + } + + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + public function getUrl() + { + return $this->url; + } + + public function getEventTime() + { + return $this->event_time; + } + + public function setImageFile($image_file = null) + { + $this->image_file = $image_file; + return $this; + } + + public function getImageFile() + { + return $this->image_file; + } +} diff --git a/src/Entity/Review.php b/src/Entity/Review.php index 9903784e..c34f7647 100644 --- a/src/Entity/Review.php +++ b/src/Entity/Review.php @@ -48,10 +48,17 @@ class Review // mobile session that sent review /** * @ORM\ManyToOne(targetEntity="MobileSession", inversedBy="reviews") - * @ORM\JoinColumn(name="mobile_session_id", referencedColumnName="id") + * @ORM\JoinColumn(name="mobile_session_id", referencedColumnName="id", nullable=true) */ protected $mobile_session; + // customer session (new) that sent review + /** + * @ORM\ManyToOne(targetEntity="CustomerSession", inversedBy="reviews") + * @ORM\JoinColumn(name="customer_session_id", referencedColumnName="id", nullable=true) + */ + protected $customer_session; + public function __construct() { $this->date_create = new DateTime(); @@ -113,5 +120,15 @@ class Review { return $this->mobile_session; } + + public function setCustomerSession(CustomerSession $customer_session) + { + $this->customer_session = $customer_session; + return $this; + } + public function getCustomerSession() + { + return $this->customer_session; + } } diff --git a/src/Entity/ReviewTag.php b/src/Entity/ReviewTag.php new file mode 100644 index 00000000..577686ff --- /dev/null +++ b/src/Entity/ReviewTag.php @@ -0,0 +1,62 @@ +id; + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getName() + { + return $this->name; + } + + public function setType($type) + { + $this->type = $type; + return $this; + } + + public function getType() + { + return $this->type; + } + +} diff --git a/src/Entity/Rider.php b/src/Entity/Rider.php index 020393da..fcdb3ed2 100644 --- a/src/Entity/Rider.php +++ b/src/Entity/Rider.php @@ -9,7 +9,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; use App\Ramcar\JOStatus; -use Catalyst\APIBundle\Entity\User as APIUser; +use App\Entity\ApiUser as APIUser; /** * @ORM\Entity @@ -81,7 +81,7 @@ class Rider // current rating of rider /** - * @ORM\Column(type="integer") + * @ORM\Column(type="float") */ protected $curr_rating; @@ -131,7 +131,7 @@ class Rider protected $current_job_order; /** - * @ORM\OneToOne(targetEntity="Catalyst\APIBundle\Entity\User", inversedBy="rider") + * @ORM\OneToOne(targetEntity="App\Entity\ApiUser", inversedBy="rider") * @ORM\JoinColumn(name="api_user_id", referencedColumnName="id", nullable=true) */ protected $api_user; @@ -241,6 +241,17 @@ class Rider return $this->image_file; } + public function updateRatingAverage() + { + $total = 0; + + foreach ($this->ratings as $rating) { + $total += $rating->getRating(); + } + + $this->setCurrentRating(round($total / $this->ratings->count(), 2)); + } + public function setCurrentRating($rating) { $this->curr_rating = $rating; diff --git a/src/Entity/Service.php b/src/Entity/Service.php index e24cd672..cd373964 100644 --- a/src/Entity/Service.php +++ b/src/Entity/Service.php @@ -28,6 +28,12 @@ class Service */ protected $name; + // icon used by service on app + /** + * @ORM\Column(type="string", length=80, nullable=true) + */ + protected $icon; + // link to partners with this service /** * @ORM\ManyToMany(targetEntity="Partner", mappedBy="services", fetch="EXTRA_LAZY") @@ -55,6 +61,17 @@ class Service return $this->name; } + public function setIcon($icon) + { + $this->icon = $icon; + return $this; + } + + public function getIcon() + { + return $this->icon; + } + public function addPartner(Partner $partner) { $this->partners[$partner->getID()] = $partner; diff --git a/src/Ramcar/CreditTransactionType.php b/src/Ramcar/CreditTransactionType.php new file mode 100644 index 00000000..26a5dd38 --- /dev/null +++ b/src/Ramcar/CreditTransactionType.php @@ -0,0 +1,14 @@ + 'Purchase', + 'redemption' => 'Redemption', + ]; +} diff --git a/src/Ramcar/MotoliteEventType.php b/src/Ramcar/MotoliteEventType.php new file mode 100644 index 00000000..3f771ae0 --- /dev/null +++ b/src/Ramcar/MotoliteEventType.php @@ -0,0 +1,16 @@ + 'Event', + 'news' => 'News', + 'blog' => 'Blog', + ]; +} diff --git a/src/Ramcar/ReviewTagType.php b/src/Ramcar/ReviewTagType.php new file mode 100644 index 00000000..a659a29c --- /dev/null +++ b/src/Ramcar/ReviewTagType.php @@ -0,0 +1,14 @@ + 'Rider', + 'partner' => 'Partner', + ]; +} diff --git a/src/Ramcar/ServiceType.php b/src/Ramcar/ServiceType.php index 83768bdc..0a25e721 100644 --- a/src/Ramcar/ServiceType.php +++ b/src/Ramcar/ServiceType.php @@ -17,7 +17,7 @@ class ServiceType extends NameValue const COLLECTION = [ 'battery_new' => 'Battery Sales', 'battery_warranty' => 'Under Warranty', - 'jumpstart_troubleshoot' => 'General Service', + 'jumpstart_troubleshoot' => 'General Service - Jumpstart', 'jumpstart_warranty' => 'General Service - Warranty', 'post_recharged' => 'Post - Recharged', 'post_replacement' => 'Post - Replacement', diff --git a/src/Service/CreditManager.php b/src/Service/CreditManager.php new file mode 100644 index 00000000..275261bb --- /dev/null +++ b/src/Service/CreditManager.php @@ -0,0 +1,47 @@ +cust = $cust; + $this->em = $em; + } + + public function recordTransaction($type, $amount) + { + // make sure this is a valid transaction type + $this->validateType($type); + + // update customer + $this->cust->modifyCredits($amount); + + // create new record + $trans = new CreditTransaction(); + $trans->setCustomer($this->cust) + ->setAmount($amount) + ->setType($type); + + $this->em->persist($trans); + } + + protected function validateType($type) + { + if (!CreditTransactionType::validate($type)) { + throw new Exception('Invalid transaction type'); + } + } +} diff --git a/src/Service/FCMSender.php b/src/Service/FCMSender.php new file mode 100644 index 00000000..8130fe1a --- /dev/null +++ b/src/Service/FCMSender.php @@ -0,0 +1,94 @@ +client = new FcmClient($server_key, $sender_id); + $this->translator = $translator; + } + + public function send($recipients, $title, $body, $data = [], $color = null, $sound = null, $badge = null) + { + $notification = new Notification(); + $notification->setTitle($title) + ->setBody($body); + + foreach ($recipients as $recipient) { + $notification->addRecipient($recipient); + } + + if (!empty($color)) { + $notification->setColor($color); + } + + if (!empty($sound)) { + $notification->setSound($sound); + } + + if (!empty($color)) { + $notification->setColor($color); + } + + if (!empty($badge)) { + $notification->setBadge($badge); + } + + if (!empty($data)) { + $notification->addDataArray($data); + } + + return $this->client->send($notification); + } + + public function sendJoEvent(JobOrder $job_order, $title, $body, $data = []) + { + // get all v2 sessions + $sessions = []; + $cust_user = $job_order->getCustomer()->getCustomerUser(); + if (!empty($cust_user)) { + $sessions = $cust_user->getMobileSessions(); + } + + if (empty($sessions)) { + error_log("no sessions to send fcm notification to"); + return; + } + + $device_ids = []; + + // send to every customer session + foreach ($sessions as $sess) { + $device_id = $sess->getDevicePushID(); + + if (!empty($device_id)) { + // send fcm notification + $device_ids[] = $device_id; + } + } + + if (empty($device_ids)) { + error_log("no devices to send fcm notification to"); + return; + } + + // attach jo info + $data['jo_id'] = $job_order->getID(); + $data['jo_status'] = $job_order->getStatus(); + + // send fcm notification + $result = $this->send($device_ids, $this->translator->trans($title), $this->translator->trans($body), $data); + + return $result; + } +} diff --git a/src/Service/InsuranceConnector.php b/src/Service/InsuranceConnector.php new file mode 100644 index 00000000..e10066a2 --- /dev/null +++ b/src/Service/InsuranceConnector.php @@ -0,0 +1,100 @@ +base_url = $base_url; + $this->username = $username; + $this->password = $password; + $this->hash = $this->generateHash(); + } + + public function createApplication($notif_url, $client_info, $client_contact_info, $car_info) + { + $body = [ + 'notif_url' => $notif_url, + 'client_info' => $client_info, + 'client_contact_info' => $client_contact_info, + 'car_info' => $car_info, + ]; + + return $this->doRequest('/api/v1/ctpl/applications', true, $body); + } + + public function tagApplicationPaid($application_id) + { + $url = '/api/v1/ctpl/application/' . $application_id . '/paid'; + return $this->doRequest($url, true); + } + + public function getVehicleMakers() + { + return $this->doRequest('/api/v1/ctpl/vehicle-makers'); + } + + public function getVehicleModels() + { + return $this->doRequest('/api/v1/ctpl/vehicle-models'); + } + + public function getVehicleTrims() + { + return $this->doRequest('/api/v1/ctpl/vehicle-trims'); + } + + protected function generateHash() + { + return base64_encode($this->username . ":" . $this->password); + } + + protected function doRequest($url, $is_post = false, $body = []) + { + $curl = curl_init(); + + $options = [ + CURLOPT_URL => $this->base_url . '/' . $url, + CURLOPT_POST => $is_post, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Authorization: Basic ' . $this->hash, + ], + ]; + + // add post body if present + if (!empty($body)) { + $options[CURLOPT_POSTFIELDS] = json_encode($body); + } + + curl_setopt_array($curl, $options); + $res = curl_exec($curl); + + curl_close($curl); + + error_log('Insurance API connector'); + error_log(print_r($options, true)); + error_log($res); + + // response + return $this->handleResponse($res); + } + + protected function handleResponse($res) + { + $inv_res = json_decode($res, true); + + // make sure result is always an array + if ($inv_res == null) + return []; + + return $inv_res; + } +} diff --git a/src/Service/JobOrderHandler/CMBJobOrderHandler.php b/src/Service/JobOrderHandler/CMBJobOrderHandler.php index 24933e8f..43a7becb 100644 --- a/src/Service/JobOrderHandler/CMBJobOrderHandler.php +++ b/src/Service/JobOrderHandler/CMBJobOrderHandler.php @@ -46,6 +46,8 @@ use App\Service\RiderAssignmentHandlerInterface; use App\Service\CustomerHandlerInterface; use App\Service\WarrantyHandler; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Service\MapTools; @@ -668,7 +670,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface } // dispatch job order - public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient) + public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { // get object data $em = $this->em; @@ -793,6 +795,10 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface 'event' => 'outlet_assign' ]; $mclient->sendEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); } return $error_array; @@ -1027,7 +1033,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface } // cancel job order - public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient) + public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { // get object data $em = $this->em; @@ -1068,10 +1074,14 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_cancelled", "jo_fcm_body_cancelled", ['reason' => $cancel_reason]); } // set hub for job order - public function setHub($req, $id, $mclient) + public function setHub($req, $id, $mclient, $mclientv2, $fcmclient) { // get object data $em = $this->em; @@ -1171,6 +1181,10 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface 'event' => 'outlet_assign' ]; $mclient->sendEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); } return $error_array; @@ -1272,7 +1286,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface } // set rider for job order - public function setRider($req, $id, $mclient) + public function setRider($req, $id, $mclient, $mclientv2, $fcmclient) { // initialize error list $error_array = []; @@ -1372,6 +1386,10 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned"); } return $error_array; diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 3195cef4..1c213699 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -59,6 +59,8 @@ use App\Service\JobOrderHandlerInterface; use App\Service\RiderAssignmentHandlerInterface; use App\Service\WarrantyHandler; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Service\MapTools; use App\Service\RisingTideGateway; @@ -396,8 +398,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -674,8 +676,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -841,7 +843,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // dispatch job order - public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient) + public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { // get object data $em = $this->em; @@ -914,8 +916,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -1038,6 +1040,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + // update redis hub jo count $this->hub_dist->incrementJoCountForHub($hub); } @@ -1081,8 +1087,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -1239,8 +1245,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -1429,7 +1435,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // cancel job order - public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient) + public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient) { // get object data $em = $this->em; @@ -1474,10 +1480,14 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_cancelled", "jo_fcm_body_cancelled", ['reason' => $cancel_reason]); } // set hub for job order - public function setHub($req, $id, $mclient) + public function setHub($req, $id, $mclient, $mclientv2, $fcmclient) { // get object data $em = $this->em; @@ -1509,8 +1519,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // error_log($req->request->get('landmark')); @@ -1670,6 +1680,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + // update redis hub_jo_count for hub // decrement old hub's count and increment new hub's count if ($old_hub != null) @@ -1779,7 +1793,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // set rider for job order - public function setRider($req, $id, $mclient) + public function setRider($req, $id, $mclient, $mclientv2, $fcmclient) { // initialize error list $error_array = []; @@ -1811,8 +1825,8 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface } // check if landmark is set - if (empty($req->request->get('landmark'))) - $error_array['landmark'] = 'Landmark is required.'; + //if (empty($req->request->get('landmark'))) + // $error_array['landmark'] = 'Landmark is required.'; // check if customer is not willing to wait $will_wait = $req->request->get('flag_willing_to_wait'); @@ -1970,6 +1984,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface ]; $mclient->sendEvent($obj, $payload); $mclient->sendRiderEvent($obj, $payload); + + // NOTE: for resq2 app + $mclientv2->sendEvent($obj, $payload); + $fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned"); } return $error_array; diff --git a/src/Service/JobOrderHandlerInterface.php b/src/Service/JobOrderHandlerInterface.php index 644db54a..17041c06 100644 --- a/src/Service/JobOrderHandlerInterface.php +++ b/src/Service/JobOrderHandlerInterface.php @@ -5,6 +5,8 @@ namespace App\Service; use Symfony\Component\HttpFoundation\Request; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Service\MapTools; use App\Service\HubSelector; @@ -29,7 +31,7 @@ interface JobOrderHandlerInterface public function processOneStepJobOrder(Request $req, int $id); // dispatch job order - public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient); + public function dispatchJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient); // assign job order public function assignJobOrder(Request $req, int $id); @@ -38,16 +40,16 @@ interface JobOrderHandlerInterface public function fulfillJobOrder(Request $req, int $id); // cancel job order - public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient); + public function cancelJobOrder(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient); // set hub for job order - public function setHub(Request $req, int $id, MQTTClient $mclient); + public function setHub(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient); // reject hub for job order public function rejectHub(Request $req, int $id); // set rider for job order - public function setRider(Request $req, int $id, MQTTClient $mclient); + public function setRider(Request $req, int $id, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient); // unlock processor public function unlockProcessor(int $id); diff --git a/src/Service/MQTTClientApiv2.php b/src/Service/MQTTClientApiv2.php new file mode 100644 index 00000000..42b85648 --- /dev/null +++ b/src/Service/MQTTClientApiv2.php @@ -0,0 +1,71 @@ +redis = $redis_client->getRedisClient(); + $this->key = $key; + } + + public function __destruct() + { + // $this->mclient->disconnect(); + } + + public function publish($channel, $message) + { + // $this->mclient->publish($channel, $message); + + $data = $channel . '|' . $message; + $this->redis->lpush($this->key, $data); + } + + public function sendEvent(JobOrder $job_order, $payload) + { + //error_log('sending mqtt event: '); + //error_log(print_r($payload, true)); + + // get all v2 sessions + $sessions = []; + $cust_user = $job_order->getCustomer()->getCustomerUser(); + if (!empty($cust_user)) { + $sessions = $cust_user->getMobileSessions(); + } + + if (empty($sessions)) { + error_log("no sessions to send mqtt event to"); + return; + } + + $channels = []; + + // send to every customer session + foreach ($sessions as $sess) { + $phone_num = $sess->getPhoneNumber(); + $channel = self::PREFIX . $phone_num; + + // attach jo id to all payloads + $payload['jo_id'] = $job_order->getID(); + + // gather channels, so we only send once + $channels[$channel] = json_encode($payload); + } + + foreach ($channels as $channel => $json_payload) { + $this->publish($channel, $json_payload); + // error_log('sent to ' . $channel); + } + } +} diff --git a/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php b/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php index 3c0236e1..e35ab643 100644 --- a/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php +++ b/src/Service/RiderAPIHandler/CMBRiderAPIHandler.php @@ -18,6 +18,8 @@ use App\Service\RiderAPIHandlerInterface; use App\Service\RedisClientProvider; use App\Service\RiderCache; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\WarrantyHandler; use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; @@ -42,6 +44,8 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface protected $rcache; protected $country_code; protected $mclient; + protected $mclientv2; + protected $fcmclient; protected $wh; protected $jo_handler; protected $ic; @@ -49,7 +53,7 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface public function __construct(EntityManagerInterface $em, RedisClientProvider $redis, EncoderFactoryInterface $ef, RiderCache $rcache, - string $country_code, MQTTClient $mclient, + string $country_code, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, WarrantyHandler $wh, JobOrderHandlerInterface $jo_handler, InvoiceGeneratorInterface $ic) { @@ -59,6 +63,8 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface $this->rcache = $rcache; $this->country_code = $country_code; $this->mclient = $mclient; + $this->mclientv2 = $mclientv2; + $this->fcmclient = $fcmclient; $this->wh = $wh; $this->jo_handler = $jo_handler; $this->ic = $ic; @@ -424,6 +430,10 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $this->fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + return $data; } @@ -465,6 +475,10 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $this->fcmclient->sendJoEvent($jo, "jo_fcm_title_driver_arrived", "jo_fcm_body_driver_arrived"); + return $data; } @@ -578,6 +592,10 @@ class CMBRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $this->fcmclient->sendJoEvent($jo, "jo_fcm_title_fulfilled", "jo_fcm_body_fulfilled"); + return $data; } diff --git a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php index 97af80a2..f992f6e5 100644 --- a/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php +++ b/src/Service/RiderAPIHandler/ResqRiderAPIHandler.php @@ -21,6 +21,8 @@ use App\Service\RiderAPIHandlerInterface; use App\Service\RedisClientProvider; use App\Service\RiderCache; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\WarrantyHandler; use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; @@ -47,6 +49,8 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface protected $rcache; protected $country_code; protected $mclient; + protected $mclientv2; + protected $fcmclient; protected $wh; protected $jo_handler; protected $ic; @@ -56,7 +60,7 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface public function __construct(EntityManagerInterface $em, RedisClientProvider $redis, EncoderFactoryInterface $ef, RiderCache $rcache, - string $country_code, MQTTClient $mclient, + string $country_code, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, WarrantyHandler $wh, JobOrderHandlerInterface $jo_handler, InvoiceGeneratorInterface $ic, RisingTideGateway $rt, RiderTracker $rider_tracker, TranslatorInterface $translator) @@ -67,6 +71,8 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface $this->rcache = $rcache; $this->country_code = $country_code; $this->mclient = $mclient; + $this->mclientv2 = $mclientv2; + $this->fcmclient = $fcmclient; $this->wh = $wh; $this->jo_handler = $jo_handler; $this->ic = $ic; @@ -466,6 +472,10 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $this->fcmclient->sendJoEvent($jo, "jo_fcm_title_outlet_assign", "jo_fcm_body_outlet_assign"); + return $data; } @@ -507,6 +517,10 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $this->fcmclient->sendJoEvent($jo, "jo_fcm_title_driver_arrived", "jo_fcm_body_driver_arrived"); + return $data; } @@ -661,6 +675,10 @@ class ResqRiderAPIHandler implements RiderAPIHandlerInterface ]; $this->mclient->sendEvent($jo, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($jo, $payload); + $fcmclient->sendJoEvent($jo, "jo_fcm_title_fulfilled", "jo_fcm_body_fulfilled"); + return $data; } diff --git a/src/Service/RiderAssignmentHandler/CMBRiderAssignmentHandler.php b/src/Service/RiderAssignmentHandler/CMBRiderAssignmentHandler.php index 0a8a8112..e6ff0664 100644 --- a/src/Service/RiderAssignmentHandler/CMBRiderAssignmentHandler.php +++ b/src/Service/RiderAssignmentHandler/CMBRiderAssignmentHandler.php @@ -6,6 +6,8 @@ use Doctrine\ORM\EntityManagerInterface; use App\Service\RiderAssignmentHandlerInterface; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Entity\JobOrder; @@ -18,12 +20,15 @@ class CMBRiderAssignmentHandler implements RiderAssignmentHandlerInterface protected $em; protected $aclient; protected $mclient; + protected $mclientv2; + protected $fcmclient; - public function __construct(EntityManagerInterface $em, MQTTClient $mclient, - APNSClient $aclient) + public function __construct(EntityManagerInterface $em, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, APNSClient $aclient) { $this->em = $em; $this->mclient = $mclient; + $this->mclientv2 = $mclientv2; + $this->fcmclient = $fcmclient; $this->aclient = $aclient; } @@ -38,6 +43,10 @@ class CMBRiderAssignmentHandler implements RiderAssignmentHandlerInterface // send event $this->mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($obj, $payload); + $this->fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned"); + // check if rider is available if ($rider->isAvailable()) { @@ -66,6 +75,10 @@ class CMBRiderAssignmentHandler implements RiderAssignmentHandlerInterface ]; $this->mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($obj, $payload); + $this->fcmclient->sendJoEvent($obj, "jo_fcm_title_fulfilled", "jo_fcm_body_fulfilled"); + // send fulfill/complete event to rider $this->mclient->sendRiderEvent($obj, $payload); diff --git a/src/Service/RiderAssignmentHandler/ResqRiderAssignmentHandler.php b/src/Service/RiderAssignmentHandler/ResqRiderAssignmentHandler.php index 6592734a..80e8d89c 100644 --- a/src/Service/RiderAssignmentHandler/ResqRiderAssignmentHandler.php +++ b/src/Service/RiderAssignmentHandler/ResqRiderAssignmentHandler.php @@ -8,6 +8,8 @@ use Symfony\Contracts\Translation\TranslatorInterface; use App\Service\RiderAssignmentHandlerInterface; use App\Service\MQTTClient; +use App\Service\MQTTClientApiv2; +use App\Service\FCMSender; use App\Service\APNSClient; use App\Entity\JobOrder; @@ -20,13 +22,16 @@ class ResqRiderAssignmentHandler implements RiderAssignmentHandlerInterface protected $em; protected $aclient; protected $mclient; + protected $mclientv2; + protected $fcmclient; protected $translator; - public function __construct(EntityManagerInterface $em, MQTTClient $mclient, - APNSClient $aclient, TranslatorInterface $translator) + public function __construct(EntityManagerInterface $em, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, APNSClient $aclient, TranslatorInterface $translator) { $this->em = $em; $this->mclient = $mclient; + $this->mclientv2 = $mclientv2; + $this->fcmclient = $fcmclient; $this->aclient = $aclient; $this->translator = $translator; } @@ -42,6 +47,10 @@ class ResqRiderAssignmentHandler implements RiderAssignmentHandlerInterface // send event $this->mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($obj, $payload); + $this->fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned"); + // check if rider is available if ($rider->isAvailable()) { @@ -72,6 +81,10 @@ class ResqRiderAssignmentHandler implements RiderAssignmentHandlerInterface ]; $this->mclient->sendEvent($obj, $payload); + // NOTE: for resq2 app + $this->mclientv2->sendEvent($obj, $payload); + $this->fcmclient->sendJoEvent($obj, "jo_fcm_title_fulfilled", "jo_fcm_body_fulfilled"); + // send fulfill/complete event to rider $this->mclient->sendRiderEvent($obj, $payload); } diff --git a/symfony.lock b/symfony.lock index 6a96a3a8..82c192d2 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,13 +1,4 @@ { - "catalyst/auth-bundle": { - "version": "dev-master" - }, - "catalyst/menu-bundle": { - "version": "dev-master" - }, - "creof/doctrine2-spatial": { - "version": "1.2.0" - }, "creof/geo-parser": { "version": "2.1.0" }, @@ -53,9 +44,6 @@ "ref": "44d3aa7752dd46f77ba11af2297a25e1dedfb4d0" } }, - "doctrine/doctrine-cache-bundle": { - "version": "1.3.2" - }, "doctrine/doctrine-fixtures-bundle": { "version": "3.0", "recipe": { @@ -113,6 +101,18 @@ "hashids/hashids": { "version": "4.1.0" }, + "jankstudio/catalyst-api-bundle": { + "version": "dev-master" + }, + "jankstudio/catalyst-auth-bundle": { + "version": "dev-master" + }, + "jankstudio/catalyst-menu-bundle": { + "version": "dev-master" + }, + "jankstudio/doctrine-spatial": { + "version": "dev-master" + }, "jdorn/sql-formatter": { "version": "v1.2.17" }, diff --git a/templates/base.html.twig b/templates/base.html.twig index 50e72b20..d679555b 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -770,7 +770,8 @@
- {{ menu.main_menu(main_menu.menu) }} + {% set main_menu = menu_get('main') %} + {{ menu.main_menu(main_menu) }}
diff --git a/templates/menu.html.twig b/templates/menu.html.twig index 4f200a7d..1d0a27d0 100644 --- a/templates/menu.html.twig +++ b/templates/menu.html.twig @@ -2,36 +2,38 @@ {% import _self as menu %} {% endmacro %} @@ -47,7 +49,7 @@ {% else %}