diff --git a/.env.dist b/.env.dist index 4e10dffc..a9fe4b6a 100644 --- a/.env.dist +++ b/.env.dist @@ -42,3 +42,14 @@ POLICY_MOBILE=insertmobilepolicyidhere # OTP OTP_MODE=settotestorrandom + +# geofence +GEOFENCE_ENABLE=settotrueorfalse + +# unknown manufacturer and vehicle ids +CVU_MFG_ID=insertmfgidforunknownvehicles +CVU_BRAND_ID=insertbrandidforunknownvehicles + +# country code prefix +COUNTRY_CODE=+insertcountrycodehere + diff --git a/catalyst/api-bundle/Command/TestAPICommand.php b/catalyst/api-bundle/Command/TestAPICommand.php index bf35ce1e..7e959808 100644 --- a/catalyst/api-bundle/Command/TestAPICommand.php +++ b/catalyst/api-bundle/Command/TestAPICommand.php @@ -41,7 +41,6 @@ class TestAPICommand extends Command // TODO: shift this out of the bundle, since it's project specific - // warranty register $serial = 'AJ34LJADR12134LKJL5'; $plate_num = 'XEN918'; @@ -54,16 +53,22 @@ class TestAPICommand extends Command 'date_expire' => '20191001', 'first_name' => 'First', 'last_name' => 'Last', - 'mobile_number' => '12345678910', + 'mobile_number' => '09231234567', ]; - $api->post('/capi/warranties', $params); + //$api->post('/capi/warranties', $params); // get all warranties - $api->get('/capi/warranties'); + $params = [ + 'order' => 'DESC', + 'limit' => '5', + 'start' => '1', + ]; + + $api->get('/capi/warranties', $params); // warranty find - $api->get('/capi/warranties/' . $serial); + //$api->get('/capi/warranties/' . $serial); // warranty update $id = 86811; @@ -78,7 +83,7 @@ class TestAPICommand extends Command 'last_name' => 'Last', 'mobile_number' => '123456789111', ]; - $api->post('/capi/warranties/'. $id, $params); + //$api->post('/capi/warranties/'. $id, $params); // warranty set privacy policy $id = 86811; @@ -86,7 +91,7 @@ class TestAPICommand extends Command $params = [ 'privacy_policy_id' => $policy_id, ]; - $api->post('/capi/warranties/' . $id .'/privacypolicy', $params); + //$api->post('/capi/warranties/' . $id .'/privacypolicy', $params); // warranty claim $id = 86811; @@ -94,30 +99,44 @@ class TestAPICommand extends Command $params = [ 'serial' => $serial, ]; - $api->post('/capi/warranties/' . $id . '/claim', $params); + //$api->post('/capi/warranties/' . $id . '/claim', $params); // warranty cancel $id = 86811; - $api->get('/capi/warranties/' . $id . '/cancel'); + //$api->get('/capi/warranties/' . $id . '/cancel'); // plate warranty - $api->get('/capi/plates/' . $plate_num . '/warranties'); + //$api->get('/capi/plates/' . $plate_num . '/warranties'); // warranty delete $id = 86811; - $api->post('/capi/warranties/' . $id . '/delete'); + //$api->post('/capi/warranties/' . $id . '/delete'); // battery - $api->get('/capi/battery_brands'); - $api->get('/capi/battery_sizes'); - $api->get('/capi/batteries'); + //$api->get('/capi/battery_brands'); + //$api->get('/capi/battery_sizes'); + //$api->get('/capi/batteries'); // vehicle - $api->get('/capi/vehicle_manufacturers'); - $api->get('/capi/vehicles'); + //$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); } } diff --git a/composer.json b/composer.json index 6c67a564..e118abfc 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "catalyst/menu-bundle": "dev-master", "creof/doctrine2-spatial": "^1.2", "data-dog/audit-bundle": "^0.1.10", + "edwinhoksberg/php-fcm": "^1.0", "guzzlehttp/guzzle": "^6.3", "predis/predis": "^1.1", "sensio/framework-extra-bundle": "^5.1", diff --git a/composer.lock b/composer.lock index 54f7abba..b3630199 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "ef9a215401e1fec51336e1d6a9df52d9", + "content-hash": "4873ae3fd18db755bc9bf395bbbfb141", "packages": [ { "name": "catalyst/auth-bundle", @@ -1564,6 +1564,55 @@ ], "time": "2018-06-14T14:45:07+00:00" }, + { + "name": "edwinhoksberg/php-fcm", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/EdwinHoksberg/php-fcm.git", + "reference": "7be637139fe54ec23f37c8dba519bafa7543e336" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/EdwinHoksberg/php-fcm/zipball/7be637139fe54ec23f37c8dba519bafa7543e336", + "reference": "7be637139fe54ec23f37c8dba519bafa7543e336", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.3", + "php": ">= 7.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fcm\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Edwin Hoksberg", + "email": "mail@edwinhoksberg.nl" + } + ], + "description": "A library for sending Firebase cloud messages and managing user topic subscriptions, device groups and devices.", + "homepage": "https://github.com/EdwinHoksberg/php-fcm", + "keywords": [ + "FCM", + "Firebase Cloud Messaging", + "firebase", + "google", + "notifications" + ], + "time": "2018-04-09T19:32:41+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "6.3.3", diff --git a/config/acl.yaml b/config/acl.yaml index e7f42308..90b2f06d 100644 --- a/config/acl.yaml +++ b/config/acl.yaml @@ -256,6 +256,8 @@ access_keys: label: Search - id: warranty.search label: Customer Battery Search + - id: warranty.upload + label: Warranty Upload - id: ticket label: Ticket Access @@ -298,6 +300,12 @@ access_keys: 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: service label: Other Services @@ -364,3 +372,17 @@ access_keys: 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 diff --git a/config/api_acl.yaml b/config/api_acl.yaml index 39557cf6..2ff18704 100644 --- a/config/api_acl.yaml +++ b/config/api_acl.yaml @@ -50,3 +50,8 @@ access_keys: acls: - id: privacypolicy.find label: Find Privacy Policy + - id: customer + label: Customer + acls: + - id: customer.register + label: Register Customer diff --git a/config/menu.yaml b/config/menu.yaml index cd3f40b9..a64dd8b4 100644 --- a/config/menu.yaml +++ b/config/menu.yaml @@ -155,6 +155,14 @@ main_menu: acl: warranty.list label: Warranty parent: support + - id: warranty_upload + acl: warranty.upload + label: Warranty Upload + parent: support + - id: static_content_list + acl: static_content.list + label: Static Content + parent: support - id: service acl: service.menu diff --git a/config/routes/capi.yaml b/config/routes/capi.yaml index cf533814..ee3c8668 100644 --- a/config/routes/capi.yaml +++ b/config/routes/capi.yaml @@ -135,3 +135,11 @@ capi_privacy_policy: path: /capi/privacy_policy/{id} controller: App\Controller\CAPI\PrivacyPolicyController::getPrivacyPolicy methods: [GET] + +# customer + +# register customer and customer vehicle +capi_customer_register: + path: /capi/quick_registration + controller: App\Controller\CAPI\CustomerController::register + methods: [POST] diff --git a/config/routes/report.yaml b/config/routes/report.yaml index 5d815490..85ad83ee 100644 --- a/config/routes/report.yaml +++ b/config/routes/report.yaml @@ -47,3 +47,33 @@ rep_resq_meh_export_csv: path: /report/meh_customer_export controller: App\Controller\ReportController::mehCustomerExportCSV methods: [POST] + +rep_warranty_class_form: + path: /report/warranty_class_report + controller: App\Controller\ReportController::warrantyClassForm + methods: [GET] + +rep_warranty_class_export_csv: + path: /report/warranty_class_report + controller: App\Controller\ReportController::warrantyClassExportCSV + methods: [POST] + +rep_vehicle_battery_compatibility_form: + path: /report/vehicle_battery_compatibility_report + controller: App\Controller\ReportController::vehicleBatteryCompatibilityForm + methods: [GET] + +rep_vehicle_battery_compatibility_export_csv: + path: /report/vehicle_battery_compatibility_report + controller: App\Controller\ReportController::vehicleBatteryCompatibilityExportCSV + methods: [POST] + +rep_warranty_details_form: + path: /report/warranty_details_report + controller: App\Controller\ReportController::warrantyDetailsForm + methods: [GET] + +rep_warranty_details_export_csv: + path: /report/warranty_details_report + controller: App\Controller\ReportController::warrantyDetailsExportCSV + methods: [POST] diff --git a/config/routes/static_content.yaml b/config/routes/static_content.yaml new file mode 100644 index 00000000..88fe3cf4 --- /dev/null +++ b/config/routes/static_content.yaml @@ -0,0 +1,33 @@ +static_content_list: + path: /static_content + controller: App\Controller\StaticContentController::index + +static_content_rows: + path: /static_content/rows + controller: App\Controller\StaticContentController::rows + methods: [POST] + +static_content_create: + path: /static_content/create + controller: App\Controller\StaticContentController::addForm + methods: [GET] + +static_content_create_submit: + path: /static_content/create + controller: App\Controller\StaticContentController::addSubmit + methods: [POST] + +static_content_update: + path: /static_content/{id} + controller: App\Controller\StaticContentController::updateForm + methods: [GET] + +static_content_update_submit: + path: /static_content/{id} + controller: App\Controller\StaticContentController::updateSubmit + methods: [POST] + +static_content_delete: + path: /static_content/{id} + controller: App\Controller\StaticContentController::destroy + methods: [DELETE] diff --git a/config/routes/warranty.yaml b/config/routes/warranty.yaml index 86c3e9b9..3e049e54 100644 --- a/config/routes/warranty.yaml +++ b/config/routes/warranty.yaml @@ -28,3 +28,13 @@ warranty_update_submit: path: /warranties/{id} controller: App\Controller\WarrantyController::updateSubmit methods: [POST] + +warranty_upload: + path: /warranty/upload + controller: App\Controller\WarrantyController::uploadForm + methods: [GET] + +warranty_upload_submit: + path: /warranty/upload + controller: App\Controller\WarrantyController::uploadSubmit + methods: [POST] diff --git a/config/services.yaml b/config/services.yaml index 353378b4..00c5c32f 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -10,6 +10,7 @@ parameters: api_access_key: 'api_access_keys' app_acl_file: 'acl.yaml' app_access_key: 'access_keys' + cvu_brand_id: "%env(CVU_BRAND_ID)%" services: # default configuration for services in *this* file @@ -87,6 +88,25 @@ services: $password: "%env(REDIS_CLIENT_PASSWORD)%" $env_flag: "dev" + App\Service\GeofenceTracker: + arguments: + $geofence_flag: "%env(GEOFENCE_ENABLE)%" + + App\Service\WarrantyHandler: + arguments: + $em: "@doctrine.orm.entity_manager" + + App\Command\SetCustomerPrivacyPolicyCommand: + arguments: + $policy_promo: "%env(POLICY_PROMO)%" + $policy_third_party: "%env(POLICY_THIRD_PARTY)%" + $policy_mobile: "%env(POLICY_MOBILE)%" + + App\Command\CreateCustomerFromWarrantyCommand: + arguments: + $cvu_mfg_id: "%env(CVU_MFG_ID)%" + $cvu_brand_id: "%env(CVU_BRAND_ID)%" + # rider tracker service App\Service\RiderTracker: arguments: @@ -144,14 +164,18 @@ services: App\Service\InvoiceGeneratorInterface: "@App\\Service\\InvoiceGenerator\\ResqInvoiceGenerator" # job order generator - App\Service\JobOrderHandler\CMBJobOrderHandler: ~ + App\Service\JobOrderHandler\ResqJobOrderHandler: + arguments: + $country_code: "%env(COUNTRY_CODE)%" #job order generator interface #App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\CMBJobOrderHandler" App\Service\JobOrderHandlerInterface: "@App\\Service\\JobOrderHandler\\ResqJobOrderHandler" # customer generator - App\Service\CustomerHandler\CMBCustomerHandler: ~ + App\Service\CustomerHandler\ResqCustomerHandler: + arguments: + $country_code: "%env(COUNTRY_CODE)%" # customer generator interface #App\Service\CustomerHandlerInterface: "@App\\Service\\CustomerHandler\\CMBCustomerHandler" diff --git a/src/Command/ComputeWarrantyExpiryDateCommand.php b/src/Command/ComputeWarrantyExpiryDateCommand.php new file mode 100644 index 00000000..383370f7 --- /dev/null +++ b/src/Command/ComputeWarrantyExpiryDateCommand.php @@ -0,0 +1,75 @@ +em = $em; + $this->wh = $wh; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('warranty:computeexpirydate') + ->setDescription('Compute expiry date for existing warranties.') + ->setHelp('Compute expiry date for existing warranties.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.date_expire is null'); + $warranties = $warr_q->iterate(); + + foreach($warranties as $row) + { + $warr = $row[0]; + + error_log('Processing warranty for ' . $warr->getID()); + + $date_purchase = $warr->getDatePurchase(); + + $batteries = $this->wh->getBatteriesForWarranty($warr); + if (!empty($batteries)) + { + $warranty_class = $warr->getWarrantyClass(); + + $warr_period = $this->wh->getWarrantyPeriod($batteries, $warranty_class); + + if ($warr_period != null) + { + $expiry_date = $this->wh->computeDateExpire($date_purchase, $warr_period); + } + else + { + $expiry_date = $date_purchase; + } + + // save expiry date + $warr->setDateExpire($expiry_date); + + $this->em->persist($warr); + $this->em->flush(); + } + + $this->em->clear(); + } + } +} diff --git a/src/Command/CreateCustomerFromWarrantyCommand.php b/src/Command/CreateCustomerFromWarrantyCommand.php new file mode 100644 index 00000000..e644fc06 --- /dev/null +++ b/src/Command/CreateCustomerFromWarrantyCommand.php @@ -0,0 +1,458 @@ +em = $em; + + $this->cvu_mfg_id = $cvu_mfg_id; + $this->cvu_brand_id = $cvu_brand_id; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('customer:createfromwarranty') + ->setDescription('Create customers from existing warranties.') + ->setHelp('Creates customers from existing warranties.') + ->addArgument('file', InputArgument::REQUIRED, 'Path to the output CSV file with the warranties.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $csv_file = $input->getArgument('file'); + + // attempt to open file + try + { + $fh = fopen($csv_file, "w"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $csv_file . '" could be opened.'); + } + + // counters for warranties, customers, customer vehicles + $total_warr = 0; + $total_inv_warr = 0; + $total_cust_added = 0; + $total_cv_added = 0; + + + /* + // load all customers + $output->writeln('Loading customer data...'); + $this->loadCustomers($output); + */ + + + // get all warranties + error_log('Getting warranties...'); + $warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.mobile_number is not null'); + $warranties = $warr_q->iterate(); + // $warranties = $warr_q->getResult(); + // $warranties = $this->em->getRepository(Warranty::class)->findAll(); + + //$invalid_warranties = []; + // $warr_count = count($warranties); + $created_objs = []; + $output->writeln("Processing warranties... "); + foreach($warranties as $row) + { + $warr = $row[0]; + + $total_warr++; + // check if warranty mobile already exists in customer + $w_mobile = $warr->getMobileNumber(); + if (empty($w_mobile)) + { + // TODO: for now, if warranty mobile number is empty, add to list of invalid entries + //$invalid_warranties[] = $this->processInvalidEntries($warr); + continue; + } + + // parse warranty mobile in case of multiple numbers + // check for spaces, slash, and forward slash + $w_mobile_array = []; + if (preg_match('/[\\\s\/]/', $w_mobile)) + { + $w_mobile_array = preg_split('/[\\\s\/]/', $w_mobile); + } + else + { + // only one mobile number + $w_mobile_array[] = $w_mobile; + } + + // set values for new customer vehicle + $w_plate_number = $this->cleanPlateNumber($warr->getPlateNumber()); + + $cust_found = false; + foreach ($w_mobile_array as $w_mobile_num) + { + $w_mobile_num = trim($w_mobile_num); + + // empty mobile num + if (empty($w_mobile_num)) + continue; + + // does it fit our 09XXXXXXXXX pattern? + if (preg_match('/^09[0-9]{9}$/', $w_mobile_num)) + { + // remove first '0' + $w_mobile_num = substr($w_mobile_num, 1); + error_log("CONVERTED TO $w_mobile_num"); + } + + // does it fit our 9XXXXXXXXX pattern? + if (!preg_match('/^9[0-9]{9}$/', $w_mobile_num)) + continue; + + /* + // min length 2 + // TODO: we need to check proper phone number format + // format should be '9XXXXXXXXX' + // TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert + if (strlen($w_mobile_num <= 2)) + continue; + */ + + error_log(''); + error_log("($total_warr) processing $w_mobile_num from warranty..."); + + $customers = $this->findCustomerByNumber($w_mobile_num); + + if (!empty($customers)) + { + error_log('found customer for ' . $w_mobile_num); + foreach ($customers as $customer) + { + // get customer vehicles for customer + $c_vehicles = $customer->getVehicles(); + + $cv_found = false; + if (!empty($c_vehicles)) + { + // check if plate number of customer vehicle matches warranty plate number + foreach ($c_vehicles as $c_vehicle) + { + $clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber()); + + // check if it's already there + if ($clean_cv_plate == $w_plate_number) + { + // customer and customer vehicle already exists + $cv_found = true; + break; + } + } + + } + + // if there was a customer vehicle matched + if ($cv_found) + { + // vehicle found, do nothing. + error_log('vehicle found - ' . $w_plate_number); + $created_objs[] = $this->createReportData($warr, self::CV_FOUND); + } + else + { + // customer exists but not customer vehicle + // add customer vehicle to existing customer with unknown manufacturer and make + error_log('new vehicle - ' . $w_plate_number); + $this->createCustomerVehicle($customer, $this->getDefaultVehicle(), $w_plate_number); + $created_objs[] = $this->createReportData($warr, self::CV_NEW); + $total_cv_added++; + } + } + } + // customer not found + else + { + error_log('NEW customer and vehicle - ' . $w_plate_number); + // customer not found, add customer and customer vehicle + // get warranty first name, last name + $w_first_name = $warr->getFirstName(); + $w_last_name = $warr->getLastName(); + + //$output->writeln($w_first_name); + //$output->writeln($w_last_name); + //$output->writeln($w_plate_number); + + $new_cust = new Customer(); + $new_cust->setFirstName($w_first_name) + ->setLastName($w_last_name) + ->setPhoneMobile($w_mobile_num); + + $this->em->persist($new_cust); + + $this->createCustomerVehicle($new_cust, $this->getDefaultVehicle(), $w_plate_number); + + $created_objs[] = $this->createReportData($warr, self::CUST_NEW); + + // add latest customer to hash + //$this->cust_index[$w_mobile_num][] = $new_cust; + + $total_cust_added++; + $total_cv_added++; + } + } + $this->em->flush(); + $this->em->clear(); + } + + /* + // process invalid warranties, if any + if (count($invalid_warranties) > 0) + { + fputcsv($fh, [ + 'ID', + 'Serial', + 'Warranty Class', + 'Last Name', + 'First Name', + 'Mobile Number', + 'Plate Number', + 'Battery Model', + 'Battery Size', + 'SAP Battery', + 'Status', + 'Date Created', + 'Date Purchased', + 'Expiry Date', + 'Date Claimed', + 'Claimed From', + 'Privacy Policy', + ]); + + foreach($invalid_warranties as $row) + { + $total_inv_warr++; + fputcsv($fh, $row); + } + } + */ + + // process the report data + if (count($created_objs) > 0) + { + fputcsv($fh, [ + 'ID', + 'Mobile Number', + 'Plate Number', + 'Action Done', + ]); + + foreach($created_objs as $row) + { + fputcsv($fh, $row); + } + } + + fclose($fh); + + $output->writeln(''); + $output->writeln('Total warranties: ' . $total_warr); + //$output->writeln('Total warranties with no mobile number: ' . $total_inv_warr); + $output->writeln('Total customers added: ' . $total_cust_added); + $output->writeln('Total customer vehicles added: ' . $total_cv_added); + } + + protected function getDefaultVehicle() + { + // get default vehicle + $default_vehicle = $this->em->getRepository(Vehicle::class)->find($this->cvu_brand_id); + if ($default_vehicle == null) + { + $output->writeln("Need to add vehicle with default values."); + return null; + } + + return $default_vehicle; + } + + protected function findCustomerByNumber($number) + { + $customers = $this->em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]); + return $customers; + } + + protected function loadCustomers() + { + error_log('starting query...'); + // get all customers + $customers = $this->em->getRepository(Customer::class)->findAll(); + $cust_q = $this->em->createQuery('select c from App\Entity\Customer c'); + $cust_iter = $q->iterate(); + + error_log('looping through query...'); + $this->cust_index = []; + foreach ($cust_iter as $customer) + { + error_log('here'); + $mobile = trim($customer->getPhoneMobile()); + if (!empty($mobile)) + { + $mobile_array = []; + // need to check if multiple numbers in mobile + if (preg_match('/[\\\s\/]/', $mobile)) + { + $mobile_array = preg_split('/[\\\s\/]/', $mobile); + } + else + { + // only one mobile number + $mobile_array[] = $mobile; + } + + foreach($mobile_array as $number) + { + if (!(empty($number))) + { + if (!isset($this->cust_index[$number])) + $this->cust_index[$number] = []; + $this->cust_index[$number][] = $customer; + } + } + } + } + } + + protected function createCustomerVehicle(Customer $cust, $vehicle, $plate_number) + { + $new_cv = new CustomerVehicle(); + + $new_cv->setCustomer($cust) + ->setPlateNumber($plate_number) + ->setStatusCondition(VehicleStatusCondition::BRAND_NEW) + ->setModelYear('') + ->setColor('') + ->setFuelType(FuelType::GAS) + ->setHasMotoliteBattery(true) + ->setVehicle($vehicle); + + $this->em->persist($new_cv); + } + + protected function createReportData($warr, $action) + { + $obj = [ + 'id' => $warr->getID(), + 'mobile_number' => $warr->getMobileNumber(), + 'plate_number' => $warr->getPlateNumber(), + 'action_done' => $action, + ]; + + return $obj; + + } + + protected function processInvalidEntries($warr) + { + $batt_model = ''; + $batt_size = ''; + $sap_batt = ''; + $policy = ''; + $date_purchased = ''; + $date_expire = ''; + $date_claim = ''; + + $create_date = $warr->getDateCreate(); + $date_create = $create_date->format('d/M/y'); + + if ($warr->getDatePurchase() != null) + { + $p_date = $warr->getDatePurchase(); + $date_purchased = $p_date->format('d/M/y'); + } + if ($warr->getDateClaim() != null) + { + $c_date = $warr->getDateClaim(); + $date_claim = $c_date->format('d/M/y'); + } + if ($warr->getDateExpire() != null) + { + $e_date = $warr->getDateExpire(); + $date_expire = $e_date->format('d/M/y'); + } + + if ($warr->getBatteryModel() != null) + { + $batt_model = $warr->getBatteryModel()->getName(); + } + if ($warr->getBatterySize() != null) + { + $batt_size = $warr->getBatterySize()->getName(); + } + if ($warr->getSAPBattery() != null) + { + $sap_batt = $warr->getSAPBattery()->getBrand()->getName(); + } + if ($warr->getPrivacyPolicy() != null) + { + $policy = $warr->getPrivacyPolicy()->getName(); + } + + $invalid_warranty = [ + 'id' => $warr->getID(), + 'serial' => $warr->getSerial(), + 'warranty_class' => $warr->getWarrantyClass(), + 'last_name' => $warr->getLastName(), + 'first_name' => $warr->getFirstName(), + 'mobile_number' => $warr->getMobileNumber(), + 'plate_number' => $warr->getPlateNumber(), + 'battery_model' => $batt_model, + 'battery_size' => $batt_size, + 'sap_battery' => $sap_batt, + 'status' => $warr->getStatus(), + 'date_create' => $date_create, + 'date_purchase' => $date_purchased, + 'date_expire' => $date_expire, + 'date_claim' => $date_claim, + 'claimed_from' => $warr->getClaimedFrom(), + 'privacy_policy' => $policy, + ]; + + return $invalid_warranty; + } + + protected function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } +} diff --git a/src/Command/ImportPartnersCommand.php b/src/Command/ImportPartnersCommand.php index 526fb282..74e02d5b 100644 --- a/src/Command/ImportPartnersCommand.php +++ b/src/Command/ImportPartnersCommand.php @@ -34,7 +34,7 @@ class ImportPartnersCommand extends Command protected $em; - public function __construct(Objectmanager $om) + public function __construct(ObjectManager $om) { $this->em = $om; diff --git a/src/Command/SetCustomerPrivacyPolicyCommand.php b/src/Command/SetCustomerPrivacyPolicyCommand.php index d4431175..4132fa91 100644 --- a/src/Command/SetCustomerPrivacyPolicyCommand.php +++ b/src/Command/SetCustomerPrivacyPolicyCommand.php @@ -7,7 +7,6 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Dotenv\Dotenv; use Doctrine\Common\Persistence\ObjectManager; @@ -19,10 +18,19 @@ class SetCustomerPrivacyPolicyCommand extends Command { private $em; - public function __construct(ObjectManager $om) + private $policy_promo_id; + private $policy_third_party_id; + private $policy_mobile_id; + + public function __construct(ObjectManager $om, $policy_promo, + $policy_third_party, $policy_mobile) { $this->em = $om; + $this->policy_promo_id = $policy_promo; + $this->policy_third_party_id = $policy_third_party; + $this->policy_mobile_id = $policy_mobile; + parent::__construct(); } @@ -35,16 +43,8 @@ class SetCustomerPrivacyPolicyCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { - // get the policy ids from .env - $dotenv = new Dotenv(); - $dotenv->loadEnv(__DIR__.'/../../.env'); - - $policy_promo_id = $_ENV['POLICY_PROMO']; - $policy_third_party_id = $_ENV['POLICY_THIRD_PARTY']; - $policy_mobile_id = $_ENV['POLICY_MOBILE']; - // get third party policy - $third_party_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_third_party_id); + $third_party_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_third_party_id); // get customers on third party $third_party_customers = $this->em->getRepository(Customer::class)->findBy(['priv_third_party' => true]); @@ -54,7 +54,7 @@ class SetCustomerPrivacyPolicyCommand extends Command } // get promo policy - $promo_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_promo_id); + $promo_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_promo_id); // get customers on promo $promo_customers = $this->em->getRepository(Customer::class)->findBy(['priv_promo' => true]); @@ -66,7 +66,7 @@ class SetCustomerPrivacyPolicyCommand extends Command $this->em->flush(); // get mobile policy - $mobile_policy = $this->em->getRepository(PrivacyPolicy::class)->find($policy_mobile_id); + $mobile_policy = $this->em->getRepository(PrivacyPolicy::class)->find($this->policy_mobile_id); // get mobile sessions $mobile_sessions = $this->em->getRepository(MobileSession::class)->findAll(); diff --git a/src/Command/UpdateCustomerVehicleWarrantyCommand.php b/src/Command/UpdateCustomerVehicleWarrantyCommand.php new file mode 100644 index 00000000..89b6e5e0 --- /dev/null +++ b/src/Command/UpdateCustomerVehicleWarrantyCommand.php @@ -0,0 +1,98 @@ +em = $em; + $this->wh = $wh; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('customervehicle:updatewarrantyinfo') + ->setDescription('Update customer vehicle warranty.') + ->setHelp('Update customer vehicle warranty.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // get all warranties + // since it's possible that the same plate number will have multiple warranties, order them from earliest to latest + $warr_q = $this->em->createQuery('select w from App\Entity\Warranty w where w.plate_number is not null order by w.date_purchase asc'); + $warranties = $warr_q->iterate(); + + foreach ($warranties as $row) + { + $warr = $row[0]; + + // clean plate number + $plate_number = $this->wh->cleanPlateNumber($warr->getPlateNumber()); + + // get other warranty information + $serial = $warr->getSerial(); + $expiry_date = $warr->getDateExpire(); + + // TODO: check length of serial for now. Should not exceed 20. + // there is a warranty with 2 serial codes in live + // for now, ignore the warranty + if (strlen($serial) > 20) + { + continue; + } + + // find battery + $batteries = $this->wh->getBatteriesForWarranty($warr); + + // find customer vehicle using plate number + /* + error_log('Finding customer vehicle with plate number ' . $plate_number); + $cust_vehicles = $this->em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $plate_number]); + + if (!empty($cust_vehicles)) + { + if (!empty($batteries)) + { + // set current battery to the first battery in list. + // there are cases where multiple batteries linked to an SAP code. + $battery = $batteries[0]; + $battery_id = $battery->getID(); + } + $q = $this->em->createQuery('update App\Entity\CustomerVehicle cv + set cv.curr_battery = :batt_id, + cv.warranty_code = :serial, + cv.warranty_expiration = :expiry_date + where cv.plate_number = :plate_number') + ->setParameters([ + 'batt_id' => $battery_id, + 'serial' => $serial, + 'expiry_date' => $expiry_date, + 'plate_number' => $plate_number]); + $q->execute(); + + } */ + $this->wh->updateCustomerVehicle($serial, $batteries, $plate_number, $expiry_date); + + $this->em->detach($row[0]); + } + } +} diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 5642dad7..9765ad8f 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -341,6 +341,15 @@ class APIController extends Controller $this->session->setCustomer($dupe_cust); } + // 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); + } + $em->flush(); // response @@ -839,18 +848,15 @@ class APIController extends Controller $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 $res->setError(true) - ->setErrorMessage('Oops! Our service is limited to Metro Manila only. We will update you as soon as we are able to cover your area'); + ->setErrorMessage('Oops! Our service is limited to some areas in Metro Manila, Laguna, and Baguio only. We will update you as soon as we are able to cover your area'); return $res->getReturnResponse(); } - */ - $jo = new JobOrder(); $jo->setSource(TransactionOrigin::MOBILE_APP) @@ -2182,4 +2188,29 @@ class APIController extends Controller return $res->getReturnResponse(); } + + protected function findCustomerByNumber($number) + { + $em = $this->getDoctrine()->getManager(); + $customers = $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; + } + } diff --git a/src/Controller/CAPI/CustomerController.php b/src/Controller/CAPI/CustomerController.php new file mode 100644 index 00000000..55aae2bd --- /dev/null +++ b/src/Controller/CAPI/CustomerController.php @@ -0,0 +1,204 @@ +acl_gen = $acl_gen; + } + + public function register(Request $req, EntityManagerInterface $em) + { + $this->denyAccessUnlessGranted('customer.register', null, 'No access.'); + + // required parameters + $params = [ + 'first_name', + 'last_name', + 'mobile_number', + 'v_make_id', + 'v_model_year', + 'v_plate_number', + 'v_color', + 'v_condition', + 'v_fuel_type', + ]; + + $msg = $this->checkRequiredParameters($req, $params); + error_log('msg - ' . $msg); + if ($msg) + return new APIResponse(false, $msg); + + $first_name = $req->request->get('first_name'); + $last_name = $req->request->get('last_name'); + $mobile_number = $req->request->get('mobile_number'); + + $make_id = $req->request->get('v_make_id'); + $model_year = $req->request->get('v_model_year'); + $plate_number = $this->cleanPlateNumber($req->request->get('v_plate_number')); + $color = $req->request->get('v_color'); + $condition = $req->request->get('v_condition'); + $fuel_type = $req->request->get('v_fuel_type'); + + // check if vehicle exists + $vehicle = $em->getRepository(Vehicle::class)->find($make_id); + if ($vehicle == null) + return new APIResponse(false, 'Invalid vehicle make.'); + + // clean up mobile number + // does it fit our 09XXXXXXXXX pattern? + if (preg_match('/^09[0-9]{9}$/', $mobile_number)) + { + // remove first '0' + $mobile_number = substr($mobile_number, 1); + error_log("CONVERTED TO $mobile_number"); + } + + // does it fit our 9XXXXXXXXX pattern? + if (!preg_match('/^9[0-9]{9}$/', $mobile_number)) + return new APIResponse(false, 'Invalid mobile number.'); + + /* + // min length 2 + // TODO: we need to check proper phone number format + // format should be '9XXXXXXXXX' + // TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert + if (strlen($mobile_number <= 2)) + continue; + */ + + + $data = []; + $message = ''; + // check if customer already exists + $customers = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $mobile_number]); + if (!empty($customers)) + { + foreach($customers as $customer) + { + // get customer vehicles for customer + $c_vehicles = $customer->getVehicles(); + + $cv_found = false; + if (!empty($c_vehicles)) + { + // check if plate number of customer vehicle matches plate number + foreach($c_vehicles as $c_vehicle) + { + $clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber()); + + // check if it's already there + if ($clean_cv_plate == $plate_number) + { + // customer and customer vehicle already exists + $cv_found = true; + break; + } + } + } + + // if there is a customer vehicle matched + if ($cv_found) + { + // vehicle found, do nothing + $message = 'Customer found.'; + } + else + { + // customer already exists but not customer vehicle + // add customer vehicle + $new_cv = new CustomerVehicle(); + + $new_cv->setCustomer($customer) + ->setPlateNumber($plate_number) + ->setStatusCondition($condition) + ->setModelYear($model_year) + ->setColor($color) + ->setFuelType($fuel_type) + ->setHasMotoliteBattery(true) + ->setVehicle($vehicle); + + $em->persist($new_cv); + + $message = 'Vehicle added.'; + $data[] = [ + 'make_id' => $make_id, + 'model_year' => $model_year, + 'plate_number' => $plate_number, + 'color' => $color, + 'condition' => $condition, + 'fuel_type' => $fuel_type, + ]; + } + } + } + else + { + // customer not found + $new_cust = new Customer(); + $new_cust->setFirstName($first_name) + ->setLastName($last_name) + ->setPhoneMobile($mobile_number); + + $em->persist($new_cust); + + // add customer vehicle + $new_cv = new CustomerVehicle(); + + $new_cv->setCustomer($new_cust) + ->setPlateNumber($plate_number) + ->setStatusCondition($condition) + ->setModelYear($model_year) + ->setColor($color) + ->setFuelType($fuel_type) + ->setHasMotoliteBattery(true) + ->setVehicle($vehicle); + + $em->persist($new_cv); + + $message = 'Customer and vehicle added.'; + $data[] = [ + 'first_name' => $first_name, + 'last_name' => $last_name, + 'mobile_number' => $mobile_number, + 'make_id' => $make_id, + 'model_year' => $model_year, + 'plate_number' => $plate_number, + 'color' => $color, + 'condition' => $condition, + 'fuel_type' => $fuel_type, + ]; + } + + $em->flush(); + $em->clear(); + + return new APIResponse(true, $message, $data); + } + + protected function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } + +} diff --git a/src/Controller/CAPI/WarrantyController.php b/src/Controller/CAPI/WarrantyController.php index d76afffc..83ecf74a 100644 --- a/src/Controller/CAPI/WarrantyController.php +++ b/src/Controller/CAPI/WarrantyController.php @@ -17,10 +17,16 @@ use App\Entity\SAPBattery; use App\Entity\SAPBatterySize; use App\Entity\SAPBatteryBrand; use App\Entity\PrivacyPolicy; +use App\Entity\Customer; +use App\Entity\CustomerVehicle; +use App\Entity\Vehicle; use App\Ramcar\NameValue; use App\Ramcar\WarrantyClass; use App\Ramcar\WarrantyStatus; +use App\Ramcar\FuelType; +use App\Ramcar\VehicleStatusCondition; + use DateTime; use Catalyst\APIBundle\Access\Generator as ACLGenerator; @@ -226,6 +232,9 @@ class WarrantyController extends APIController try { $em->persist($warr); + + $this->getCustomerFromMobile($em, $warr); + $em->flush(); } catch (UniqueConstraintViolationException $e) @@ -488,9 +497,156 @@ class WarrantyController extends APIController } $em->persist($warr); - $em->flush(); return new APIResponse(true, 'Privacy policy for warranty set successfully.'); } + + protected function getCustomerFromMobile($em, $warranty) + { + $w_mobile = $warranty->getMobileNumber(); + if (empty($w_mobile)) + { + return null; + } + + // set values for new customer vehicle + $w_plate_number = $this->cleanPlateNumber($warranty->getPlateNumber()); + + $cust_found = false; + + $w_mobile_num = trim($w_mobile); + + // does it fit our 09XXXXXXXXX pattern? + if (preg_match('/^09[0-9]{9}$/', $w_mobile_num)) + { + // remove first '0' + $w_mobile_num = substr($w_mobile_num, 1); + error_log("CONVERTED TO $w_mobile_num"); + } + + // does it fit our 9XXXXXXXXX pattern? + if (!preg_match('/^9[0-9]{9}$/', $w_mobile_num)) + return null; + + /* + // min length 2 + // TODO: we need to check proper phone number format + // format should be '9XXXXXXXXX' + // TODO: if format doesn't fit and there's a 0 or 63 prefix, we should be able to detect and convert + if (strlen($w_mobile_num <= 2)) + continue; + */ + + $customers = $this->findCustomerByNumber($em, $w_mobile_num); + + if (!empty($customers)) + { + error_log('found customer for ' . $w_mobile_num); + foreach ($customers as $customer) + { + // get customer vehicles for customer + $c_vehicles = $customer->getVehicles(); + + $cv_found = false; + if (!empty($c_vehicles)) + { + // check if plate number of customer vehicle matches warranty plate number + foreach ($c_vehicles as $c_vehicle) + { + $clean_cv_plate = $this->cleanPlateNumber($c_vehicle->getPlateNumber()); + + // check if it's already there + if ($clean_cv_plate == $w_plate_number) + { + // customer and customer vehicle already exists + $cv_found = true; + break; + } + } + + } + + // if there was a customer vehicle matched + if ($cv_found) + { + // vehicle found, do nothing. + error_log('vehicle found - ' . $w_plate_number); + } + else + { + // customer exists but not customer vehicle + // add customer vehicle to existing customer with unknown manufacturer and make + error_log('new vehicle - ' . $w_plate_number); + $this->createCustomerVehicle($em, $customer, $this->getDefaultVehicle($em), $w_plate_number); + } + } + } + // customer not found + else + { + error_log('NEW customer and vehicle - ' . $w_plate_number); + // customer not found, add customer and customer vehicle + // get warranty first name, last name + $w_first_name = $warranty->getFirstName(); + $w_last_name = $warranty->getLastName(); + + $new_cust = new Customer(); + $new_cust->setFirstName($w_first_name) + ->setLastName($w_last_name) + ->setPhoneMobile($w_mobile_num); + + $em->persist($new_cust); + + $this->createCustomerVehicle($em, $new_cust, $this->getDefaultVehicle($em), $w_plate_number); + } + + $em->flush(); + $em->clear(); + } + + protected function getDefaultVehicle($em) + { + // get default vehicle + $cvu_brand_id = $this->getParameter('cvu_brand_id'); + $default_vehicle = $em->getRepository(Vehicle::class)->find($cvu_brand_id); + if ($default_vehicle == null) + { + $output->writeln("Need to add vehicle with default values."); + return null; + } + + return $default_vehicle; + } + + + protected function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } + + protected function createCustomerVehicle($em, Customer $cust, $vehicle, $plate_number) + { + $new_cv = new CustomerVehicle(); + + $new_cv->setCustomer($cust) + ->setPlateNumber($plate_number) + ->setStatusCondition(VehicleStatusCondition::BRAND_NEW) + ->setModelYear('') + ->setColor('') + ->setFuelType(FuelType::GAS) + ->setHasMotoliteBattery(true) + ->setVehicle($vehicle); + + $em->persist($new_cv); + } + + + protected function findCustomerByNumber($em, $number) + { + $customers = $em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]); + return $customers; + } + } diff --git a/src/Controller/ReportController.php b/src/Controller/ReportController.php index e06d1711..2f72b3fa 100644 --- a/src/Controller/ReportController.php +++ b/src/Controller/ReportController.php @@ -14,6 +14,8 @@ use App\Entity\Warranty; use App\Entity\CustomerVehicle; use App\Entity\MobileSession; use App\Entity\Customer; +use App\Entity\BatteryModel; +use App\Entity\BatterySize; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; @@ -27,7 +29,6 @@ use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Symfony\Component\Dotenv\Dotenv; use Catalyst\MenuBundle\Annotation\Menu; @@ -36,6 +37,8 @@ use DateTime; class ReportController extends Controller { + const PREREGISTER_PREFIX = '9'; + /** * @Menu(selected="outlet_list") */ @@ -474,6 +477,7 @@ class ReportController extends Controller 'Plate Number', 'Warranty Create Date', 'Activation Status', + 'Warranty Class', 'Has Mobile App?', 'Date Mobile App Downloaded', 'Mobile Number Using Mobile App', @@ -546,6 +550,181 @@ class ReportController extends Controller return $resp; } + /** + * @Menu(selected="outlet_list") + */ + public function warrantyClassForm() + { + $this->denyAccessUnlessGranted('report.warranty.class', null, 'No access.'); + $params['mode'] = 'form'; + + return $this->render('report/warranty-class/form.html.twig', $params); + } + + /** + * @Menu(selected="outlet_list") + */ + public function warrantyClassExportCSV(Request $req, EntityManagerInterface $em) + { + $data = $this->getWarrantyClassData($em); + + $resp = new StreamedResponse(); + $resp->setCallback(function() use ($data) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Customer Last Name', + 'Customer First Name', + 'Vehicle Manufacturer', + 'Vehicle Make', + 'Model Year', + 'Vehicle Color', + 'Warranty Serial', + 'Warranty Class', + 'Plate Number', + 'Warranty Last Name', + 'Warranty First Name', + 'Warranty Mobile Number', + 'Warranty Battery Model', + 'Warranty Battery Size', + 'Warranty SAP Battery', + 'Warranty Status', + 'Warranty Created', + 'Warranty Purchased', + 'Warranty Expiry Date', + 'Warranty Claim Date', + 'Warranty Claimed From', + 'Warranty Privacy Policy', + 'Is Warranty Activated?', + ]); + foreach ($data as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + $filename = 'warranty_class_report' . '.csv'; + + $resp->setStatusCode(200); + $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + + return $resp; + + } + + /** + * @Menu(selected="outlet_list") + */ + public function vehicleBatteryCompatibilityForm() + { + $this->denyAccessUnlessGranted('report.vehicle.battery.compatibility', null, 'No access.'); + $params['mode'] = 'form'; + + return $this->render('report/vehicle-battery-compatibility/form.html.twig', $params); + } + + /** + * @Menu(selected="outlet_list") + */ + public function vehicleBatteryCompatibilityExportCSV(Request $req, EntityManagerInterface $em) + { + $data = $this->getVehicleBatteryCompatibilityData($em); + + $resp = new StreamedResponse(); + $resp->setCallback(function() use ($data) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Vehicle Manufacturer', + 'Vehicle Make', + 'Vehicle Model Year From', + 'Vehicle Model Year To', + 'Battery Manufacturer', + 'Battery Model', + 'Battery Size', + 'Battery SAP Code', + ]); + foreach ($data as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + $filename = 'vehicle_battery_compatibility_report' . '.csv'; + + $resp->setStatusCode(200); + $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + + return $resp; + } + + /** + * @Menu(selected="outlet_list") + */ + public function warrantyDetailsForm() + { + $this->denyAccessUnlessGranted('report.warranty.details', null, 'No access.'); + $params['mode'] = 'form'; + + return $this->render('report/warranty-details/form.html.twig', $params); + } + + /** + * @Menu(selected="outlet_list") + */ + public function warrantyDetailsExportCSV(Request $resq, EntityManagerInterface $em) + { + $data = $this->getWarrantyDetailsData($em); + + $resp = new StreamedResponse(); + $resp->setCallback(function() use ($data) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Warranty ID', + 'Serial', + 'Battery Model', + 'Battery Size', + 'Warranty Class', + 'Plate Number', + 'Status', + 'Date Created', + 'Date Purchased', + 'Expiry Date', + 'Date Claimed', + 'SAP Battery ID', + 'Claim ID', + 'Last Name', + 'First Name', + 'Mobile Number', + 'Privacy Policy Number', + 'Activated?', + + ]); + foreach ($data as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + $filename = 'warranty_details_report' . '.csv'; + + $resp->setStatusCode(200); + $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + + return $resp; + + } + protected function processPopappFile(UploadedFile $csv_file, EntityManagerInterface $em) { // attempt to open file @@ -588,6 +767,7 @@ class ReportController extends Controller 'plate_num' => '', 'warr_date_create' => '', 'warr_activation_status' => '', + 'warr_class' => '', 'has_mobile' => '', 'date_mobile' => '', 'mobile_number' => '', @@ -605,66 +785,68 @@ class ReportController extends Controller if (!empty($serial)) { // get the warranty for serial - $warr_qb = $this->getDoctrine() - ->getRepository(Warranty::class) - ->createQueryBuilder('q'); - $warranty_query = $warr_qb->select('q') - ->where('q.serial = :serial') - ->setParameter('serial', $serial); - $warranty = $warranty_query->getQuery()->getOneOrNullResult(); + $warranties = $em->getRepository(Warranty::class)->findBy(['serial' => $serial]); - if ($warranty != null) + if (!empty($warranties)) { - $isValid = InvalidPlateNumber::isInvalid($warranty->getPlateNumber()); - if ($isValid) + foreach ($warranties as $warranty) { - // get customer vehicles using plate number - $customer_vehicles = $em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $warranty->getPlateNumber()]); - - // check if customer vehicle is empty - if (count($customer_vehicles) != 0) + //error_log('found warranty for serial ' . $serial); + $plate_number = $warranty->getPlateNumber(); + $isValid = InvalidPlateNumber::isInvalid($plate_number); + if ($isValid) { - $has_mobile = false; - $mobile_date = ''; - $mobile_number = ''; - - // get the first customer vehicle, store as best_cv until we find one with a mobile session - $best_cv = current($customer_vehicles); - - foreach($customer_vehicles as $cv) + // get customer vehicles using plate number + $customer_vehicles = $em->getRepository(CustomerVehicle::class)->findBy(['plate_number' => $plate_number]); + + // check if customer vehicle is empty + if (count($customer_vehicles) != 0) { - // get mobile session of customer - //error_log($cv->getCustomer()->getLastName() . ' ' . $cv->getCustomer()->getFirstName()); - $mobile_session = $em->getRepository(MobileSession::class) - ->findOneBy(['customer' => $cv->getCustomer()->getID()], ['date_generated' => 'ASC']); - if ($mobile_session != null) + //error_log('found customer vehicle for plate number ' . $plate_number); + $has_mobile = false; + $mobile_date = ''; + $mobile_number = ''; + + // get the first customer vehicle, store as best_cv until we find one with a mobile session + $best_cv = current($customer_vehicles); + + foreach($customer_vehicles as $cv) { - // get mobile data - $has_mobile = true; - $mobile_date = $mobile_session->getDateGenerated()->format("d M Y"); - $mobile_number = $mobile_session->getPhoneNumber(); + // get mobile session of customer + //error_log($cv->getCustomer()->getLastName() . ' ' . $cv->getCustomer()->getFirstName()); + $cust_id = $cv->getCustomer()->getID(); + $mobile_session = $em->getRepository(MobileSession::class) + ->findOneBy(['customer' => $cust_id], ['date_generated' => 'ASC']); + if ($mobile_session != null) + { + // get mobile data + //error_log('found mobile session for customer id ' . $cv->getCustomer()->getID()); + $has_mobile = true; + $mobile_date = $mobile_session->getDateGenerated()->format("d M Y"); + $mobile_number = $mobile_session->getPhoneNumber(); - // set best_cv to this customer vehicle with mobile session - $best_cv = $cv; + // set best_cv to this customer vehicle with mobile session + $best_cv = $cv; + } } + // set the customer data in results + $results[$key]['cust_id'] = $best_cv->getCustomer()->getID(); + $results[$key]['cust_lastname'] = $best_cv->getCustomer()->getLastName(); + $results[$key]['cust_firstname'] = $best_cv->getCustomer()->getFirstName(); + $results[$key]['cust_mobile_number'] = $best_cv->getCustomer()->getPhoneMobile(); + $results[$key]['plate_num'] = $best_cv->getPlateNumber(); + $results[$key]['has_mobile'] = ($has_mobile ? 'Yes' : 'No'); + $results[$key]['date_mobile'] = $mobile_date; + $results[$key]['mobile_number'] = $mobile_number; } - - // set the customer data in results - $results[$key]['cust_id'] = $best_cv->getCustomer()->getID(); - $results[$key]['cust_lastname'] = $best_cv->getCustomer()->getLastName(); - $results[$key]['cust_firstname'] = $best_cv->getCustomer()->getFirstName(); - $results[$key]['cust_mobile_number'] = $best_cv->getCustomer()->getPhoneMobile(); - $results[$key]['plate_num'] = $best_cv->getPlateNumber(); - $results[$key]['has_mobile'] = ($has_mobile ? 'Yes' : 'No'); - $results[$key]['date_mobile'] = $mobile_date; - $results[$key]['mobile_number'] = $mobile_number; } + // set the warranty data in results + $results[$key]['warr_lastname'] = $warranty->getLastName(); + $results[$key]['warr_firstname'] = $warranty->getFirstName(); + $results[$key]['warr_date_create'] = $warranty->getDateCreate()->format("d M Y"); + $results[$key]['warr_activation_status'] = ($warranty->isActivated() ? 'Active' : 'Inactive'); + $results[$key]['warr_class'] = $warranty->getWarrantyClass(); } - // set the warranty data in results - $results[$key]['warr_lastname'] = $warranty->getLastName(); - $results[$key]['warr_firstname'] = $warranty->getFirstName(); - $results[$key]['warr_date_create'] = $warranty->getDateCreate()->format("d M Y"); - $results[$key]['warr_activation_status'] = ($warranty->isActivated() ? 'Active' : 'Inactive'); } } } @@ -719,6 +901,265 @@ class ReportController extends Controller } return $results; + } + + protected function getWarrantyClassData(EntityManagerInterface $em) + { + $results = []; + + // query preregistered ustomers using search term '%9' + $cust_query = $em->createQuery('select c from App\Entity\Customer c where c.phone_mobile like :search_mobile') + ->setParameter('search_mobile', "%" . self::PREREGISTER_PREFIX); + $customers = $cust_query->iterate(); + + foreach($customers as $crow) + { + $cust = $crow[0]; + //error_log('Processing customer ' . $cust->getID()); + + // get list of customer vehicles + $c_vehicles = $cust->getVehicles(); + + foreach($c_vehicles as $cv) + { + if (!empty($c_vehicles)) + { + // find warranty for plate number + $clean_cv_plate = $this->cleanPlateNumber($cv->getPlateNumber()); + + $warranties = $em->getRepository(Warranty::class)->findBy(['plate_number' => $clean_cv_plate]); + + foreach ($warranties as $warr) + { + //error_log('Found warranty for plate number ' . $warr->getPlateNumber()); + + // form the result row + $results[] = $this->formWarrantyClassResult($cust, $cv, $warr); + } + } + } + $em->clear(); + + } + + return $results; + } + + protected function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } + + protected function formWarrantyClassResult($cust, $cv, $warr) + { + $batt_model = ''; + $batt_size = ''; + $sap_batt = ''; + $policy = ''; + $date_purchased = ''; + $date_expire = ''; + $date_claim = ''; + + $create_date = $warr->getDateCreate(); + $date_create = $create_date->format('d/M/y'); + + if ($warr->getDatePurchase() != null) + { + $p_date = $warr->getDatePurchase(); + $date_purchased = $p_date->format('d/M/y'); + } + if ($warr->getDateClaim() != null) + { + $c_date = $warr->getDateClaim(); + $date_claim = $c_date->format('d/M/y'); + } + if ($warr->getDateExpire() != null) + { + $e_date = $warr->getDateExpire(); + $date_expire = $e_date->format('d/M/y'); + } + + if ($warr->getBatteryModel() != null) + { + $batt_model = $warr->getBatteryModel()->getName(); + } + if ($warr->getBatterySize() != null) + { + $batt_size = $warr->getBatterySize()->getName(); + } + if ($warr->getSAPBattery() != null) + { + $sap_batt = $warr->getSAPBattery()->getBrand()->getName(); + } + if ($warr->getPrivacyPolicy() != null) + { + $policy = $warr->getPrivacyPolicy()->getName(); + } + + $data = [ + 'c_last_name' => $cust->getLastName(), + 'c_first_name' => $cust->getFirstName(), + 'manufacturer' => $cv->getVehicle()->getManufacturer()->getName(), + 'make' => $cv->getVehicle()->getMake(), + 'model_year' => $cv->getModelYear(), + 'color' => $cv->getColor(), + 'serial' => $warr->getSerial(), + 'class' => $warr->getWarrantyClass(), + 'plate_number' => $warr->getPlateNumber(), + 'w_last_name' => $warr->getLastName(), + 'w_first_name' => $warr->getFirstName(), + 'w_mobile_num' => $warr->getMobileNumber(), + 'w_batt_model' => $batt_model, + 'w_batt_size' => $batt_size, + 'w_sap_batt' => $sap_batt, + 'w_status' => $warr->getStatus(), + 'w_date_create' => $date_create, + 'w_date_purchase' => $date_purchased, + 'w_date_expire' => $date_expire, + 'w_date_claim' => $date_claim, + 'w_claimed_from' => $warr->getClaimedFrom(), + 'w_privacy_policy' => $policy, + 'w_activated' => ($warr->isActivated() ? 'Active' : 'Inactive'), + ]; + + return $data; } + + protected function getVehicleBatteryCompatibilityData(EntityManagerInterface $em) + { + $results = []; + + $conn = $em->getConnection(); + $sql = 'SELECT vm.name AS vm_name, v.make, + v.model_year_from, v.model_year_to, + bm.name AS bm_name, bmodel.name AS bmodel_name, + bsize.name AS bsize_name, + b.sap_code + FROM vehicle_manufacturer vm, vehicle v, battery_vehicle bv, + battery b, battery_manufacturer bm, battery_model bmodel, + battery_size bsize + WHERE vm.id = v.manufacturer_id + AND v.id = bv.vehicle_id + AND bv.battery_id = b.id + AND b.manufacturer_id = bm.id + AND b.model_id = bmodel.id + AND b.size_id = bsize.id + ORDER BY vm.name, v.make'; + + $stmt = $conn->prepare($sql); + $stmt->execute(); + + $query_results = $stmt->fetchAll(); + + foreach($query_results as $row) + { + $results[] = [ + 'vehicle_manufacturer' => $row['vm_name'], + 'vehicle_make' => $row['make'], + 'vehicle_model_year_from' => $row['model_year_from'], + 'vehicle_model_year_to' => $row['model_year_to'], + 'battery_manufacturer' => $row['bm_name'], + 'battery_model' => $row['bmodel_name'], + 'battery_size' => $row['bsize_name'], + 'battery_sap_code' => $row['sap_code'], + ]; + } + + return $results; + } + + protected function getWarrantyDetailsData(EntityManagerInterface $em) + { + $bm_hash = $this->loadBatteryModels($em); + $bs_hash = $this->loadBatterySizes($em); + + $results = []; + + $conn = $em->getConnection(); + $sql = 'SELECT w.id, w.serial, w.warranty_class, w.plate_number, + w.status, w.date_create, w.date_purchase, w.date_expire, + w.date_claim, w.sap_bty_id, w.claim_id, w.first_name, + w.last_name, w.mobile_number, w.flag_activated, + w.warranty_privacy_policy, w.bty_model_id, w.bty_size_id + FROM warranty w'; + + $stmt = $conn->prepare($sql); + $stmt->execute(); + + $query_results = $stmt->fetchAll(); + + foreach ($query_results as $row) + { + // get battery model and size names + $bmodel_name = ''; + $bm_id = $row['bty_model_id']; + if (!empty($bm_id)) + { + if (isset($bm_hash[$bm_id])) + $bmodel_name = $bm_hash[$bm_id]; + } + + $bsize_name = ''; + $bs_id = $row['bty_size_id']; + if (!empty($bs_id)) + { + if (isset($bs_hash[$bs_id])) + $bsize_name = $bs_hash[$bs_id]; + } + + $results[] = [ + 'id' => $row['id'], + 'serial' => $row['serial'], + 'battery_model' => $bmodel_name, + 'battery_size' => $bsize_name, + 'warranty_class' => $row['warranty_class'], + 'plate_number' => $row['plate_number'], + 'status' => $row['status'], + 'date_create' => $row['date_create'], + 'date_purchase' => $row['date_purchase'], + 'date_expire' => $row['date_expire'], + 'date_claim' => $row['date_claim'], + 'sap_bty_id' => $row['sap_bty_id'], + 'claim_id' => $row['claim_id'], + 'last_name' => $row['last_name'], + 'first_name' => $row['first_name'], + 'mobile_number' => $row['mobile_number'], + 'privacy_policy' => $row['warranty_privacy_policy'], + 'flag_activated' => (boolean) $row['flag_activated'], + ]; + } + + return $results; + } + + protected function loadBatteryModels(EntityManagerInterface $em) + { + $bmodel_hash = []; + + $models = $em->getRepository(BatteryModel::class)->findAll(); + foreach ($models as $model) + { + $bmodel_id = $model->getID(); + $bmodel_hash[$bmodel_id] = $model->getName(); + } + + return $bmodel_hash; + } + + protected function loadBatterySizes(EntityManagerInterface $em) + { + $bsize_hash = []; + + $sizes = $em->getRepository(BatterySize::class)->findAll(); + foreach ($sizes as $size) + { + $bsize_id = $size->getID(); + $bsize_hash[$bsize_id] = $size->getName(); + } + + return $bsize_hash; + } + } diff --git a/src/Controller/StaticContentController.php b/src/Controller/StaticContentController.php new file mode 100644 index 00000000..395736d4 --- /dev/null +++ b/src/Controller/StaticContentController.php @@ -0,0 +1,289 @@ +denyAccessUnlessGranted('static_content.list', null, 'No access.'); + + return $this->render('static-content/list.html.twig'); + } + + public function rows(Request $req) + { + $this->denyAccessUnlessGranted('static_content.list', null, 'No access.'); + + // build query + $qb = $this->getDoctrine() + ->getRepository(StaticContent::class) + ->createQueryBuilder('q'); + + // get datatable params + $datatable = $req->request->get('datatable'); + + // count total records + $tquery = $qb->select('COUNT(q)'); + + // add fitlers to count query + $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'); + + // add filters to query + $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(); + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('static_content.update')) + $row['meta']['update_url'] = $this->generateUrl('static_content_update', ['id' => $row['id']]); + if ($this->isGranted('static_content.delete')) + $row['meta']['delete_url'] = $this->generateUrl('static_content_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + /** + * @Menu(selected="static_content_list") + */ + public function addForm() + { + $this->denyAccessUnlessGranted('static_content.add', null, 'No access.'); + + $params = []; + $params['obj'] = new StaticContent(); + $params['mode'] = 'create'; + + // response + return $this->render('static-content/form.html.twig', $params); + } + + public function addSubmit(Request $req, ValidatorInterface $validator) + { + $this->denyAccessUnlessGranted('static_content.add', null, 'No access.'); + + // create new object + $em = $this->getDoctrine()->getManager(); + $row = new StaticContent(); + + // set and save values + $id = $req->request->get('id'); + $row->setID($id); + $row->setContent($req->request->get('content')); + + // validate + $errors = $validator->validate($row); + + // initialize error list + $error_array = []; + + // check for duplicate ID + $result = $em->getRepository(StaticContent::class)->find($id); + if ($result != null) + { + error_log($id); + $error_array['id'] = 'Duplicate ID exists.'; + } + + // 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($row); + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + } + + /** + * @Menu(selected="static_content_list") + */ + public function updateForm($id) + { + $this->denyAccessUnlessGranted('static_content.update', null, 'No access.'); + + $params = []; + $params['mode'] = 'update'; + + // get row data + $em = $this->getDoctrine()->getManager(); + $row = $em->getRepository(StaticContent::class)->find($id); + + // make sure this row exists + if (empty($row)) + throw $this->createNotFoundException('The item does not exist'); + + $params['obj'] = $row; + + // response + return $this->render('static-content/form.html.twig', $params); + } + + public function updateSubmit(Request $req, ValidatorInterface $validator, $id) + { + $this->denyAccessUnlessGranted('static_content.update', null, 'No access.'); + + // get row data + $em = $this->getDoctrine()->getManager(); + $row = $em->getRepository(StaticContent::class)->find($id); + + // make sure this row exists + if (empty($row)) + throw $this->createNotFoundException('The item does not exist'); + + // set and save values + $row->setID($req->request->get('id')) + ->setContent($req->request->get('content')); + + // validate + $errors = $validator->validate($row); + + // initialize error list + $error_array = []; + + // check for duplicate ID + $result = $em->getRepository(StaticContent::class)->find($id); + if ($result != null) + { + error_log($id); + $error_array['id'] = 'Duplicate ID exists.'; + } + + // 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->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + } + + /** + * @Menu(selected="static_content_list") + */ + public function destroy($id) + { + $this->denyAccessUnlessGranted('static_content.delete', null, 'No access.'); + + $params = []; + + // get row data + $em = $this->getDoctrine()->getManager(); + $row = $em->getRepository(StaticContent::class)->find($id); + + if (empty($row)) + throw $this->createNotFoundException('The item does not exist'); + + // delete this row + $em->remove($row); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } + + protected function setQueryFilters($datatable, &$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'] . '%'); + } + } +} diff --git a/src/Controller/WarrantyController.php b/src/Controller/WarrantyController.php index 0dc5a43e..40afec1a 100644 --- a/src/Controller/WarrantyController.php +++ b/src/Controller/WarrantyController.php @@ -4,15 +4,23 @@ namespace App\Controller; use App\Entity\Warranty; use App\Entity\SAPBattery; +use App\Entity\Battery; use App\Entity\BatteryModel; use App\Entity\BatterySize; +use App\Entity\Invoice; +use App\Entity\CustomerVehicle; use App\Ramcar\WarrantyClass; use App\Ramcar\WarrantyStatus; +use App\Service\WarrantyHandler; + use Doctrine\ORM\Query; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -22,6 +30,11 @@ use Catalyst\MenuBundle\Annotation\Menu; class WarrantyController extends Controller { + const PURCHASE_DATE_EMPTY = 'Purchase date missing.'; + const PLATE_NUM_EMPTY = 'Plate number missing.'; + const SERIAL_EMPTY = 'Serial number missing.'; + const PURCHASE_DATE_INVALID = 'Invalid purchase date.'; + /** * @Menu(selected="warranty_list") */ @@ -348,9 +361,239 @@ class WarrantyController extends Controller 'success' => 'Changes have been saved!' ]); } - } + /** + * @Menu(selected="warranty_list") + */ + public function uploadForm() + { + $this->denyAccessUnlessGranted('warranty.upload', null, 'No access.'); + + return $this->render('warranty/upload.form.html.twig'); + } + + /** + * @Menu(selected="warranty_list") + */ + public function uploadSubmit(Request $req, EntityManagerInterface $em, + WarrantyHandler $wh) + { + // retrieve temporary info for file + $file = $req->files->get('csv_file'); + + // process the csv file + $inv_entries = $this->processWarrantyFile($file, $em, $wh); + + $resp = new StreamedResponse(); + $resp->setCallback(function() use($inv_entries) { + // csv output + $csv_handle = fopen('php://output', 'w+'); + fputcsv($csv_handle, [ + 'Owner First Name', + 'Owner Last Name', + 'Owner Email', + 'Owner Address', + 'Owner Mobile', + 'Owner Telephone', + 'Vehicle Make', + 'Vehicle Model', + 'Vehicle Year', + 'Vehicle Plate Number', + 'Battery Serial Number', + 'Battery Sales Invoice', + 'Battery Date of Purchase', + 'Distributor Name', + 'Distributor Address', + 'Application Type ID', + 'Battery ID', + 'Ownership Type', + 'Reason Warranty Not Added', + ]); + foreach ($inv_entries as $row) + { + fputcsv($csv_handle, $row); + } + + fclose($csv_handle); + }); + + $filename = 'invalid_warranties' . '.csv'; + + $resp->setStatusCode(200); + $resp->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $resp->headers->set('Content-Disposition', 'attachment; filename="' . $filename . '"'); + + return $resp; + } + + protected function processWarrantyFile(UploadedFile $csv_file, EntityManagerInterface $em, + WarrantyHandler $wh) + { + // attempt to open file + try + { + $fh = fopen($csv_file, "r"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $csv_file . '" could be read.'); + } + + // loop through the rows + // 0 - Owner First Name + // 1 - Owner Last Name + // 2 - Owner Email + // 3 - Owner Address + // 4 - Owner Mobile + // 5 - Owner Telephone + // 6 - Vehicle Make + // 7 - Vehicle Model + // 8 - Vehicle Year + // 9 - Vehicle Plate Number + // 10 - Battery Serial Number + // 11 - Battery Sales Invoice + // 12 - Battery Date of Purchase + // 13 - Distributor Name + // 14 - Distributor Address + // 15 - Application Type ID + // 16 - Battery ID + // 17 - Ownership Type + + $row_num = 0; + $invalid_entries = []; + while (($fields = fgetcsv($fh)) !== false) + { + // start processing at row 1, not 0 + if ($row_num < 1) + { + $row_num++; + continue; + } + + // get the data + $first_name = trim($fields[0]); + $last_name = trim($fields[1]); + $mobile_number = trim($fields[4]); + $plate = trim($fields[9]); + $serial = trim($fields[10]); + $purchase_date = trim($fields[12]); + $battery_id = trim($fields[16]); + $batt_invoice = trim($fields[11]); + + $plate_number = $wh->cleanPlateNumber($plate); + + // check if purchase_date or plate_number or serial is empty or if + // purchase date is valid + $date_purchase = DateTime::createFromFormat('d-M-y', $purchase_date); + + if (empty($purchase_date) || + empty($plate_number) || + empty($serial) || + ($date_purchase == false)) + { + $reason = ''; + if (empty($plate_number)) + $reason = $reason . self::PLATE_NUM_EMPTY . ' '; + if (empty($serial)) + $reason = $reason . self::SERIAL_EMPTY . ' '; + if (empty($purchase_date)) + $reason = $reason . self::PURCHASE_DATE_EMPTY . ' '; + else + { + if ($date_purchase == false) + $reason = $reason . self::PURCHASE_DATE_INVALID . ' '; + } + + // add to invalid_entries + $invalid_entries[] = [ + 'owner_first_name' => $first_name, + 'owner_last_name' => $last_name, + 'owner_email' => trim($fields[2]), + 'owner_address' => trim($fields[3]), + 'owner_mobile' => $mobile_number, + 'owner_telephone' => trim($fields[5]), + 'vehicle_make' => trim($fields[6]), + 'vehicle_model' => trim($fields[7]), + 'vehicle_year' => trim($fields[8]), + 'vehicle_plate_number' => $plate_number, + 'battery_serial_number' => $serial, + 'battery_sales_invoice' => $batt_invoice, + 'battery_date_purchase' => $purchase_date, + 'distributor_name' => trim($fields[13]), + 'distributor_address' => trim($fields[14]), + 'application_type_id' => trim($fields[15]), + 'battery_id' => $battery_id, + 'ownership_type' => trim($fields[17]), + 'reason' => $reason, + ]; + } + else + { + // additional validation + // check if serial number and plate number already exists + $warr_results = $em->getRepository(Warranty::class)->findBy(['serial' => $serial, 'plate_number' => $plate_number]); + + // get battery via the invoice because battery_id doesn't match what's in the live data + // get job order via invoice to get the warranty class + $warranty_class = ''; + $batt_list = array(); + + // find invoice + $invoice = $em->getRepository(Invoice::class)->find($batt_invoice); + if (!empty($invoice)) + { + // get job order + $jo = $invoice->getJobOrder(); + + // get warranty class + $warranty_class = $jo->getWarrantyClass(); + + // get battery + $invoice_items = $invoice->getItems(); + foreach ($invoice_items as $item) + { + $battery = $item->getBattery(); + if ($battery != null) + { + $batt_list[] = $item->getBattery(); + } + } + } + + if (!empty($warr_results)) + { + foreach($warr_results as $warr) + { + // call service to check if warranty details is incomplete and then update warranty + // using details from csv file + error_log('Updating warranty for ' . $warr->getID()); + $wh->updateWarranty($warr, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase); + } + } + else + { + // TODO: what if serial exists but plate number is different? + // check if just the serial exists + // if warranty exists, ignore for now + $w_results = $em->getRepository(Warranty::class)->findBy(['serial' => $serial]); + if (!empty($w_results)) + { + continue; + } + + error_log('Creating warranty for serial ' . $serial . ' and plate number ' . $plate_number); + + $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class); + } + } + + $em->clear(); + $row_num++; + } + + return $invalid_entries; + } protected function fillDropdownParameters(&$params) { @@ -371,4 +614,10 @@ class WarrantyController extends Controller ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); } } + + protected function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } } diff --git a/src/Entity/BatteryModel.php b/src/Entity/BatteryModel.php index 86f3b666..b516e8a6 100644 --- a/src/Entity/BatteryModel.php +++ b/src/Entity/BatteryModel.php @@ -68,6 +68,7 @@ class BatteryModel public function getBatteries() { + // TODO: fix this to be a proper getter function // has to return set of strings because symfony is trying to move away from role objects $str_batteries = []; foreach ($this->batteries as $battery) diff --git a/src/Entity/BatterySize.php b/src/Entity/BatterySize.php index 021e115c..9fff4d44 100644 --- a/src/Entity/BatterySize.php +++ b/src/Entity/BatterySize.php @@ -89,6 +89,7 @@ class BatterySize public function getBatteries() { + // TODO: fix this to be a proper getter function // has to return set of strings because symfony is trying to move away from role objects $str_batteries = []; foreach ($this->batteries as $battery) diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index 5ae565a5..b96dfae9 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -10,13 +10,10 @@ use App\Ramcar\CustomerClassification; /** * @ORM\Entity - * @ORM\Table(name="customer") + * @ORM\Table(name="customer", indexes={@ORM\Index(name="phone_mobile_idx", columns={"phone_mobile"})}) */ class Customer { - // TODO: make this a setting somewhere - const COUNTRY_CODE_PREFIX = '+60'; - // unique id /** * @ORM\Id @@ -266,16 +263,16 @@ class Customer $phones = []; if (!empty($this->phone_mobile)) - $phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_mobile; + $phones[] = $this->phone_mobile; if (!empty($this->phone_landline)) - $phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_landline; + $phones[] = $this->phone_landline; if (!empty($this->phone_office)) - $phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_office; + $phones[] = $this->phone_office; if (!empty($this->phone_fax)) - $phones[] = self::COUNTRY_CODE_PREFIX . $this->phone_fax; + $phones[] = $this->phone_fax; return $phones; } diff --git a/src/Entity/CustomerVehicle.php b/src/Entity/CustomerVehicle.php index 4f593ac3..a5525a38 100644 --- a/src/Entity/CustomerVehicle.php +++ b/src/Entity/CustomerVehicle.php @@ -10,7 +10,8 @@ use DateTime; /** * @ORM\Entity - * @ORM\Table(name="customer_vehicle", indexes={@ORM\Index(columns={"plate_number"}, flags={"fulltext"})}) + * @ORM\Table(name="customer_vehicle", indexes={@ORM\Index(columns={"plate_number"}, flags={"fulltext"}), + @ORM\Index(name="plate_number_idx", columns={"plate_number"})}) */ class CustomerVehicle { @@ -54,7 +55,6 @@ class CustomerVehicle // model year /** * @ORM\Column(type="smallint") - * @Assert\NotBlank() */ protected $model_year; diff --git a/src/Entity/StaticContent.php b/src/Entity/StaticContent.php new file mode 100644 index 00000000..b450bb2a --- /dev/null +++ b/src/Entity/StaticContent.php @@ -0,0 +1,54 @@ +id = $id; + return $this; + } + + public function getID() + { + return $this->id; + } + + public function setContent($content) + { + $this->content = $content; + return $this; + } + + public function getContent() + { + return $this->content; + } +} + diff --git a/src/Entity/Warranty.php b/src/Entity/Warranty.php index 605d81ce..113fbb93 100644 --- a/src/Entity/Warranty.php +++ b/src/Entity/Warranty.php @@ -14,7 +14,8 @@ use Exception; * name="warranty", * uniqueConstraints={ * @ORM\UniqueConstraint(columns={"serial"}) - * } + * }, + * indexes={@ORM\Index(name="plate_number_idx", columns={"plate_number"})}) * ) */ class Warranty diff --git a/src/Service/CustomerHandler/CMBCustomerHandler.php b/src/Service/CustomerHandler/CMBCustomerHandler.php index a0f3ca2e..fb6a888e 100644 --- a/src/Service/CustomerHandler/CMBCustomerHandler.php +++ b/src/Service/CustomerHandler/CMBCustomerHandler.php @@ -25,17 +25,17 @@ use DateTime; class CMBCustomerHandler implements CustomerHandlerInterface { - const COUNTRY_CODE_PREFIX = '+60'; - protected $em; protected $validator; - + protected $country_code; protected $template_hash; - public function __construct(EntityManagerInterface $em, ValidatorInterface $validator) + public function __construct(EntityManagerInterface $em, ValidatorInterface $validator, + string $country_code) { $this->em = $em; $this->validator = $validator; + $this->country_code = $country_code; $this->loadTemplates(); } @@ -121,7 +121,14 @@ class CMBCustomerHandler implements CustomerHandlerInterface $row['flag_csat'] = $orow->isCSAT(); // TODO: properly add mobile numbers and plate numbers as searchable/sortable fields, use doctrine events - $row['mobile_numbers'] = implode("
", $orow->getMobileNumberList()); + // prepend the country code before each mobile number + $mobile_number_list = []; + $mobile_numbers = $orow->getMobileNumberList(); + foreach ($mobile_numbers as $mobile_number) + { + $mobile_number_list[] = $this->country_code . $mobile_number; + } + $row['mobile_numbers'] = implode("
", $mobile_number_list); $row['plate_numbers'] = implode("
", $orow->getPlateNumberList()); $rows[] = $row; @@ -467,7 +474,7 @@ class CMBCustomerHandler implements CustomerHandlerInterface $cust = $cv->getCustomer(); $vehicles[] = [ 'id' => $cv->getID(), - 'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')', + 'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. $this->country_code . $cust->getPhoneMobile() . ')', ]; } diff --git a/src/Service/CustomerHandler/ResqCustomerHandler.php b/src/Service/CustomerHandler/ResqCustomerHandler.php index 8ea688cf..5f7e00e2 100644 --- a/src/Service/CustomerHandler/ResqCustomerHandler.php +++ b/src/Service/CustomerHandler/ResqCustomerHandler.php @@ -27,17 +27,17 @@ use DateTime; class ResqCustomerHandler implements CustomerHandlerInterface { - const COUNTRY_CODE_PREFIX = '+63'; - protected $em; protected $validator; - + protected $country_code; protected $template_hash; - public function __construct(EntityManagerInterface $em, ValidatorInterface $validator) + public function __construct(EntityManagerInterface $em, ValidatorInterface $validator, + string $country_code) { $this->em = $em; $this->validator = $validator; + $this->country_code = $country_code; $this->loadTemplates(); } @@ -124,7 +124,14 @@ class ResqCustomerHandler implements CustomerHandlerInterface $row['flag_csat'] = $orow->isCSAT(); // TODO: properly add mobile numbers and plate numbers as searchable/sortable fields, use doctrine events - $row['mobile_numbers'] = implode("
", $orow->getMobileNumberList()); + // prepend the country code before each mobile number + $mobile_number_list = []; + $mobile_numbers = $orow->getMobileNumberList(); + foreach ($mobile_numbers as $mobile_number) + { + $mobile_number_list[] = $this->country_code . $mobile_number; + } + $row['mobile_numbers'] = implode("
", $mobile_number_list); $row['plate_numbers'] = implode("
", $orow->getPlateNumberList()); $rows[] = $row; @@ -465,7 +472,7 @@ class ResqCustomerHandler implements CustomerHandlerInterface $cust = $cv->getCustomer(); $vehicles[] = [ 'id' => $cv->getID(), - 'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. self::COUNTRY_CODE_PREFIX . $cust->getPhoneMobile() . ')', + 'text' => $cv->getPlateNumber() . ' ' . $cust->getFirstName() . ' ' . $cust->getLastName() . ' ('. $this->country_code . $cust->getPhoneMobile() . ')', ]; } diff --git a/src/Service/GeofenceTracker.php b/src/Service/GeofenceTracker.php index b2052e02..5acc7564 100644 --- a/src/Service/GeofenceTracker.php +++ b/src/Service/GeofenceTracker.php @@ -11,25 +11,33 @@ use CrEOF\Spatial\PHP\Types\Geometry\Point; class GeofenceTracker { protected $em; + protected $geofence_flag; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, $geofence_flag) { $this->em = $em; + $this->geofence_flag = $geofence_flag; } public function isCovered($long, $lat) { - // see if the point is in any of the polygons - $query = $this->em->createQuery('SELECT count(s) from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true') - ->setParameter('long', $long) - ->setParameter('lat', $lat); + // check if geofence is enabled + if ($this->geofence_flag == 'true') + { + // see if the point is in any of the polygons + $query = $this->em->createQuery('SELECT count(s) from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true') + ->setParameter('long', $long) + ->setParameter('lat', $lat); - // number of polygons that contain the point - $count = $query->getSingleScalarResult(); + // number of polygons that contain the point + $count = $query->getSingleScalarResult(); - if ($count > 0) - return true; + if ($count > 0) + return true; - return false; + return false; + } + + return true; } } diff --git a/src/Service/JobOrderHandler/CMBJobOrderHandler.php b/src/Service/JobOrderHandler/CMBJobOrderHandler.php index 1e4d8f9f..89dc9663 100644 --- a/src/Service/JobOrderHandler/CMBJobOrderHandler.php +++ b/src/Service/JobOrderHandler/CMBJobOrderHandler.php @@ -55,20 +55,20 @@ use FPDF; class CMBJobOrderHandler implements JobOrderHandlerInterface { - const COUNTRY_CODE_PREFIX = '+60'; - protected $em; protected $ic; protected $security; protected $validator; protected $translator; protected $rah; + protected $country_code; protected $template_hash; public function __construct(Security $security, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, ValidatorInterface $validator, - TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah) + TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah, + string $country_code) { $this->em = $em; $this->ic = $ic; @@ -76,6 +76,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $this->validator = $validator; $this->translator = $translator; $this->rah = $rah; + $this->country_code = $country_code; $this->loadTemplates(); } @@ -1860,7 +1861,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Mobile Phone:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneMobile() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? $this->country_code . $customer->getPhoneMobile() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); @@ -1877,7 +1878,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Landline:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneLandline() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? $this->country_code . $customer->getPhoneLandline() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); @@ -1887,11 +1888,11 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Office Phone:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneOffice() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? $this->country_code . $customer->getPhoneOffice() : '', 0, 'L'); $pdf->SetX($col2_x); $pdf->Cell($label_width, $line_height, 'Fax:'); - $pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneFax() : '', 0, 'L'); + $pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? $this->country_code . $customer->getPhoneFax() : '', 0, 'L'); // insert vehicle info $cv = $obj->getCustomerVehicle(); diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index f6f07188..e91e855e 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -53,25 +53,25 @@ use FPDF; class ResqJobOrderHandler implements JobOrderHandlerInterface { - const COUNTRY_CODE_PREFIX = '+60'; - protected $em; protected $ic; protected $security; protected $validator; protected $translator; + protected $country_code; protected $template_hash; public function __construct(Security $security, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, ValidatorInterface $validator, - TranslatorInterface $translator) + TranslatorInterface $translator, string $country_code) { $this->em = $em; $this->ic = $ic; $this->security = $security; $this->validator = $validator; $this->translator = $translator; + $this->country_code = $country_code; $this->loadTemplates(); } @@ -1868,7 +1868,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Mobile Phone:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneMobile() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneMobile() ? $this->country_code . $customer->getPhoneMobile() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); @@ -1885,7 +1885,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Landline:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneLandline() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneLandline() ? $this->country_code . $customer->getPhoneLandline() : '', 0, 'L'); // get Y after right cell $y2 = $pdf->GetY(); @@ -1895,11 +1895,11 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $pdf->SetXY($col2_x, $y); $pdf->Cell($label_width, $line_height, 'Office Phone:'); - $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneOffice() : '', 0, 'L'); + $pdf->MultiCell(0, $line_height, $customer && $customer->getPhoneOffice() ? $this->country_code . $customer->getPhoneOffice() : '', 0, 'L'); $pdf->SetX($col2_x); $pdf->Cell($label_width, $line_height, 'Fax:'); - $pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? self::COUNTRY_CODE_PREFIX . $customer->getPhoneFax() : '', 0, 'L'); + $pdf->MultiCell($val_width, $line_height, $customer && $customer->getPhoneFax() ? $this->country_code . $customer->getPhoneFax() : '', 0, 'L'); // insert vehicle info $cv = $obj->getCustomerVehicle(); diff --git a/src/Service/WarrantyHandler.php b/src/Service/WarrantyHandler.php new file mode 100644 index 00000000..bfc30021 --- /dev/null +++ b/src/Service/WarrantyHandler.php @@ -0,0 +1,332 @@ +em = $em; + } + + public function createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, + $batt_list, DateTime $date_purchase, $warranty_class) + { + // new warranty + $warranty = new Warranty(); + + foreach ($batt_list as $battery) + { + // get the battery model and battery size + $model_id = $battery->getModel()->getID(); + $size_id = $battery->getSize()->getID(); + + $bty_model = $this->em->getRepository(BatteryModel::class)->find($model_id); + $bty_size = $this->em->getRepository(BatterySize::class)->find($size_id); + + if ($bty_model != null) + { + $warranty->setBatteryModel($bty_model); + } + if ($bty_size != null) + { + $warranty->setBatterySize($bty_size); + } + + $sap_code = $battery->getSAPCode(); + if (!empty($sap_code)) + { + // find sap battery + $sap_battery = $this->em->getRepository(SAPBattery::class)->find($sap_code); + if ($sap_battery != null) + { + $warranty->setSAPBattery($sap_battery); + } + } + } + + // compute expiry date + $date_expire = null; + if ((!empty($warranty_class)) && + (count($batt_list) != 0)) + { + $period = $this->getWarrantyPeriod($batt_list, $warranty_class); + $date_expire = $this->computeDateExpire($date_purchase, $period); + + $warranty->setDateExpire($date_expire); + } + + // set and save values + $warranty->setSerial($serial) + ->setPlateNumber($plate_number) + ->setFirstName($first_name) + ->setLastName($last_name) + ->setMobileNumber($mobile_number) + ->setDatePurchase($date_purchase); + + $this->em->persist($warranty); + $this->em->flush(); + + // update customer vehicle with warranty info + $this->updateCustomerVehicle($serial, $batt_list, $plate_number, $date_expire); + + $this->em->clear(); + } + + public function updateCustomerVehicle($serial, $batteries, $plate_number, $date_expire) + { + // find customer vehicle using plate number + error_log('Finding customer vehicle with plate number ' . $plate_number); + $cv_q = $this->em->createQuery('select count(cv) from App\Entity\CustomerVehicle cv where cv.plate_number = :plate_number') + ->setParameter('plate_number', $plate_number); + $cv_result = $cv_q->getSingleScalarResult(); + + $battery_id = null; + if ($cv_result != 0) + { + if (!empty($batteries)) + { + // set current battery to the first battery in list. + // there are cases where multiple batteries linked to an SAP code. + $battery = $batteries[0]; + $battery_id = $battery->getID(); + } + //error_log('Serial/Warranty Code = ' . $serial); + $q = $this->em->createQuery('update App\Entity\CustomerVehicle cv + set cv.curr_battery = :batt_id, + cv.warranty_code = :serial, + cv.warranty_expiration = :expiry_date + where cv.plate_number = :plate_number') + ->setParameters([ + 'batt_id' => $battery_id, + 'serial' => $serial, + 'expiry_date' => $date_expire, + 'plate_number' => $plate_number]); + $q->execute(); + } + } + + public function updateWarranty(Warranty $warr, $first_name, $last_name, $mobile_number, $batt_list, DateTime $date_purchase) + { + // TODO: add serial and plate number to update + // TODO: check if data from existing warranty matches the new data + // check if details are complete + if (empty($warr->getFirstName())) + { + if (!empty($first_name)) + { + $warr->setFirstName($first_name); + } + } + if (empty($warr->getLastName())) + { + if (!empty($last_name)) + { + $warr->setLastName($last_name); + } + } + if (empty($warr->getMobileNumber())) + { + if (!empty($mobile_number)) + { + $warr->setMobileNumber($mobile_number); + } + } + if ((empty($warr->getBatteryModel())) || + (empty($warr->getBatterySize()))) + { + if (count($batt_list) != 0) + { + foreach ($batt_list as $battery) + { + // get the battery model and battery size + $model_id = $battery->getModel()->getID(); + $size_id = $battery->getSize()->getID(); + + $bty_model = $this->em->getRepository(BatteryModel::class)->find($model_id); + $bty_size = $this->em->getRepository(BatterySize::class)->find($size_id); + + if ($bty_model != null) + { + $warranty->setBatteryModel($bty_model); + } + if ($bty_size != null) + { + $warranty->setBatterySize($bty_size); + } + + $sap_code = $battery->getSAPCode(); + if (!empty($sap_code)) + { + // find sap battery + $sap_battery = $this->em->getRepository(SAPBattery::class)->find($sap_code); + if ($sap_battery != null) + { + $warranty->setSAPBattery($sap_battery); + } + } + } + } + } + + $purchase_date = $warr->getDatePurchase(); + if (empty($purchase_date)) + { + if (!empty($date_purchase)) + { + $warr->setDatePurchase($date_purchase); + } + $purchase_date = $date_purchase; + } + + if (empty($warr->getDateExpire())) + { + $batteries = []; + if (count($batt_list) == 0) + { + $batteries = $this->getBatteriesForWarranty($warr); + } + else + { + $batteries = $batt_list; + } + + if (!empty($batteries)) + { + $period = $this->getWarrantyPeriod($batteries, $warr->getWarrantyClass()); + if (!empty($purchase_date)) + { + $expire_date = $this->computeDateExpire($purchase_date, $period); + $warr->setDateExpire($expire_date); + } + } + } + + $this->em->persist($warr); + $this->em->flush(); + $this->em->clear(); + } + + public function computeDateExpire($date_create, $warranty_period) + { + $expire_date = clone $date_create; + $expire_date->add(new DateInterval('P'.$warranty_period.'M')); + return $expire_date; + } + + public function getWarrantyPeriod($batteries, $warranty_class) + { + // set to -1 to show that we haven't set a warranty period yet + // cannot set initial value to 0 because warranty tnv can be 0 + $least_warranty = -1; + $warr_period = 0; + foreach ($batteries as $battery) + { + // if multiple batteries, get the smallest warranty period + // check warranty class to get warranty period + if ($warranty_class == WarrantyClass::WTY_PRIVATE) + { + $warr_period = $battery->getWarrantyPrivate(); + //error_log('Warranty Period for Private: ' . $warr_period); + } + if ($warranty_class == WarrantyClass::WTY_COMMERCIAL) + { + $warr_period = $battery->getWarrantyCommercial(); + //error_log('Warranty Period for Commercial: ' . $warr_period); + } + if ($warranty_class == WarrantyClass::WTY_TNV) + { + $warr_period = $battery->getWarrantyTnv(); + //error_log('Warranty Period for TNV: ' . $warr_period); + } + + if ($least_warranty < 0) + { + // set least warranty to the first obtained warranty period + $least_warranty = $warr_period; + } + + if ($least_warranty > $warr_period) + { + $least_warranty = $warr_period; + } + } + + $warranty_period = $least_warranty; + + return $warranty_period; + } + + public function getBatteriesForWarranty($warr) + { + // find battery via sku/sap battery first + // if sku is null, use battery model and battery size to find battery + // if all three are null, do nothing + $batteries = null; + + $sap_battery = $warr->getSAPBattery(); + $batt_model = $warr->getBatteryModel(); + $batt_size = $warr->getBatterySize(); + $warranty_class = $warr->getWarrantyClass(); + + if (empty($warranty_class)) + { + error_log('Warranty class is empty for warranty id ' . $warr->getID()); + return null; + } + + if ($sap_battery != null) + { + // get the battery linked to SAP Battery using sap_battery id + $batteries = $this->em->getRepository(Battery::class)->findBy(['sap_code' => $sap_battery->getID()]); + } + else + { + if ($batt_model == null) + { + error_log('Battery model is null for warranty id ' . $warr->getID()); + return null; + } + if ($batt_size == null) + { + error_log('Battery size is null for warranty id ' . $warr->getID()); + return null; + } + + // find battery using battery model and battery size + $batteries = $this->em->getRepository(Battery::class)->findBy(['model' => $batt_model, 'size' => $batt_size]); + } + + if (empty($batteries)) + { + error_log('Battery not found for warranty id ' . $warr->getID()); + return null; + } + + return $batteries; + } + + + public function cleanPlateNumber($plate) + { + // remove spaces and make upper case + return strtoupper(str_replace(' ', '', $plate)); + } + +} diff --git a/symfony.lock b/symfony.lock index 81b878d9..88d10d33 100644 --- a/symfony.lock +++ b/symfony.lock @@ -98,6 +98,9 @@ "doctrine/reflection": { "version": "v1.0.0" }, + "edwinhoksberg/php-fcm": { + "version": "1.0.0" + }, "guzzlehttp/guzzle": { "version": "6.3.0" }, diff --git a/templates/base.html.twig b/templates/base.html.twig index ad096362..ec13aa91 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -153,7 +153,7 @@ diff --git a/templates/customer/form.html.twig b/templates/customer/form.html.twig index 4f2f5e9f..f502e778 100644 --- a/templates/customer/form.html.twig +++ b/templates/customer/form.html.twig @@ -131,7 +131,7 @@ Mobile Phone
- +63 + {% trans %}country_code_prefix{% endtrans %}
@@ -141,7 +141,7 @@ Landline
- +63 + {% trans %}country_code_prefix{% endtrans %}
@@ -153,7 +153,7 @@ Office Phone
- +63 + {% trans %}country_code_prefix{% endtrans %}
@@ -163,7 +163,7 @@ Fax
- +63 + {% trans %}country_code_prefix{% endtrans %}
diff --git a/templates/report/vehicle-battery-compatibility/form.html.twig b/templates/report/vehicle-battery-compatibility/form.html.twig new file mode 100644 index 00000000..83dea44a --- /dev/null +++ b/templates/report/vehicle-battery-compatibility/form.html.twig @@ -0,0 +1,50 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Vehicle Battery Compatibility Report +

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ Generate Vehicle Battery Compatibility CSV File +

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+{% endblock %} + diff --git a/templates/report/warranty-class/form.html.twig b/templates/report/warranty-class/form.html.twig new file mode 100644 index 00000000..a2313b1d --- /dev/null +++ b/templates/report/warranty-class/form.html.twig @@ -0,0 +1,50 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Warranty Class Report +

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ Generate Warranty Class CSV File +

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+{% endblock %} + diff --git a/templates/report/warranty-details/form.html.twig b/templates/report/warranty-details/form.html.twig new file mode 100644 index 00000000..c329785a --- /dev/null +++ b/templates/report/warranty-details/form.html.twig @@ -0,0 +1,50 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Warranty Details Report +

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ Generate Warranty Details CSV File +

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+{% endblock %} + diff --git a/templates/static-content/form.html.twig b/templates/static-content/form.html.twig new file mode 100644 index 00000000..dece1005 --- /dev/null +++ b/templates/static-content/form.html.twig @@ -0,0 +1,142 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

Static Content

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ {% if mode == 'update' %} + Edit Static Content + {{ obj.getID() }} + {% else %} + New Static Content + {% endif %} +

+
+
+
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+
+
+ + Back +
+
+
+
+
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/static-content/list.html.twig b/templates/static-content/list.html.twig new file mode 100644 index 00000000..186f0958 --- /dev/null +++ b/templates/static-content/list.html.twig @@ -0,0 +1,138 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Static Content +

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/warranty/upload.form.html.twig b/templates/warranty/upload.form.html.twig new file mode 100644 index 00000000..d778bf47 --- /dev/null +++ b/templates/warranty/upload.form.html.twig @@ -0,0 +1,52 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Warranty Upload +

+
+
+
+ +
+ +
+
+
+
+
+
+ + + +

+ Upload Warranty CSV File +

+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+{% endblock %} diff --git a/utils/fcm_sender/file_send.php b/utils/fcm_sender/file_send.php new file mode 100644 index 00000000..e413a8df --- /dev/null +++ b/utils/fcm_sender/file_send.php @@ -0,0 +1,23 @@ +addRecipient($device_id) + ->setTitle('Motolite RES-Q') + ->setBody('Test notification sending') + +// Send the notification to the Firebase servers for further handling. +$client->send($notification);