em = $em; $this->loadCustomerTags(); parent::__construct(); } protected function configure() { $this->setName('customer:createfromcarclub') ->setDescription('Create customers from car club file.') ->setHelp('Creates customers from car club file.') ->addArgument('promo_tag', InputArgument::REQUIRED, 'Promo customer tag ID to use.') ->addArgument('input_file', InputArgument::REQUIRED, 'Path to the output CSV file with the car club info.') ->addArgument('output_file', InputArgument::REQUIRED, 'Output filename'); } protected function getValidContactNumbers($contact_number) { // check contact number if mobile or not // check for spaces, slash, and forward slash $contact_num_array = []; if (preg_match('/[\\\s\/]/', $contact_number)) { $contact_num_array = preg_split('/[\\\s\/]/', $contact_number); } else { // only one mobile number $contact_num_array[] = $contact_number; } // collet clean numbers $clean_nums = []; foreach ($contact_num_array as $contact_num) { $c_num = trim($contact_num); // clean the numbers $cleaned_number = $this->normalizeContactNumber($c_num); // not a blank, save it if ($cleaned_number != '') { $clean_nums[] = $cleaned_number; } } return $clean_nums; } protected function execute(InputInterface $input, OutputInterface $output) { $csv_file = $input->getArgument('input_file'); $output_file = $input->getArgument('output_file'); $promo_tag_id = $input->getArgument('promo_tag'); // fetch promo tag $promo_tag = $this->em->getRepository(CustomerTag::class)->find($promo_tag_id); if ($promo_tag == null) { throw new Exception('Could not find promo tag - ' . $promo_tag_id); } // attempt to open file try { $fh = fopen($csv_file, "r"); } catch (Exception $e) { throw new Exception('The file "' . $csv_file . '" could be opened.'); } $row_num = 1; $output_info = []; while (($fields = fgetcsv($fh)) !== false) { // ignore first row if ($row_num == 1) { $row_num++; continue; } // process row $output_info[] = $this->processRow($fields, $promo_tag); $row_num++; } // write to output file $this->outputCustomerInfo($output_file, $output_info); fclose($fh); return 0; } protected function setOutputInfo($fields, $status, $reason, $cust_id) { $timestamp = trim($fields[self::F_TIMESTAMP]); $mname = trim($fields[self::F_MIDDLE_NAME]); $birthdate = trim($fields[self::F_BIRTHDATE]); $address = trim($fields[self::F_ADDRESS]); $city = trim($fields[self::F_CITY]); $region = trim($fields[self::F_REGION]); $car_club = trim($fields[self::F_CAR_CLUB]); $position = trim($fields[self::F_POSITION]); $member_number = trim($fields[self::F_MEMBER_NUM]); $vehicle = trim($fields[self::F_VEHICLE]); $vehicle_excel = trim($fields[self::F_VEHICLE_EXCEL]); $batt_size = trim($fields[self::F_BATT_SIZE]); $replace_sked = trim($fields[self::F_REPLACE_SKED]); $dealer_visit = trim($fields[self::F_DEALER_VISIT]); $bwi_location = trim($fields[self::F_BWI_LOCATION]); $sap_code = trim($fields[self::F_SAP_CODE]); $sku = trim($fields[self::F_SKU]); $qty = trim($fields[self::F_QTY]); $fname = trim($fields[self::F_FIRST_NAME]); $lname = trim($fields[self::F_LAST_NAME]); $dpa = trim($fields[self::F_DPA]); $contact_number = trim($fields[SELF::F_CONTACT_NUM]); return [ $timestamp, $dpa, $fname, $mname, $lname, $birthdate, $address, $city, $region, $car_club, $position, $member_number, $vehicle, $vehicle_excel, $batt_size, $replace_sked, $dealer_visit, $contact_number, $bwi_location, $sap_code, $sku, $qty, $status, $reason, $cust_id ]; } protected function createNewCustomer($fields, $contact_numbers, $cust_tag, $promo_tag) { $fname = trim($fields[self::F_FIRST_NAME]); $lname = trim($fields[self::F_LAST_NAME]); $dpa = trim($fields[self::F_DPA]); if (count($contact_numbers) > 0) $clean_number = $contact_numbers[0]; else $clean_number = ''; // check dpa $is_dpa = false; if (strtoupper($dpa) == 'YES') $is_dpa = true; // create new customer $new_cust = new Customer(); $new_cust->setFirstName($fname) ->setLastName($lname) ->setPhoneMobile($clean_number) ->setDpaConsent($is_dpa) ->setCreateSource('car_club_file') ->addCustomerTag($cust_tag) ->addCustomerTag($promo_tag); $this->em->persist($new_cust); $this->em->flush(); return $new_cust; } protected function processRow($fields, $promo_tag) { $contact_number = trim($fields[SELF::F_CONTACT_NUM]); $car_club = trim($fields[self::F_CAR_CLUB]); // clean up contact number $valid_contact_numbers = $this->getValidContactNumbers($contact_number); // NOTE: commenting this out because we want to add customers without mobile number /* // QUESTION: do we need this? // QUESTION: why are we not adding those without contact numbers? Add customer, leave contact number blank was what was agreed, right? if (count($valid_contact_numbers) <= 0) { // add info to output array return $this->setOutputInfo($fields, 'NOT CREATED', 'Missing contact number', 0); } */ // check customer tag $cust_tag = $this->findCustomerTag($car_club); $cust_id = ''; // give me first customer that matches any of the numbers $customer = $this->findCustomerByNumbers($valid_contact_numbers); // if no customer found, create one if ($customer == null) { error_log('Creating customer...'); error_log('cust tag id ' . $cust_tag->getID()); // create new customer $new_cust = $this->createNewCustomer($fields, $valid_contact_numbers, $cust_tag, $promo_tag); // get customer id of new customer here $cust_id = $new_cust->getID(); // add info to output array return $this->setOutputInfo($fields, 'CREATED', '', $cust_id); } error_log('Updating customer...'); // add customer tag to existing customer $cust_id = $customer->getID(); // need to check if customer tag already exists for customer $tag_exists = $customer->getCustomerTag($cust_tag->getID()); if ($tag_exists == null) { $customer->addCustomerTag($cust_tag) ->addCustomerTag($promo_tag); $this->em->flush(); // add info to output array return $this->setOutputInfo($fields, 'UPDATED', '', $cust_id); } return $this->setOutputInfo($fields, 'NOT CREATED/UPDATED', 'Customer and tag already exist', $cust_id); } protected function findCustomerByNumbers($numbers) { error_log(print_r($numbers, true)); $customer = $this->em->getRepository(Customer::class)->findOneBy(['phone_mobile' => $numbers]); return $customer; } protected function outputCustomerInfo($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, [ 'Timestamp', 'I have read and understood and agreed to the confidentiality of this form request', 'First Name', 'Middle Name', 'Last Name', 'Birth date', 'Address', 'City', 'Region', 'Car Club/Organization', 'Position in the organization', 'Official Member Number (type NA if not applicable)', 'Vehicles you own? Year - Make -Model - Plate/Conduction number (ex 2017 NISSAN NAVARA ABC 1234) you can indicate all your vehicles', 'If your were given a chance to EXperience the New Motolite Excel, Choose 1 vehicle and it\'s plate/conduction number', 'What is the Battery size of the vehicle you with to EXperience the New Motolite Excel', 'Given a specific date, when can you schedule your replacement?', 'Will you be able to visit our dealer that we will assign nearest to you?', 'Contact Number', 'BWI LOCATION', 'SAP CODE', 'SKU', 'QTY', 'Status', 'Reason', 'Customer ID', ]); foreach($entries as $row) { fputcsv($fh, $row); } fclose($fh); } protected function loadCustomerTags() { $this->cust_tag_hash = []; $cust_tags = $this->em->getRepository(CustomerTag::class)->findAll(); foreach ($cust_tags as $cust_tag) { $tag_id = $cust_tag->getID(); $this->cust_tag_hash[$tag_id] = $cust_tag; } } protected function normalizeClubName($name) { // uppercase the name $clean_name = trim(strtoupper($name)); // remove apostrophes $clean_name = str_replace("'", '', $clean_name); // replace all special characters except ampersand (&) with whitespace $clean_name = trim(preg_replace('/[^A-Za-z0-9&]/', ' ', $clean_name)); // replace spaces with underscore (_) $clean_name = preg_replace('/\s+/', '_', $clean_name); // prepend 'TAG_' $tag_name = 'TAG_' . $clean_name; return $tag_name; } protected function findCustomerTag($car_club) { // find the customer tag for club $tag_name = $this->normalizeClubName($car_club); error_log($tag_name); if (isset($this->cust_tag_hash[$tag_name])) return $this->cust_tag_hash[$tag_name]; error_log('customer tag not in hash...'); // create the customer tag $new_cust_tag = new CustomerTag(); $tag_details = json_decode('{"type":"car club"}', true); $new_cust_tag->setID($tag_name) ->setName(strtoupper($car_club)) ->setTagDetails($tag_details); $this->em->persist($new_cust_tag); // need to flush before adding to hash $this->em->flush(); $this->cust_tag_hash[$tag_name] = $new_cust_tag; return $new_cust_tag; } protected function normalizeContactNumber($c_num) { // remove any non digit character from string $clean_number = preg_replace('~\D~', '', $c_num); error_log('cleaned ' . $clean_number); // does it fit our 09XXXXXXXXX pattern? if (preg_match('/^09[0-9]{9}$/', $clean_number)) { // remove first '0' $clean_number = substr($clean_number, 1); error_log("CONVERTED TO $clean_number"); return $clean_number; } // does it fit our 63XXXXXXXXXX pattern? else if (preg_match('/^63[0-9]{10}$/', $clean_number)) { // remove the 63 $clean_number = substr($clean_number, 2); error_log("CONVERTED TO $clean_number"); return $clean_number; } // does it fit our 9XXXXXXXXX pattern? else if (preg_match('/^9[0-9]{9}$/', $clean_number)) { error_log("already cleaned $clean_number"); return $clean_number; } return ""; } }