em = $em; parent::__construct(); } protected function configure() { $this->setName('testwarranty:upload') ->setDescription('Test bulk warranty upload.') ->setHelp('Test bulk warranty upload.') ->addArgument('input_file', InputArgument::REQUIRED, 'Path to the CSV file.') ->addArgument('output_file', InputArgument::REQUIRED, 'Path to output file.'); } protected function execute(InputInterface $input, OutputInterface $output) { // hash the battery table using sap_code as index $this->populateBatteryIndex(); $csv_file = $input->getArgument('input_file'); $output_file = $input->getArgument('output_file'); // 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(); } // write to output file $this->outputWarrantyInfo($output_file, $output_info); fclose($fh); return 0; } 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); 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 ADDED', $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 ADDED', $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 ADDED', $message); return $errors; } // validate serial // (1) should not be empty if (empty($serial)) { $message = 'No battery serial number.'; $errors = $this->setOutputInfo($fields, 'NOT ADDED', $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 ADDED', $message); return $errors; } if (!(isset($this->batt_hash[$sap_code]))) { $message = '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(); // 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 ADDED', $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 ADDED', $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 outputWarrantyInfo($output_file, $entries) { try { $fh = fopen($output_file, "w"); } catch (Exception $e) { throw new Exception('The file "' . $report_file . '" could be opened.'); } // write the headers fputcsv($fh, [ 'Encoded By', 'Date of Encoded', 'Owner First Name', 'Owner Last Name', 'Owner Email', 'Owner Address', 'Owner Mobile', 'Owner Telephone', 'Vehicle Make', 'Vehicle Model', 'Vehicle Year', 'Vehicle Plate No.', 'Battery Serial No.', 'Battery Sales Invoice No.', 'Battery Date of Purchase', 'Distributor Name', 'Distributor Address', 'Application Type ID', 'Battery ID', 'Ownership Type', 'Status', 'Reason', ]); foreach($entries as $row) { if ($row != null) fputcsv($fh, $row); } fclose($fh); } 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)); } }