From 8401eeb0da11c4a8723c111ba27543a32ab1b90c Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 10 May 2022 06:28:28 +0000 Subject: [PATCH] Move the bulk warranty upload to its own service. #660 --- config/services.yaml | 5 + src/Command/TestWarrantyUploadCommand.php | 34 -- src/Controller/WarrantyController.php | 14 +- src/Service/WarrantyBulkUploader.php | 401 ++++++++++++++++++++++ 4 files changed, 415 insertions(+), 39 deletions(-) create mode 100644 src/Service/WarrantyBulkUploader.php diff --git a/config/services.yaml b/config/services.yaml index 0498fcdd..9d1ee14e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -301,3 +301,8 @@ services: App\Service\HubFilteringGeoChecker: arguments: $geofence_flag: "%env(HUB_GEOFENCE_ENABLE)%" + + # bulk warranty uploader + App\Service\WarrantyBulkUploader: + arguments: + $em: "@doctrine.orm.entity_manager" diff --git a/src/Command/TestWarrantyUploadCommand.php b/src/Command/TestWarrantyUploadCommand.php index 4b216472..1155c6f1 100644 --- a/src/Command/TestWarrantyUploadCommand.php +++ b/src/Command/TestWarrantyUploadCommand.php @@ -65,9 +65,6 @@ class TestWarrantyUploadCommand extends Command // hash the battery table using sap_code as index $this->populateBatteryIndex(); - // hash the sap battery table using id aka sap code as index - $this->populateSAPBatteryIndex(); - $csv_file = $input->getArgument('input_file'); $output_file = $input->getArgument('output_file'); @@ -264,8 +261,6 @@ class TestWarrantyUploadCommand extends Command // validate battery // (1) should not be empty // (2) should find battery using sap_code. - // (3) TODO: depending on Myla's answer. If she says sap_code is id of sap battery - // should find sap battery using sap_code if (empty($sap_code)) { $message = 'No battery ID.'; @@ -280,14 +275,6 @@ class TestWarrantyUploadCommand extends Command return $errors; } - // TODO: remove this if Myla says sap code is not id of sap battery - if (!(isset($this->sap_batt_hash[$sap_code]))) - { - $message = 'SAP Battery not found.'; - $errors = $this->setOutputInfo($fields, 'NOT ADDED', $message); - return $errors; - } - // (1) check if warranty exists using serial + plate number // (2) check if serial already exists even if for another plate number $conn = $this->em->getConnection(); @@ -469,27 +456,6 @@ class TestWarrantyUploadCommand extends Command } } - protected function populateSAPBatteryIndex() - { - $conn = $this->em->getConnection(); - - // get all the sap batteries - $sql = 'SELECT sap.id, sap.brand_id, sap.size_id FROM sap_battery sap'; - $stmt = $conn->prepare($sql); - $stmt->execute(); - - $results = $stmt->fetchAll(); - - // go through the rows - foreach ($results as $row) - { - $this->sap_batt_hash[$row['id']] = [ - 'sap_brand' => $row['brand_id'], - 'sap_size' => $row['size_id'], - ]; - } - } - protected function cleanPlateNumber($plate) { return strtoupper(str_replace(' ', '', $plate)); diff --git a/src/Controller/WarrantyController.php b/src/Controller/WarrantyController.php index 9c74dee8..3e45576d 100644 --- a/src/Controller/WarrantyController.php +++ b/src/Controller/WarrantyController.php @@ -15,8 +15,8 @@ use App\Ramcar\WarrantyClass; use App\Ramcar\WarrantyStatus; use App\Ramcar\WarrantySource; -use App\Service\WarrantyHandler; use App\Service\WarrantyAPILogger; +use App\Service\WarrantyBulkUploader; use Doctrine\ORM\Query; use Doctrine\ORM\EntityManagerInterface; @@ -448,14 +448,13 @@ class WarrantyController extends Controller /** * @Menu(selected="warranty_list") */ - public function uploadSubmit(Request $req, EntityManagerInterface $em, - WarrantyHandler $wh) + public function uploadSubmit(Request $req, WarrantyBulkUploader $warr_uploader) { // retrieve temporary info for file $file = $req->files->get('csv_file'); - // process the csv file - $inv_entries = $this->processWarrantyFile($file, $em, $wh); + // process the csv file. Call the WarrantyBulkUploader service + $inv_entries = $warr_uploader->warrantyUpload($file); $resp = new StreamedResponse(); @@ -465,6 +464,8 @@ class WarrantyController extends Controller // csv output $csv_handle = fopen('php://output', 'w+'); fputcsv($csv_handle, [ + 'Encoded By', + 'Date of Encoded', 'Owner First Name', 'Owner Last Name', 'Owner Email', @@ -483,6 +484,7 @@ class WarrantyController extends Controller 'Application Type ID', 'Battery ID', 'Ownership Type', + 'Status', 'Reason Warranty Not Added', ]); foreach ($inv_entries as $row) @@ -514,6 +516,8 @@ class WarrantyController extends Controller return $resp; } + // NOTE: this is not being called anymore. We are now using the WarrantyBulkUploader service. + // Do we delete this? protected function processWarrantyFile(UploadedFile $csv_file, EntityManagerInterface $em, WarrantyHandler $wh) { diff --git a/src/Service/WarrantyBulkUploader.php b/src/Service/WarrantyBulkUploader.php new file mode 100644 index 00000000..085386a4 --- /dev/null +++ b/src/Service/WarrantyBulkUploader.php @@ -0,0 +1,401 @@ +em = $em; + } + + public function warrantyUpload(UploadedFile $csv_file) + { + // hash the battery table using sap_code as index + $this->populateBatteryIndex(); + + // attempt to open file + try + { + $fh = fopen($csv_file, "r"); + } + catch (Exception $e) + { + throw new Exception('The file "' . $csv_file . '" could be read.'); + } + + $output_info = []; + + // loop through rows + // ignore first row since that's header data + $row_num = 0; + + $sql_values = ''; + while (($fields = fgetcsv($fh)) !== false) + { + // ignore first row since that's the header + if ($row_num == 0) + { + $row_num++; + continue; + } + + // process row + $output_info[] = $this->processRow($fields, $sql_values); + + $row_num++; + } + + // check if we have values to insert + if (strlen($sql_values) > 0) + { + $sql_statement = 'INSERT INTO `warranty` (bty_model_id,bty_size_id,sap_bty_id,serial,warranty_class,plate_number,status,date_create,date_purchase,date_expire,first_name,last_name,mobile_number,flag_activated,vehicle_id,customer_id, create_source) VALUES ' . $sql_values . ';' . "\n"; + + // error_log($sql_statement); + + $conn = $this->em->getConnection(); + $stmt = $conn->prepare($sql_statement); + $stmt->execute(); + } + + fclose($fh); + + // return invalid entries + return $output_info; + } + + protected function processRow($fields, &$sql_values) + { + // error_log('Processing warranty with serial ' . trim($fields[self::F_SERIAL])); + + $output_info = []; + + // get necessary fields + $fname = trim($fields[self::F_FNAME]); + $lname = trim($fields[self::F_LNAME]); + $mobile = trim($fields[self::F_MOBILE]); + $serial = trim($fields[self::F_SERIAL]); + $date_purchase = trim($fields[self::F_DATE_PURCHASE]); + $sap_code = trim($fields[self::F_BATT_ID]); + $plate_number = $this->cleanPlateNumber($fields[self::F_PLATE_NUMBER]); + + // validate the necessary fields + $output_info = $this->validateFields($fields); + if (!empty($output_info)) + return $output_info; + + // see if we can get customer id and vehicle id, given the plate number. + // this is not required so if we can't find customer and/or vehicle, + // we still create the warranty + $conn = $this->em->getConnection(); + + // NOTE: what happens if there's more than one result? + // for now, get the first one + $sql = 'SELECT c.id AS c_id, v.id AS v_id FROM customer_vehicle cv, customer c, vehicle v + WHERE cv.customer_id = c.id AND cv.vehicle_id = v.id AND cv.plate_number = :plate_number LIMIT 1'; + $stmt = $conn->prepare($sql); + $stmt->execute(['plate_number' => $plate_number]); + + $cv_results = $stmt->fetch(); + + $cust_id = 'NULL'; + $vehicle_id = 'NULL'; + if (!empty($cv_results)) + { + $cust_id = $cv_results['c_id']; + $vehicle_id = $cv_results['v_id']; + } + + // get battery info from hash (battery model id, battery size id, warranty periods (needed for expiration date) + $batt_info = $this->batt_hash[$sap_code]; + $b_id = $batt_info['id']; + $model_id = $batt_info['model_id']; + $size_id = $batt_info['size_id']; + $warr_private = $batt_info['warr_private']; + $warr_commercial = $batt_info['warr_commercial']; + $warr_tnv = $batt_info['warr_tnv']; + + // format purchase date to DateTime and then change the format to Y-m-d + $purchase_date = DateTime::createFromFormat('m/d/y', $date_purchase); + + // need to manually create the created date + $date_create = date('Y-m-d H:i:s'); + + // compute expiration date + // TODO: might need checking for what kind of warranty for the warranty period + // by default, we use private + $warranty_class = WarrantyClass::WTY_PRIVATE; + $date_expire = $this->computeDateExpire($purchase_date, $warr_private); + + // convert all dates to string for the values string for the insert statement + //$str_date_create = $date_create->format('Y-m-d H:i:s'); + $str_date_purchase = $purchase_date->format('Y-m-d H:i:s'); + $str_date_expire = $date_expire->format('Y-m-d H:i:s'); + + $first_name = addslashes($fname); + $last_name = addslashes($lname); + $mobile_number = addslashes($mobile); + + // populate the values string for the values to be inserted into warranty + $value_string = '(' . $model_id . ',' . $size_id . ',\'' . $sap_code . '\',\'' . $serial . '\',\'' . $warranty_class . '\',\'' + . $plate_number . '\',\'' . WarrantyStatus::ACTIVE . '\',\'' . $date_create . '\',\'' . $str_date_purchase + . '\',\'' . $str_date_expire . '\',\'' . $first_name . '\',\'' . $last_name . '\',\'' . $mobile_number . '\',' . 1 . ',' . $vehicle_id . ',' . $cust_id . ',\'' . WarrantySource::BULK_UPLOAD . '\')'; + + if (strlen($sql_values) == 0) + { + // first entry to insert, should have no comma before + $sql_values = $value_string; + } + else + { + // need to insert a comma after the existing string + $sql_values = $sql_values . ',' . $value_string; + } + + // error_log($sql_values); + + // if we reach this point, warranty is going to be uploaded + // so we also output to file the warranty that will be uploaded + $output_info = $this->setOutputInfo($fields, 'UPLOADED', ''); + + return $output_info; + } + + protected function validateFields($fields) + { + $errors = []; + + $serial = trim($fields[self::F_SERIAL]); + $date_purchase = trim($fields[self::F_DATE_PURCHASE]); + $sap_code = trim($fields[self::F_BATT_ID]); + $plate_number = trim($fields[self::F_PLATE_NUMBER]); + + // clean the plate number + $clean_plate = $this->cleanPlateNumber($plate_number); + + // validate the plate number + // (1) plate number should not be empty + if (empty($clean_plate)) + { + $message = 'No plate number.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + // validate date purchase + // (1) date purchase should not be empty + // (2) date purchase should be of format: d-M-y + if (empty($date_purchase)) + { + $message = 'No date purchase.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + + $purchase_date = DateTime::createFromFormat('m/d/y', $date_purchase); + if ($purchase_date === false) + { + $message = 'Invalid date format. Date format should be: m/d/y (example: 06/13/16)'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + // validate serial + // (1) should not be empty + if (empty($serial)) + { + $message = 'No battery serial number.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + // validate battery + // (1) should not be empty + // (2) should find battery using sap_code. + if (empty($sap_code)) + { + $message = 'No battery ID.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + + if (!(isset($this->batt_hash[$sap_code]))) + { + $message = 'Battery not found.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + + // (1) check if warranty exists using serial + plate number + // (2) check if serial already exists even if for another plate number + $conn = $this->em->getConnection(); + + // find warranties using serial + plate number + $sql = 'SELECT w.id FROM warranty w WHERE w.serial = :serial AND w.plate_number = :plate_number'; + $stmt = $conn->prepare($sql); + $stmt->execute([ + 'serial' => $serial, + 'plate_number' => $plate_number, + ]); + + $warr_results = $stmt->fetchAll(); + + if (!empty($warr_results)) + { + $message = 'Warranty already exists for serial and plate number.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + + // find warranties using serial number alone + $w_sql = 'SELECT w.id FROM warranty w WHERE w.serial = :serial'; + $w_stmt = $conn->prepare($w_sql); + $w_stmt->execute([ + 'serial' => $serial, + ]); + + $w_results = $w_stmt->fetchAll(); + + if (!empty($w_results)) + { + $message = 'Warranty already exists for serial.'; + $errors = $this->setOutputInfo($fields, 'NOT UPLOADED', $message); + return $errors; + } + + return $errors; + } + + protected function computeDateExpire($date_create, $warranty_period) + { + $expire_date = clone $date_create; + $expire_date->add(new DateInterval('P'.$warranty_period.'M')); + return $expire_date; + } + + protected function setOutputInfo($fields, $status, $message) + { + $encoder = trim($fields[self::F_ENCODER]); + $date_encoded = trim($fields[self::F_DATE_ENCODED]); + $fname = trim($fields[self::F_FNAME]); + $lname = trim($fields[self::F_LNAME]); + $email = trim($fields[self::F_EMAIL]); + $address = trim($fields[self::F_ADDRESS]); + $mobile = trim($fields[self::F_MOBILE]); + $telephone = trim($fields[self::F_TELEPHONE]); + $vmake = trim($fields[self::F_VMAKE]); + $vmodel = trim($fields[self::F_VMODEL]); + $year = trim($fields[self::F_MYEAR]); + $serial = trim($fields[self::F_SERIAL]); + $invoice_number = trim($fields[self::F_INVOICE_NUM]); + $date_purchase = trim($fields[self::F_DATE_PURCHASE]); + $dist_name = trim($fields[self::F_DIST_NAME]); + $dist_address = trim($fields[self::F_DIST_ADDRESS]); + $app_type_id = trim($fields[self::F_APP_TYPE_ID]); + $sap_code = trim($fields[self::F_BATT_ID]); + $plate_number = trim($fields[self::F_PLATE_NUMBER]); + $owner_type = trim($fields[self::F_OWNER_TYPE]); + + return [ + $encoder, + $date_encoded, + $fname, + $lname, + $email, + $address, + $mobile, + $telephone, + $vmake, + $vmodel, + $year, + $plate_number, + $serial, + $invoice_number, + $date_purchase, + $dist_name, + $dist_address, + $app_type_id, + $sap_code, + $owner_type, + $status, + $message, + ]; + } + + protected function populateBatteryIndex() + { + $conn = $this->em->getConnection(); + + // get all the batteries + $sql = 'SELECT b.id, b.model_id, b.size_id, b.sap_code, b.warr_private, b.warr_commercial, b.warr_tnv + FROM battery b'; + $stmt = $conn->prepare($sql); + $stmt->execute(); + + $results = $stmt->fetchAll(); + + // go through the rows + foreach ($results as $row) + { + // breaking this down for clarity + $battery_id = $row['id']; + $model_id = $row['model_id']; + $size_id = $row['size_id']; + $sap_code = trim($row['sap_code']); + $warr_private = $row['warr_private']; + $warr_commercial = $row['warr_commercial']; + $warr_tnv = $row['warr_tnv']; + + if(!empty($sap_code)) + { + $this->batt_hash[$sap_code] = [ + 'id' => $battery_id, + 'model_id' => $model_id, + 'size_id' => $size_id, + 'warr_private' => $warr_private, + 'warr_commercial' => $warr_commercial, + 'warr_tnv' => $warr_tnv, + ]; + } + } + } + + protected function cleanPlateNumber($plate) + { + return strtoupper(str_replace(' ', '', $plate)); + } + +}