From 22d4201097af0295ceb6c30705899c49d4d679a5 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 7 Sep 2023 16:29:27 +0800 Subject: [PATCH 001/119] Add command to archive job order data. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 344 ++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 src/Command/GetJobOrderArchiveDataCommand.php diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php new file mode 100644 index 00000000..ec5266e6 --- /dev/null +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -0,0 +1,344 @@ +em = $em; + $this->project_dir = $kernel->getProjectDir(); + $this->filesystem = $filesystem; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('joborder:archive') + ->setDescription('Get job order data to archive.') + ->setHelp('Get job order data to archive.') + ->addArgument('cutoff_date', InputArgument::REQUIRED, 'cutoff_date') + ->addArgument('period', InputArgument::REQUIRED, 'period'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // get table to back up + $period = $input->getArgument('period'); + $cutoff_date = $input->getArgument('cutoff_date'); + + $em = $this->em; + + $db = $em->getConnection(); + + // create the archive table + $archive_table_name = $this->createArchiveTable($cutoff_date, $period); + + // sql query to retrieve the rows or entries for backup + $query_sql = 'SELECT id, + customer_id, + cvehicle_id, + rider_id, + date_create, + date_schedule, + date_fulfill, + coordinates, + flag_advance, + service_type, + source, + date_cancel, + status, + delivery_instructions, + delivery_address, + create_user_id, + assign_user_id, + date_assign, + warranty_class, + process_user_id, + hub_id, + cancel_reason, + ref_jo_id, + tier1_notes, + tier2_notes, + mode_of_payment, + or_name, + landmark, + promo_detail, + or_num, + trade_in_type, + flag_rider_rating, + flag_coolant, + facilitated_hub_id, + facilitated_type, + coord_long, + coord_lat, + priority, + meta, + status_autoassign, + first_name, + last_name, + plate_number, + phone_mobile, + no_trade_in_reason, + will_wait, + reason_not_waiting, + not_waiting_notes, + delivery_status, + emergency_type_id, + ownership_type_id, + cust_location_id, + source_of_awareness, + remarks, + initial_concern, + initial_concern_notes, + gender, + caller_classification, + inventory_count + FROM job_order + WHERE DATE_CREATE < DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR)'; + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); + + $results = $query_stmt->executeQuery(); + + $backup_data = []; + + while ($row = $results->fetchAssociative()) + { + $backup_data[] = $this->createBackupData($row); + } + + // create the load file for the backup data + $this->createLoadDataFileForBackupData($backup_data); + + return 0; + } + + protected function createArchiveTable($str_date, $period) + { + // form the archive table name _archive_ + $modifier = '-' . $period. 'year'; + + // convert the date string into DateTime + $date = new DateTime($str_date); + $year = $date->modify($modifier)->format('Y'); + + $archive_table_name = 'job_order_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `customer_id` int(11) DEFAULT NULL, + `cvehicle_id` int(11) DEFAULT NULL, + `rider_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_schedule` datetime NOT NULL, + `date_fulfill` datetime DEFAULT NULL, + `coordinates` point NOT NULL COMMENT \'(DC2Type:point)\', + `flag_advance` tinyint(1) NOT NULL, + `service_type` varchar(25) COLLATE utf8_unicode_ci NOT NULL, + `source` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `date_cancel` datetime DEFAULT NULL, + `status` varchar(15) COLLATE utf8_unicode_ci NOT NULL, + `delivery_instructions` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `delivery_address` longtext COLLATE utf8_unicode_ci NOT NULL, + `create_user_id` int(11) DEFAULT NULL, + `assign_user_id` int(11) DEFAULT NULL, + `date_assign` datetime DEFAULT NULL, + `warranty_class` varchar(25) COLLATE utf8_unicode_ci NOT NULL, + `process_user_id` int(11) DEFAULT NULL, + `hub_id` int(11) DEFAULT NULL, + `cancel_reason` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL, + `ref_jo_id` int(11) DEFAULT NULL, + `tier1_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `tier2_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `mode_of_payment` varchar(50) COLLATE utf8_unicode_ci NOT NULL, + `or_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `landmark` longtext COLLATE utf8_unicode_ci NOT NULL, + `promo_detail` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `or_num` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `trade_in_type` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL, + `flag_rider_rating` tinyint(1) DEFAULT NULL, + `flag_coolant` tinyint(1) NOT NULL, + `facilitated_hub_id` int(11) DEFAULT NULL, + `facilitated_type` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL, + `coord_long` decimal(11,8) NOT NULL, + `coord_lat` decimal(11,8) NOT NULL, + `priority` int(11) NOT NULL DEFAULT 0, + `meta` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + `status_autoassign` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL, + `first_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `last_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `plate_number` varchar(100) COLLATE utf8_unicode_ci NOT NULL, + `phone_mobile` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `no_trade_in_reason` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `will_wait` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `reason_not_waiting` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `not_waiting_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `delivery_status` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL, + `emergency_type_id` int(11) DEFAULT NULL, + `ownership_type_id` int(11) DEFAULT NULL, + `cust_location_id` int(11) DEFAULT NULL, + `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `initial_concern` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `initial_concern_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `gender` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `caller_classification` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + + return $archive_table_name; + } + + protected function createBackupData($row) + { + // get job order data + // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, + // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, + // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, + // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + + $id = $row['id']; + $cust_id = $row['customer_id']; + $cv_id = $row['cvehicle_id']; + + $rider_id = '\N'; + if ($row['rider_id'] != NULL) + $rider_id = $row]'rider_id']; + + $date_create = $row['date_create']; + $date_schedule = $row['date_schedule']; + + $date_fulfill = '\N'; + if ($row['date_fulfill'] != NULL) + $date_fulfill = $row['date_schedule']; + + $coordinates = $row['coordinates']; + $flag_advance = $row['flag_advance']; + $service_type = $row['service_type']; + $source = $row['source']; + + $date_cancel = '\N'; + if ($row['date_cancel'] != NULL) + $date_cancel = $row['date_cancel']; + + $status = $row['status']; + $del_instructions = $row['delivery_instructions']; + $del_address = $row['delivery_address']; + + $create_user_id = '\N'; + if ($row['create_user_id'] != NULL) + $create_user_id = $row['create_user_id']; + + $assign_user_id = '\N'; + if ($row['assign_user_id'] != NULL) + $assign_user_id = $row['assign_user_id']; + + $date_assign = '\N'; + if ($row['date_assign'] != NULL) + $date_assign = $row['date_assign']; + + $warr_class = $row['warranty_class']; + + $process_user_id = '\N'; + if ($row['process_user_id'] != NULL) + $process_user_id = $row['process_user_id']; + + $hub_id = '\N'; + if ($row['hub_id'] != NULL) + $hub_id = $row['hub_id']; + + $cancel_reason = '\N'; + if ($row['cancel_reason'] != NULL) + $cancel_reason = $row['cancel_reason']; + + $ref_jo_id = '\N'; + if ($row['ref_jo_id'] != NULL) + $ref_jo_id = $row['ref_jo_id']; + + $tier1_notes = $row['tier1_notes']; + $tier2_notes = $row['tier2_notes']; + $mode_of_payment = $row['mode_of_payment']; + $or_name = $row['or_name']; + $landmark = $row['landmark']; + $promo_details = $row['promo_detail']; + + $or_num = '\N'; + if ($row['or_num'] != NULL) + $or_num = $row['or_num']; + + $trade_in_type = '\N'; + if ($row['trade_in_type'] != NULL) + $trade_in_type = $row['trade_in_type']; + + $flag_rider_rating = '\N'; + if ($row['flag_rider_rating'] != NULL) + $flag_rider_rating = $row['flag_rider_rating']; + + $flag_coolant = $row['flag_coolant']; + + $fac_hub_id = '\N'; + if ($row['facilitated_hub_id'] != NULL) + $fac_hub_id = $row['facilitated_hub_id']; + + $fac_type = '\N'; + if ($row['facilitated_type'] != NULL) + $fac_type = $row['facilitated_type']; + + $coord_long = $row['coord_long']; + $coord_lat = $row['coord_lat']; + $priority = $row['priority']; + $meta = $row['meta']; + $status_autoassign = $row['status_autoassign']; + $first_name = $row['first_name']; + $last_name = $row['last_name']; + $plate_number = $row['plate_number']; + $phone_mobile = $row['phone_mobile']; + $no_trade_in_reason = $row[' no_trade_in_reason']; + $will_wait = $row['will_wait']; + $reason_not_waiting = $row['reason_not_waiting']; + $not_waiting_notes = $row['not_waiting_notes']; + $del_status = $row['delivery_status']; + $emergency_type_id = $row['emergency_type_id']; + $owner_type_id = $row['ownership_type_id']; + $cust_location_id = $row['cust_location_id']; + $source_of_awareness = $row['source_of_awareness']; + $remarks = $row['remarks']; + $initial_concern = $row['initial_concern']; + $initial_concern_notes = $row['initial_concern_notes']; + $gender = $row['gender']; + $caller_class = $row['caller_classification']; + $inv_count = $row['inventory_count']; + + // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, + // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, + // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, + // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + } +} -- 2.43.5 From c318c471ff5c59d87ea285009f2405a1ab313b8d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 7 Sep 2023 18:01:13 +0800 Subject: [PATCH 002/119] Add checking for nulls when creating the data for backup. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 89 ++++++++++++++----- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index ec5266e6..704c509f 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -311,34 +311,83 @@ class GetJobOrderArchiveDataCommand extends Command $fac_type = $row['facilitated_type']; $coord_long = $row['coord_long']; - $coord_lat = $row['coord_lat']; $priority = $row['priority']; $meta = $row['meta']; - $status_autoassign = $row['status_autoassign']; + + $status_autoassign = '\N'; + if ($row['status_autoassign'] != NULL) + $status_autoassign = $row['status_autoassign']; + $first_name = $row['first_name']; $last_name = $row['last_name']; $plate_number = $row['plate_number']; $phone_mobile = $row['phone_mobile']; - $no_trade_in_reason = $row[' no_trade_in_reason']; + + $no_trade_in_reason = '\N'; + if ($row['no_trade_in_reason'] != NULL) + $no_trade_in_reason = $row[' no_trade_in_reason']; + $will_wait = $row['will_wait']; - $reason_not_waiting = $row['reason_not_waiting']; - $not_waiting_notes = $row['not_waiting_notes']; - $del_status = $row['delivery_status']; - $emergency_type_id = $row['emergency_type_id']; - $owner_type_id = $row['ownership_type_id']; - $cust_location_id = $row['cust_location_id']; - $source_of_awareness = $row['source_of_awareness']; - $remarks = $row['remarks']; - $initial_concern = $row['initial_concern']; - $initial_concern_notes = $row['initial_concern_notes']; - $gender = $row['gender']; - $caller_class = $row['caller_classification']; + + $reason_not_waiting = '\N'; + if ($row['reason_not_waiting'] != NULL) + $reason_not_waiting = $row['reason_not_waiting']; + + $not_waiting_notes = '\N'; + if ($row['not_waiting_notes'] != NULL) + $not_waiting_notes = $row['not_waiting_notes']; + + $del_status = '\N'; + if ($row['delivery_status'] != NULL) + $del_status = $row['delivery_status']; + + $emergency_type_id = '\N'; + if ($row['emergency_type_id'] != NULL) + $emergency_type_id = $row['emergency_type_id']; + + $owner_type_id = '\N'; + if ($row['ownership_type_id'] != NULL) + $owner_type_id = $row['ownership_type_id']; + + $cust_location_id = '\N'; + if ($row['cust_location_id'] != NULL) + $cust_location_id = $row['cust_location_id']; + + $source_of_awareness = '\N'; + if ($row['source_of_awareness'] != NULL) + $source_of_awareness = $row['source_of_awareness']; + + $remarks = '\N'; + if ($row['remarks'] != NULL) + $remarks = $row['remarks']; + + $initial_concern = '\N'; + if ($row['initial_concern'] != NULL) + $initial_concern = $row['initial_concern']; + + $initial_concern_notes = '\N'; + if ($row['initial_concern_notes'] != NULL) + $initial_concern_notes = $row['initial_concern_notes']; + + $gender = '\N'; + if ($row['gender'] != NULL) + $gender = $row['gender']; + + $caller_class = '\N'; + if ($row['caller_classification'] != NULL) + $caller_class = $row['caller_classification']; + $inv_count = $row['inventory_count']; - // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, - // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, - // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, - // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, - // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + // create the array for the file + $data = [ + $id, + $cust_id, + // TODO: finish writing to array + ]; + + return $data; } + + // TODO: write the load data file function } -- 2.43.5 From 4c0460bdb5b5a97fa8d3eee82b4306eb70ef7104 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 8 Sep 2023 15:27:19 +0800 Subject: [PATCH 003/119] Add loading of data into database. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 115 +++++++++++++++++- 1 file changed, 110 insertions(+), 5 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 704c509f..47c3e174 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -127,7 +127,7 @@ class GetJobOrderArchiveDataCommand extends Command } // create the load file for the backup data - $this->createLoadDataFileForBackupData($backup_data); + $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); return 0; } @@ -229,7 +229,7 @@ class GetJobOrderArchiveDataCommand extends Command $rider_id = '\N'; if ($row['rider_id'] != NULL) - $rider_id = $row]'rider_id']; + $rider_id = $row['rider_id']; $date_create = $row['date_create']; $date_schedule = $row['date_schedule']; @@ -311,6 +311,7 @@ class GetJobOrderArchiveDataCommand extends Command $fac_type = $row['facilitated_type']; $coord_long = $row['coord_long']; + $coord_lat = $row['coord_lat']; $priority = $row['priority']; $meta = $row['meta']; @@ -325,7 +326,7 @@ class GetJobOrderArchiveDataCommand extends Command $no_trade_in_reason = '\N'; if ($row['no_trade_in_reason'] != NULL) - $no_trade_in_reason = $row[' no_trade_in_reason']; + $no_trade_in_reason = $row['no_trade_in_reason']; $will_wait = $row['will_wait']; @@ -383,11 +384,115 @@ class GetJobOrderArchiveDataCommand extends Command $data = [ $id, $cust_id, - // TODO: finish writing to array + $cv_id, + $rider_id, + $date_create, + $date_schedule, + $date_fulfill, + $coordinates, + $flag_advance, + $service_type, + $source, + $date_cancel, + $status, + $del_instructions, + $del_address, + $create_user_id, + $assign_user_id, + $date_assign, + $warr_class, + $process_user_id, + $hub_id, + $cancel_reason, + $ref_jo_id, + $tier1_notes, + $tier2_notes, + $mode_of_payment, + $or_name, + $landmark, + $promo_details, + $or_num, + $trade_in_type, + $flag_rider_rating, + $flag_coolant, + $fac_hub_id, + $fac_type, + $coord_long, + $coord_lat, + $priority, + $meta, + $status_autoassign, + $first_name, + $last_name, + $plate_number, + $phone_mobile, + $no_trade_in_reason, + $will_wait, + $reason_not_waiting, + $not_waiting_notes, + $del_status, + $emergency_type_id, + $owner_type_id, + $cust_location_id, + $source_of_awareness, + $remarks, + $initial_concern, + $initial_concern_notes, + $gender, + $caller_class, + $inv_count ]; return $data; } - // TODO: write the load data file function + protected function createLoadDataFileForBackupData($backup_data, $table_name) + { + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/jo_archive.tab'; + error_log('opening file for jo archive - ' . $file); + + $fp = fopen($file, 'w'); + if ($fp === false) + { + error_log('could not open file for load data infile - ' . $file); + } + else + { + foreach ($backup_data as $key => $data) + { + $line = implode('|', $data) . "\r\n"; + fwrite($fp, $line); + } + } + + fclose($fp); + + $conn = $this->em->getConnection(); + $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count)'); + + $result = $stmt->execute(); + + if (!$result) + error_log('Failed loading data.'); + + // TODO: delete file? + } + } -- 2.43.5 From 4eca65cc59bbd9ac4f7075cf83b96d7a70a42568 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 8 Sep 2023 17:24:43 +0800 Subject: [PATCH 004/119] Add saving of data to archive table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 47c3e174..7e9f969e 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -126,6 +126,8 @@ class GetJobOrderArchiveDataCommand extends Command $backup_data[] = $this->createBackupData($row); } + error_log('count ' . count($backup_data)); + // create the load file for the backup data $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); @@ -238,7 +240,6 @@ class GetJobOrderArchiveDataCommand extends Command if ($row['date_fulfill'] != NULL) $date_fulfill = $row['date_schedule']; - $coordinates = $row['coordinates']; $flag_advance = $row['flag_advance']; $service_type = $row['service_type']; $source = $row['source']; @@ -248,6 +249,8 @@ class GetJobOrderArchiveDataCommand extends Command $date_cancel = $row['date_cancel']; $status = $row['status']; + + // TODO: might need to clean delivery address and delivery instructions $del_instructions = $row['delivery_instructions']; $del_address = $row['delivery_address']; @@ -312,6 +315,10 @@ class GetJobOrderArchiveDataCommand extends Command $coord_long = $row['coord_long']; $coord_lat = $row['coord_lat']; + + // coordinates needs special handling since it's a spatial column + $coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; + $priority = $row['priority']; $meta = $row['meta']; @@ -471,11 +478,11 @@ class GetJobOrderArchiveDataCommand extends Command fclose($fp); $conn = $this->em->getConnection(); - $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' + $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' FIELDS TERMINATED BY \'|\' LINES TERMINATED BY \'\\r\\n\' (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, coordinates, flag_advance, service_type, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, source, date_cancel, status, delivery_instructions, delivery_address, create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, @@ -485,7 +492,9 @@ class GetJobOrderArchiveDataCommand extends Command first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count)'); + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@coordinates)' + ); $result = $stmt->execute(); -- 2.43.5 From 7e3c392c03b6c8b0e464dacc3a823cf081bbacad Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 11 Sep 2023 15:10:08 +0800 Subject: [PATCH 005/119] Fix issues found when saving archive data. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 7e9f969e..4a42849f 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -44,6 +44,8 @@ class GetJobOrderArchiveDataCommand extends Command $period = $input->getArgument('period'); $cutoff_date = $input->getArgument('cutoff_date'); + $cutoff_date_time = $cutoff_date . ' 23:59:59'; + $em = $this->em; $db = $em->getConnection(); @@ -112,7 +114,8 @@ class GetJobOrderArchiveDataCommand extends Command caller_classification, inventory_count FROM job_order - WHERE DATE_CREATE < DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR)'; + WHERE DATE_CREATE <= DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR) + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); @@ -250,9 +253,8 @@ class GetJobOrderArchiveDataCommand extends Command $status = $row['status']; - // TODO: might need to clean delivery address and delivery instructions - $del_instructions = $row['delivery_instructions']; - $del_address = $row['delivery_address']; + $del_instructions = $this->cleanData($row['delivery_instructions']); + $del_address = $this->cleanData($row['delivery_address']); $create_user_id = '\N'; if ($row['create_user_id'] != NULL) @@ -284,11 +286,13 @@ class GetJobOrderArchiveDataCommand extends Command if ($row['ref_jo_id'] != NULL) $ref_jo_id = $row['ref_jo_id']; - $tier1_notes = $row['tier1_notes']; - $tier2_notes = $row['tier2_notes']; + $tier1_notes = $this->cleanData($row['tier1_notes']); + $tier2_notes = $this->cleanData($row['tier2_notes']); + $mode_of_payment = $row['mode_of_payment']; $or_name = $row['or_name']; - $landmark = $row['landmark']; + + $landmark = $this->cleanData($row['landmark']); $promo_details = $row['promo_detail']; $or_num = '\N'; @@ -367,7 +371,7 @@ class GetJobOrderArchiveDataCommand extends Command $remarks = '\N'; if ($row['remarks'] != NULL) - $remarks = $row['remarks']; + $remarks = $this->cleanData(row['remarks']); $initial_concern = '\N'; if ($row['initial_concern'] != NULL) @@ -504,4 +508,15 @@ class GetJobOrderArchiveDataCommand extends Command // TODO: delete file? } + protected function cleanData($text) + { + $clean_text = ''; + + // replace the new lines with whitespace + $clean_text = preg_replace("/[\n\r]/", ' ', $text); + + return $clean_text; + + } + } -- 2.43.5 From 986181c7807585e8f67b0c8195fcc76ecbb57599 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 12 Sep 2023 11:35:31 +0800 Subject: [PATCH 006/119] Modify code according to code review. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 229 ++++-------------- 1 file changed, 44 insertions(+), 185 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 4a42849f..2e8e6a41 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -34,91 +34,32 @@ class GetJobOrderArchiveDataCommand extends Command $this->setName('joborder:archive') ->setDescription('Get job order data to archive.') ->setHelp('Get job order data to archive.') - ->addArgument('cutoff_date', InputArgument::REQUIRED, 'cutoff_date') - ->addArgument('period', InputArgument::REQUIRED, 'period'); + ->addArgument('year', InputArgument::REQUIRED, 'year'); } protected function execute(InputInterface $input, OutputInterface $output) { // get table to back up - $period = $input->getArgument('period'); - $cutoff_date = $input->getArgument('cutoff_date'); - - $cutoff_date_time = $cutoff_date . ' 23:59:59'; + $year = $input->getArgument('year'); $em = $this->em; $db = $em->getConnection(); // create the archive table - $archive_table_name = $this->createArchiveTable($cutoff_date, $period); + $archive_table_name = $this->createArchiveTable($year); + // TODO: move the creation of the query_sql to a function or + // set this as a preset or a variable or something and load specific query + // according to what table is to be archived. // sql query to retrieve the rows or entries for backup - $query_sql = 'SELECT id, - customer_id, - cvehicle_id, - rider_id, - date_create, - date_schedule, - date_fulfill, - coordinates, - flag_advance, - service_type, - source, - date_cancel, - status, - delivery_instructions, - delivery_address, - create_user_id, - assign_user_id, - date_assign, - warranty_class, - process_user_id, - hub_id, - cancel_reason, - ref_jo_id, - tier1_notes, - tier2_notes, - mode_of_payment, - or_name, - landmark, - promo_detail, - or_num, - trade_in_type, - flag_rider_rating, - flag_coolant, - facilitated_hub_id, - facilitated_type, - coord_long, - coord_lat, - priority, - meta, - status_autoassign, - first_name, - last_name, - plate_number, - phone_mobile, - no_trade_in_reason, - will_wait, - reason_not_waiting, - not_waiting_notes, - delivery_status, - emergency_type_id, - ownership_type_id, - cust_location_id, - source_of_awareness, - remarks, - initial_concern, - initial_concern_notes, - gender, - caller_classification, - inventory_count + $query_sql = 'SELECT * FROM job_order - WHERE DATE_CREATE <= DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR) + WHERE YEAR(date_create) = :year ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); + $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $results = $query_stmt->executeQuery(); @@ -137,20 +78,15 @@ class GetJobOrderArchiveDataCommand extends Command return 0; } - protected function createArchiveTable($str_date, $period) + protected function createArchiveTable($year) { // form the archive table name _archive_ - $modifier = '-' . $period. 'year'; - - // convert the date string into DateTime - $date = new DateTime($str_date); - $year = $date->modify($modifier)->format('Y'); - $archive_table_name = 'job_order_archive_' . $year; // create the table if it doesn't exist $db = $this->em->getConnection(); + // TODO: What if table already exists? $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( `id` int(11) NOT NULL, `customer_id` int(11) DEFAULT NULL, @@ -223,7 +159,7 @@ class GetJobOrderArchiveDataCommand extends Command { // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, - // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // assign_user_id, process_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id @@ -232,59 +168,34 @@ class GetJobOrderArchiveDataCommand extends Command $cust_id = $row['customer_id']; $cv_id = $row['cvehicle_id']; - $rider_id = '\N'; - if ($row['rider_id'] != NULL) - $rider_id = $row['rider_id']; + $rider_id = $row['rider_id'] ?? '\N'; $date_create = $row['date_create']; $date_schedule = $row['date_schedule']; - $date_fulfill = '\N'; - if ($row['date_fulfill'] != NULL) - $date_fulfill = $row['date_schedule']; + $date_fulfill = $row['date_fulfill'] ?? '\N'; $flag_advance = $row['flag_advance']; $service_type = $row['service_type']; $source = $row['source']; - $date_cancel = '\N'; - if ($row['date_cancel'] != NULL) - $date_cancel = $row['date_cancel']; + $date_cancel = $row['date_cancel'] ?? '\N'; $status = $row['status']; $del_instructions = $this->cleanData($row['delivery_instructions']); $del_address = $this->cleanData($row['delivery_address']); - $create_user_id = '\N'; - if ($row['create_user_id'] != NULL) - $create_user_id = $row['create_user_id']; - - $assign_user_id = '\N'; - if ($row['assign_user_id'] != NULL) - $assign_user_id = $row['assign_user_id']; - - $date_assign = '\N'; - if ($row['date_assign'] != NULL) - $date_assign = $row['date_assign']; + $create_user_id = $row['create_user_id'] ?? '\N'; + $assign_user_id = $row['assign_user_id'] ?? '\N'; + $date_assign = $row['date_assign'] ?? '\N'; $warr_class = $row['warranty_class']; - $process_user_id = '\N'; - if ($row['process_user_id'] != NULL) - $process_user_id = $row['process_user_id']; - - $hub_id = '\N'; - if ($row['hub_id'] != NULL) - $hub_id = $row['hub_id']; - - $cancel_reason = '\N'; - if ($row['cancel_reason'] != NULL) - $cancel_reason = $row['cancel_reason']; - - $ref_jo_id = '\N'; - if ($row['ref_jo_id'] != NULL) - $ref_jo_id = $row['ref_jo_id']; + $process_user_id = $row['process_user_id'] ?? '\N'; + $hub_id = $row['hub_id'] ?? '\N'; + $cancel_reason = $row['cancel_reason'] ?? '\N'; + $ref_jo_id = $row['ref_jo_id'] ?? '\N'; $tier1_notes = $this->cleanData($row['tier1_notes']); $tier2_notes = $this->cleanData($row['tier2_notes']); @@ -295,99 +206,47 @@ class GetJobOrderArchiveDataCommand extends Command $landmark = $this->cleanData($row['landmark']); $promo_details = $row['promo_detail']; - $or_num = '\N'; - if ($row['or_num'] != NULL) - $or_num = $row['or_num']; - - $trade_in_type = '\N'; - if ($row['trade_in_type'] != NULL) - $trade_in_type = $row['trade_in_type']; - - $flag_rider_rating = '\N'; - if ($row['flag_rider_rating'] != NULL) - $flag_rider_rating = $row['flag_rider_rating']; + $or_num = $row['or_num'] ?? '\N'; + $trade_in_type = $row['trade_in_type'] ?? '\N'; + $flag_rider_rating = $row['flag_rider_rating'] ?? '\N'; $flag_coolant = $row['flag_coolant']; - $fac_hub_id = '\N'; - if ($row['facilitated_hub_id'] != NULL) - $fac_hub_id = $row['facilitated_hub_id']; - - $fac_type = '\N'; - if ($row['facilitated_type'] != NULL) - $fac_type = $row['facilitated_type']; + $fac_hub_id = $row['facilitated_hub_id'] ?? '\N'; + $fac_type = $row['facilitated_type'] ?? '\N'; $coord_long = $row['coord_long']; $coord_lat = $row['coord_lat']; // coordinates needs special handling since it's a spatial column - $coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; + $geo_coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; $priority = $row['priority']; $meta = $row['meta']; - $status_autoassign = '\N'; - if ($row['status_autoassign'] != NULL) - $status_autoassign = $row['status_autoassign']; + $status_autoassign = $row['status_autoassign'] ?? '\N'; $first_name = $row['first_name']; $last_name = $row['last_name']; $plate_number = $row['plate_number']; $phone_mobile = $row['phone_mobile']; - $no_trade_in_reason = '\N'; - if ($row['no_trade_in_reason'] != NULL) - $no_trade_in_reason = $row['no_trade_in_reason']; + $no_trade_in_reason = $row['no_trade_in_reason'] ?? '\N'; $will_wait = $row['will_wait']; - $reason_not_waiting = '\N'; - if ($row['reason_not_waiting'] != NULL) - $reason_not_waiting = $row['reason_not_waiting']; - - $not_waiting_notes = '\N'; - if ($row['not_waiting_notes'] != NULL) - $not_waiting_notes = $row['not_waiting_notes']; - - $del_status = '\N'; - if ($row['delivery_status'] != NULL) - $del_status = $row['delivery_status']; - - $emergency_type_id = '\N'; - if ($row['emergency_type_id'] != NULL) - $emergency_type_id = $row['emergency_type_id']; - - $owner_type_id = '\N'; - if ($row['ownership_type_id'] != NULL) - $owner_type_id = $row['ownership_type_id']; - - $cust_location_id = '\N'; - if ($row['cust_location_id'] != NULL) - $cust_location_id = $row['cust_location_id']; - - $source_of_awareness = '\N'; - if ($row['source_of_awareness'] != NULL) - $source_of_awareness = $row['source_of_awareness']; - - $remarks = '\N'; - if ($row['remarks'] != NULL) - $remarks = $this->cleanData(row['remarks']); - - $initial_concern = '\N'; - if ($row['initial_concern'] != NULL) - $initial_concern = $row['initial_concern']; - - $initial_concern_notes = '\N'; - if ($row['initial_concern_notes'] != NULL) - $initial_concern_notes = $row['initial_concern_notes']; - - $gender = '\N'; - if ($row['gender'] != NULL) - $gender = $row['gender']; - - $caller_class = '\N'; - if ($row['caller_classification'] != NULL) - $caller_class = $row['caller_classification']; + $reason_not_waiting = $row['reason_not_waiting'] ?? '\N'; + $not_waiting_notes = $this->cleanData($row['not_waiting_notes']) ?? '\N'; + $del_status = $row['delivery_status'] ?? '\N'; + $emergency_type_id = $row['emergency_type_id'] ?? '\N'; + $owner_type_id = $row['ownership_type_id'] ?? '\N'; + $cust_location_id = $row['cust_location_id'] ?? '\N'; + $source_of_awareness = $row['source_of_awareness'] ?? '\N'; + $remarks = $this->cleanData($row['remarks']) ?? '\N'; + $initial_concern = $row['initial_concern'] ?? '\N'; + $initial_concern_notes = $this->cleanData($row['initial_concern_notes']) ?? '\N'; + $gender = $row['gender'] ?? '\N'; + $caller_class = $row['caller_classification'] ?? '\N'; $inv_count = $row['inventory_count']; @@ -400,7 +259,7 @@ class GetJobOrderArchiveDataCommand extends Command $date_create, $date_schedule, $date_fulfill, - $coordinates, + $geo_coordinates, $flag_advance, $service_type, $source, @@ -497,7 +356,7 @@ class GetJobOrderArchiveDataCommand extends Command will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@coordinates)' + SET coordinates=ST_GeomFromText(@geo_coordinates)' ); $result = $stmt->execute(); -- 2.43.5 From 35ed917336f3112a3a54153e65e5b3dac69d3cea Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 12 Sep 2023 18:18:37 +0800 Subject: [PATCH 007/119] Refactor the retrieval of job order data to include the other associated tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 154 ++++++++++++++++-- 1 file changed, 136 insertions(+), 18 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 2e8e6a41..e1bcabbd 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -42,43 +42,134 @@ class GetJobOrderArchiveDataCommand extends Command // get table to back up $year = $input->getArgument('year'); - $em = $this->em; + // get the data to archive for the following tables: + // (1) job_order + // (2) invoice (has jo foreign key) + // (3) invoice_item (has invoice foreign key) + // (4) ticket (has jo foreign key) + // (5) jo_rejection (has jo foreign key) + // (6) rider_rating (has jo foreign key) - $db = $em->getConnection(); + $jo_backup_data = $this->getJobOrderData($year); - // create the archive table - $archive_table_name = $this->createArchiveTable($year); + // create the archive tables + // TODO: create the other archive tables + $archive_table_name = $this->createJobOrderArchiveTable($year); + + error_log('count ' . count($jo_backup_data)); + + // create the load file for the backup data + // $this->createLoadDataFileForBackupData($jo_backup_data, $archive_table_name); + + return 0; + } + + protected function getJobOrderData($year) + { + $db = $this->em->getConnection(); - // TODO: move the creation of the query_sql to a function or - // set this as a preset or a variable or something and load specific query - // according to what table is to be archived. - // sql query to retrieve the rows or entries for backup $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $results = $query_stmt->executeQuery(); - $backup_data = []; + $jo_data = []; + $jo_event_data = []; + $invoice_data = []; + $ticket_data = []; + $jo_rejection_data = []; + $rider_rating_data = []; while ($row = $results->fetchAssociative()) { - $backup_data[] = $this->createBackupData($row); + $jo_data[] = $this->createJobOrderArchiveData($row); + + // get the data to archive for jo_event, invoice, ticket, jo_rejection, rider_rating + // using the job order id + $id = $row['id']; + + $jo_event_data = $this->getJORelatedData($id, 'jo_event'); + $ticket_data = $this->getJORelatedData($id, 'ticket'); + $jo_rejection_data = $this->getJORelatedData($id, 'jo_rejection'); + $rider_rating_data = $this->getJORelatedData($id, 'rider_rating'); + + // TODO: separate the invoice and invoice item data } - error_log('count ' . count($backup_data)); + $backup_data = [ + 'jo' => $jo_data, + 'jo_event' => $jo_event_data, + 'invoice' => $invoice_data, + 'ticket' => $ticket_data, + 'jo_rejection' => $jo_rejection_data, + 'rider_rating' => $rider_rating_data, + ]; - // create the load file for the backup data - $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); - - return 0; + return $backup_data; } - protected function createArchiveTable($year) + protected function getJORelatedData($id, $table_name) + { + $db = $this->em->getConnection(); + + if (($table_name == 'jo_event') || + ($table_name == 'invoice') || + ($table_name == 'ticket')) + { + $query_sql = 'SELECT * + FROM ' . $table_name . ' WHERE job_order_id = :id'; + } + else + { + $query_sql = 'SELECT * + FROM ' . $table_name . ' WHERE jo_id = :id'; + } + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $id); + + $results = $query_stmt->executeQuery(); + + $jo_related_data = []; + + while ($row = $results->fetchAssociative()) + { + if ($table_name == 'jo_event') + { + // create the jo event archive data + $jo_related_data = $this->createJOEventArchiveData($row); + } + if ($table_name == 'invoice') + { + // get the data to archive for invoice item + // create the invoice archive data + } + if ($table_name == 'ticket') + { + // create the ticket archive data + } + if ($table_name == 'jo_rejection') + { + // create the jo rejection archive data + } + if ($table_name == 'rider_rating') + { + // create the rider rating archive data + } + } + + return $jo_related_data; + } + + // TODO: make this so you just call one function to create all the tables + // pass the year and the table name + // set the create sql as a constant or something + protected function createJobOrderArchiveTable($year) { // form the archive table name _archive_ $archive_table_name = 'job_order_archive_' . $year; @@ -155,7 +246,7 @@ class GetJobOrderArchiveDataCommand extends Command return $archive_table_name; } - protected function createBackupData($row) + protected function createJobOrderArchiveData($row) { // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, @@ -316,6 +407,33 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } + protected function createJOEventArchiveData($row) + { + // fields that can be null: rider_id, create_user_id + $id = $row['id']; + + $create_user_id = $row['create_user_id'] ?? '\N'; + + $job_order_id = $row['job_order_id']; + $date_create = $row['date_create']; + $date_happen = $row['date_happen']; + $type_id = $row['type_id']; + + $rider_id = $row['rider_id'] ?? '\N'; + + $data = [ + $id, + $create_user_id, + $job_order_id, + $date_create, + $date_happen, + $type_id, + $rider_id, + ]; + + return $data; + } + protected function createLoadDataFileForBackupData($backup_data, $table_name) { // cache directory -- 2.43.5 From d7a2b25e51d4fab4640abda8de249d6f7c82df79 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 13 Sep 2023 17:18:33 +0800 Subject: [PATCH 008/119] Add data files for the related job order tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 190 +++++++++--------- 1 file changed, 96 insertions(+), 94 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e1bcabbd..de602ab5 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -39,7 +39,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { - // get table to back up + // get year to archive $year = $input->getArgument('year'); // get the data to archive for the following tables: @@ -50,70 +50,59 @@ class GetJobOrderArchiveDataCommand extends Command // (5) jo_rejection (has jo foreign key) // (6) rider_rating (has jo foreign key) - $jo_backup_data = $this->getJobOrderData($year); - // create the archive tables // TODO: create the other archive tables $archive_table_name = $this->createJobOrderArchiveTable($year); - - error_log('count ' . count($jo_backup_data)); - - // create the load file for the backup data - // $this->createLoadDataFileForBackupData($jo_backup_data, $archive_table_name); - - return 0; - } - - protected function getJobOrderData($year) - { $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); - $results = $query_stmt->executeQuery(); + $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; - $jo_data = []; - $jo_event_data = []; - $invoice_data = []; - $ticket_data = []; - $jo_rejection_data = []; - $rider_rating_data = []; + $this->getArchiveData($query_stmt, $callback); + + return 0; + } + + protected function getArchiveData($stmt, $callbackJO) + { + $results = $stmt->executeQuery(); + + $related_tables = ['jo_event', 'invoice', 'ticket', 'jo_rejection', 'rider_rating']; + + // delete the related data files + foreach ($related_tables as $tname) + { + $this->deleteDataFiles($tname); + } while ($row = $results->fetchAssociative()) { $jo_data[] = $this->createJobOrderArchiveData($row); - // get the data to archive for jo_event, invoice, ticket, jo_rejection, rider_rating - // using the job order id - $id = $row['id']; + // foreach job order id we got from the first query, we get the JO related + // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating - $jo_event_data = $this->getJORelatedData($id, 'jo_event'); - $ticket_data = $this->getJORelatedData($id, 'ticket'); - $jo_rejection_data = $this->getJORelatedData($id, 'jo_rejection'); - $rider_rating_data = $this->getJORelatedData($id, 'rider_rating'); - - // TODO: separate the invoice and invoice item data + if (is_callable($callbackJO)) + { + foreach ($related_tables as $table_name) + { + call_user_func($callbackJO, $row, $table_name); + } + } } - $backup_data = [ - 'jo' => $jo_data, - 'jo_event' => $jo_event_data, - 'invoice' => $invoice_data, - 'ticket' => $ticket_data, - 'jo_rejection' => $jo_rejection_data, - 'rider_rating' => $rider_rating_data, - ]; + // TODO: load data infile for job order - return $backup_data; } - protected function getJORelatedData($id, $table_name) + protected function getRelatedArchiveData($row, $table_name) { $db = $this->em->getConnection(); @@ -131,39 +120,77 @@ class GetJobOrderArchiveDataCommand extends Command } $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $id); + $query_stmt->bindValue('id', $row['id']); $results = $query_stmt->executeQuery(); - $jo_related_data = []; + $data = []; - while ($row = $results->fetchAssociative()) + while ($q_row = $results->fetchAssociative()) { - if ($table_name == 'jo_event') + $fields = []; + + foreach ($q_row as $key => $value) { - // create the jo event archive data - $jo_related_data = $this->createJOEventArchiveData($row); - } - if ($table_name == 'invoice') - { - // get the data to archive for invoice item - // create the invoice archive data - } - if ($table_name == 'ticket') - { - // create the ticket archive data - } - if ($table_name == 'jo_rejection') - { - // create the jo rejection archive data - } - if ($table_name == 'rider_rating') - { - // create the rider rating archive data + $cleaned_value = $this->cleanData(($value) ?? '\N'); + $fields[] = $cleaned_value; } + + $data[$table_name][$q_row['id']] = $fields; } - return $jo_related_data; + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($data, $table_name); + + if ($file != null) + { + // call load data infile + } + } + + protected function deleteDataFiles($tname) + { + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/' . $tname . '_archive.tab'; + + if (file_exists($file)) + unlink($file); + } + + protected function createDataFileRelatedArchiveData($archive_data, $table_name) + { + if (isset($archive_data[$table_name])) + { + $adata = $archive_data[$table_name]; + + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/' . $table_name . '_archive.tab'; + error_log('opening file for archive - ' . $file); + + $fp = fopen($file, 'a'); + if ($fp === false) + { + error_log('could not open file for load data infile - ' . $file); + } + else + { + foreach ($adata as $key => $data) + { + $line = implode('|', $data) . "\r\n"; + fwrite($fp, $line); + } + } + + fclose($fp); + + return $file; + } + + return null; } // TODO: make this so you just call one function to create all the tables @@ -248,6 +275,8 @@ class GetJobOrderArchiveDataCommand extends Command protected function createJobOrderArchiveData($row) { + // TODO: this could be shrunk further + // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, // assign_user_id, process_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, @@ -407,34 +436,7 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - protected function createJOEventArchiveData($row) - { - // fields that can be null: rider_id, create_user_id - $id = $row['id']; - - $create_user_id = $row['create_user_id'] ?? '\N'; - - $job_order_id = $row['job_order_id']; - $date_create = $row['date_create']; - $date_happen = $row['date_happen']; - $type_id = $row['type_id']; - - $rider_id = $row['rider_id'] ?? '\N'; - - $data = [ - $id, - $create_user_id, - $job_order_id, - $date_create, - $date_happen, - $type_id, - $rider_id, - ]; - - return $data; - } - - protected function createLoadDataFileForBackupData($backup_data, $table_name) + protected function createLoadDataFileForArchiveData($archive_data, $table_name) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; @@ -449,7 +451,7 @@ class GetJobOrderArchiveDataCommand extends Command } else { - foreach ($backup_data as $key => $data) + foreach ($archive_data as $key => $data) { $line = implode('|', $data) . "\r\n"; fwrite($fp, $line); -- 2.43.5 From c1578eee1f9c47f052907ae548dd5ecd0875bd0e Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 15 Sep 2023 18:19:11 +0800 Subject: [PATCH 009/119] Add archiving for invoice item. Add creation of other archive tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 284 ++++++++++++++---- 1 file changed, 229 insertions(+), 55 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index de602ab5..81cd795d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -51,14 +51,19 @@ class GetJobOrderArchiveDataCommand extends Command // (6) rider_rating (has jo foreign key) // create the archive tables - // TODO: create the other archive tables - $archive_table_name = $this->createJobOrderArchiveTable($year); + $this->createJobOrderArchiveTables($year); + $this->createInvoiceArchiveTable($year); + $this->createInvoiceItemArchiveTable($year); + $this->createTicketArchiveTable($year); + $this->createJORejectionArchiveTable($year); + $this->createRiderRatingArchiveTable($year); + $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -82,52 +87,66 @@ class GetJobOrderArchiveDataCommand extends Command $this->deleteDataFiles($tname); } + // special since this is not directly related to JO but to invoice + $this->deleteDataFiles('invoice_item'); + while ($row = $results->fetchAssociative()) { - $jo_data[] = $this->createJobOrderArchiveData($row); + $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); // foreach job order id we got from the first query, we get the JO related // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating if (is_callable($callbackJO)) - { + { foreach ($related_tables as $table_name) { - call_user_func($callbackJO, $row, $table_name); + if (($table_name == 'jo_event') || + ($table_name == 'invoice') || + ($table_name == 'ticket')) + { + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; + } + else + { + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + } + + $db = $this->em->getConnection(); + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $row['id']); + + call_user_func($callbackJO, $row, $query_stmt, $table_name); } } } - // TODO: load data infile for job order - + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($jo_data, 'job_order', 'w'); + + if ($file != null) + { + // call load data infile + } } - protected function getRelatedArchiveData($row, $table_name) + protected function getRelatedArchiveData($row, $query_stmt, $table_name) { - $db = $this->em->getConnection(); - - if (($table_name == 'jo_event') || - ($table_name == 'invoice') || - ($table_name == 'ticket')) - { - $query_sql = 'SELECT * - FROM ' . $table_name . ' WHERE job_order_id = :id'; - } - else - { - $query_sql = 'SELECT * - FROM ' . $table_name . ' WHERE jo_id = :id'; - } - - $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); - $results = $query_stmt->executeQuery(); $data = []; while ($q_row = $results->fetchAssociative()) { + // check if table name is invoice because we need to get + // all invoice items for a specific invoice too + if ($table_name == 'invoice') + { + // get invoice item related data + $this->getInvoiceItemArchiveData($q_row); + } + $fields = []; foreach ($q_row as $key => $value) @@ -140,7 +159,46 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($data, $table_name); + $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + + if ($file != null) + { + // call load data infile + } + } + + protected function getInvoiceItemArchiveData($row) + { + $db = $this->em->getConnection(); + + $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $row['id']); + + $results = $query_stmt->executeQuery(); + + $ii_data = []; + while ($ii_row = $results->fetchAssociative()) + { + $id = $ii_row['id']; + $invoice_id = $ii_row['invoice_id']; + $title = $ii_row['title']; + $qty = $ii_row['qty']; + $price = $ii_row['price']; + $battery_id = $ii_row['battery_id'] ?? '\N'; + + $ii_data['invoice_item'][$id] = [ + $id, + $invoice_id, + $title, + $qty, + $price, + $battery_id + ]; + } + + $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); if ($file != null) { @@ -159,7 +217,7 @@ class GetJobOrderArchiveDataCommand extends Command unlink($file); } - protected function createDataFileRelatedArchiveData($archive_data, $table_name) + protected function createDataFileRelatedArchiveData($archive_data, $table_name, $option) { if (isset($archive_data[$table_name])) { @@ -171,7 +229,7 @@ class GetJobOrderArchiveDataCommand extends Command $file = $cache_dir . '/' . $table_name . '_archive.tab'; error_log('opening file for archive - ' . $file); - $fp = fopen($file, 'a'); + $fp = fopen($file, $option); if ($fp === false) { error_log('could not open file for load data infile - ' . $file); @@ -193,11 +251,7 @@ class GetJobOrderArchiveDataCommand extends Command return null; } - // TODO: make this so you just call one function to create all the tables - // pass the year and the table name - // set the create sql as a constant or something - protected function createJobOrderArchiveTable($year) - { + protected function createJobOrderArchiveTables($year) { // form the archive table name _archive_ $archive_table_name = 'job_order_archive_' . $year; @@ -269,10 +323,142 @@ class GetJobOrderArchiveDataCommand extends Command $create_stmt = $db->prepare($create_sql); $result = $create_stmt->execute(); - - return $archive_table_name; } + protected function createInvoiceArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'invoice_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_paid` datetime DEFAULT NULL, + `date_cancel` datetime DEFAULT NULL, + `discount` decimal(9,2) NOT NULL, + `trade_in` decimal(9,2) NOT NULL, + `vat` decimal(9,2) NOT NULL, + `vat_exclusive_price` decimal(9,2) NOT NULL, + `total_price` decimal(9,2) NOT NULL, + `status` varchar(40) COLLATE utf8_unicode_ci NOT NULL, + `promo_id` int(11) DEFAULT NULL, + `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createInvoiceItemArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'invoice_item_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `invoice_id` int(11) DEFAULT NULL, + `title` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `qty` smallint(6) NOT NULL, + `price` decimal(9,2) NOT NULL, + `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createTicketArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'ticket_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `customer_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `status` varchar(15) COLLATE utf8_unicode_ci NOT NULL, + `ticket_type` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL, + `other_ticket_type` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `first_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `last_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `contact_num` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL, + `details` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `plate_number` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL, + `ticket_type_id` int(11) DEFAULT NULL, + `subticket_type_id` int(11) DEFAULT NULL, + `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createJORejectionArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_rejection_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `hub_id` int(11) DEFAULT NULL, + `jo_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `reason` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createRiderRatingArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_rejection_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `rider_id` int(11) DEFAULT NULL, + `customer_id` int(11) DEFAULT NULL, + `jo_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `rating` int(11) NOT NULL, + `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createJobOrderArchiveData($row) { // TODO: this could be shrunk further @@ -436,31 +622,19 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - protected function createLoadDataFileForArchiveData($archive_data, $table_name) + // TODO: rewrite this to just load the file + protected function loadDataFileForArchiveData($file, $table_name) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/jo_archive.tab'; + $file = $cache_dir . '/' $table_name . 'archive.tab'; error_log('opening file for jo archive - ' . $file); - $fp = fopen($file, 'w'); - if ($fp === false) - { - error_log('could not open file for load data infile - ' . $file); - } - else - { - foreach ($archive_data as $key => $data) - { - $line = implode('|', $data) . "\r\n"; - fwrite($fp, $line); - } - } - - fclose($fp); - $conn = $this->em->getConnection(); + + // this statement is for job order + // TODO: make for other tables $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' FIELDS TERMINATED BY \'|\' LINES TERMINATED BY \'\\r\\n\' -- 2.43.5 From 3773a664d13ffd100171e6735c81a958924ab210 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 18 Sep 2023 18:10:06 +0800 Subject: [PATCH 010/119] Add loading of data file. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 144 +++++++++++++----- 1 file changed, 109 insertions(+), 35 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 81cd795d..2aa81c42 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -57,25 +57,27 @@ class GetJobOrderArchiveDataCommand extends Command $this->createTicketArchiveTable($year); $this->createJORejectionArchiveTable($year); $this->createRiderRatingArchiveTable($year); + $this->createJOEventArchiveTable($year); $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create + LIMIT 100'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; - $this->getArchiveData($query_stmt, $callback); + $this->getArchiveData($query_stmt, $callback, 'job_order', $year); return 0; } - protected function getArchiveData($stmt, $callbackJO) + protected function getArchiveData($stmt, $callbackJO, $jo_tname, $year) { $results = $stmt->executeQuery(); @@ -117,21 +119,42 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - call_user_func($callbackJO, $row, $query_stmt, $table_name); + call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); } } } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, 'job_order', 'w'); + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); if ($file != null) - { + { + $archive_tname = $jo_tname . '_archive_' . $year; + + // load statement for job order + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@geo_coordinates)'; + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); } } - protected function getRelatedArchiveData($row, $query_stmt, $table_name) + protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) { $results = $query_stmt->executeQuery(); @@ -144,7 +167,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($table_name == 'invoice') { // get invoice item related data - $this->getInvoiceItemArchiveData($q_row); + $this->getInvoiceItemArchiveData($q_row, $year); } $fields = []; @@ -161,13 +184,56 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + // TODO: this needs to move or something because we are writing duplicate rows into the db if ($file != null) { + $archive_tname = $table_name . '_archive_' . $year; + + if ($table_name == 'jo_event') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; + } + if ($table_name == 'jo_rejection') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; + } + if ($table_name == 'invoice') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, + total_price, status, promo_id, used_customer_tag_id)'; + } + if ($table_name == 'rider_rating') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; + } + if ($table_name == 'ticket') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, + contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, + source_of_awareness, remarks, other_description)'; + } + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); } } - protected function getInvoiceItemArchiveData($row) + protected function getInvoiceItemArchiveData($row, $year) { $db = $this->em->getConnection(); @@ -202,6 +268,12 @@ class GetJobOrderArchiveDataCommand extends Command if ($file != null) { + $archive_tname = 'invoice_item_archive' . $year; + + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, invoice_id, title, qty, price, battery_id)'; // call load data infile } } @@ -323,6 +395,8 @@ class GetJobOrderArchiveDataCommand extends Command $create_stmt = $db->prepare($create_sql); $result = $create_stmt->execute(); + + return $archive_table_name; } protected function createInvoiceArchiveTable($year) @@ -438,7 +512,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function createRiderRatingArchiveTable($year) { // form the archive table name _archive_ - $archive_table_name = 'jo_rejection_archive_' . $year; + $archive_table_name = 'rider_rating_archive_' . $year; // create the table if it doesn't exist $db = $this->em->getConnection(); @@ -458,6 +532,29 @@ class GetJobOrderArchiveDataCommand extends Command $result = $create_stmt->execute(); } + protected function createJOEventArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_event_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `create_user_id` int(11) DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_happen` datetime NOT NULL, + `type_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + protected function createJobOrderArchiveData($row) { @@ -622,36 +719,13 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - // TODO: rewrite this to just load the file - protected function loadDataFileForArchiveData($file, $table_name) + protected function loadDataFileForArchiveData($load_stmt) { - // cache directory - $cache_dir = __DIR__ . '/../../var/cache'; - - $file = $cache_dir . '/' $table_name . 'archive.tab'; - error_log('opening file for jo archive - ' . $file); - $conn = $this->em->getConnection(); // this statement is for job order // TODO: make for other tables - $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, @coordinates, flag_advance, service_type, - source, date_cancel, status, delivery_instructions, delivery_address, - create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, - hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, - mode_of_payment, or_name, landmark, promo_detail, or_num, - trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, - coord_long, coord_lat, priority, meta, status_autoassign, - first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, - will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, - ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@geo_coordinates)' - ); + $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From f52293caa63fbd75078ae363060f107b15e75ea5 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 19 Sep 2023 12:48:14 +0800 Subject: [PATCH 011/119] Fix load file issue. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 76 +++++-------------- 1 file changed, 18 insertions(+), 58 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 2aa81c42..061bddc2 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -92,6 +92,7 @@ class GetJobOrderArchiveDataCommand extends Command // special since this is not directly related to JO but to invoice $this->deleteDataFiles('invoice_item'); + $related_files = []; while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); @@ -119,11 +120,20 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + $files[] = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + + // TODO: need to figure out how to get the filenames + foreach ($files as $key =>$file) + { + $related_files[$key] = $file; + } + } } } + error_log(print_r($related_files, true)); + // write the array into the file $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); @@ -159,6 +169,7 @@ class GetJobOrderArchiveDataCommand extends Command $results = $query_stmt->executeQuery(); $data = []; + $files = []; while ($q_row = $results->fetchAssociative()) { @@ -167,7 +178,9 @@ class GetJobOrderArchiveDataCommand extends Command if ($table_name == 'invoice') { // get invoice item related data - $this->getInvoiceItemArchiveData($q_row, $year); + $ii_file = $this->getInvoiceItemArchiveData($q_row, $year); + + $files['invoice_item'] = $ii_file; } $fields = []; @@ -184,53 +197,9 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); - // TODO: this needs to move or something because we are writing duplicate rows into the db - if ($file != null) - { - $archive_tname = $table_name . '_archive_' . $year; + $files[$table_name] = $file; - if ($table_name == 'jo_event') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; - } - if ($table_name == 'jo_rejection') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; - } - if ($table_name == 'invoice') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, - total_price, status, promo_id, used_customer_tag_id)'; - } - if ($table_name == 'rider_rating') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; - } - if ($table_name == 'ticket') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, - contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, - source_of_awareness, remarks, other_description)'; - } - - // call load data infile - $this->loadDataFileForArchiveData($load_stmt); - } + return $files; } protected function getInvoiceItemArchiveData($row, $year) @@ -266,16 +235,7 @@ class GetJobOrderArchiveDataCommand extends Command $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); - if ($file != null) - { - $archive_tname = 'invoice_item_archive' . $year; - - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, invoice_id, title, qty, price, battery_id)'; - // call load data infile - } + return $file; } protected function deleteDataFiles($tname) -- 2.43.5 From a7c69886079f2ecb3fd28ea8c259840052c3a661 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 20 Sep 2023 11:54:05 +0800 Subject: [PATCH 012/119] Add loading of data files. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 119 +++++++++++++----- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 061bddc2..8115be68 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -65,7 +65,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 100'; + LIMIT 100000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -92,7 +92,7 @@ class GetJobOrderArchiveDataCommand extends Command // special since this is not directly related to JO but to invoice $this->deleteDataFiles('invoice_item'); - $related_files = []; + $archive_files = []; while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); @@ -120,48 +120,27 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - $files[] = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + $files = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); - // TODO: need to figure out how to get the filenames foreach ($files as $key =>$file) { - $related_files[$key] = $file; + if ($file != null) + $archive_files[$key] = $file; } - } } } - error_log(print_r($related_files, true)); - // write the array into the file $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); if ($file != null) { - $archive_tname = $jo_tname . '_archive_' . $year; - - // load statement for job order - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, @coordinates, flag_advance, service_type, - source, date_cancel, status, delivery_instructions, delivery_address, - create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, - hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, - mode_of_payment, or_name, landmark, promo_detail, or_num, - trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, - coord_long, coord_lat, priority, meta, status_autoassign, - first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, - will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, - ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@geo_coordinates)'; - - // call load data infile - $this->loadDataFileForArchiveData($load_stmt); + $archive_files[$jo_tname] = $file; } + + // error_log(print_r($archive_files, true)); + $this->loadArchiveFiles($archive_files, $year); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -197,7 +176,8 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); - $files[$table_name] = $file; + if ($file != null) + $files[$table_name] = $file; return $files; } @@ -679,6 +659,83 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } + protected function loadArchiveFiles($archive_files, $year) + { + foreach ($archive_files as $tname => $file) + { + $archive_tname = $tname . '_archive_' . $year; + + if ($tname == 'job_order') + { + // load statement for job order + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@geo_coordinates)'; + } + if ($tname == 'jo_event') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; + } + if ($tname == 'jo_rejection') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; + } + if ($tname == 'invoice') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, + total_price, status, promo_id, used_customer_tag_id)'; + } + if ($tname == 'rider_rating') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; + } + if ($tname == 'ticket') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, + contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, + source_of_awareness, remarks, other_description)'; + } + if ($tname == 'invoice_item') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, invoice_id, title, qty, price, battery_id)'; + } + + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); + } + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); -- 2.43.5 From 19840c03058affa9f71c6ebb33fad4d6c5e7758c Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 20 Sep 2023 15:31:46 +0800 Subject: [PATCH 013/119] Improve performance. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 8115be68..c1f24cc6 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -61,11 +61,12 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); + // TODO: improve performance. out of memory exception $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create - LIMIT 100000'; + ORDER BY date_create + LIMIT 150000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -93,13 +94,22 @@ class GetJobOrderArchiveDataCommand extends Command $this->deleteDataFiles('invoice_item'); $archive_files = []; + + $jo_id_list = []; + while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); + // add jo id to jo_id_list + $jo_id_list[] = $row['id']; + } + + // get all related data for job order + foreach ($jo_id_list as $jo_id) + { // foreach job order id we got from the first query, we get the JO related // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating - if (is_callable($callbackJO)) { foreach ($related_tables as $table_name) @@ -118,7 +128,7 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); + $query_stmt->bindValue('id', $jo_id); $files = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); @@ -149,6 +159,7 @@ class GetJobOrderArchiveDataCommand extends Command $data = []; $files = []; + $invoice_id_list = []; while ($q_row = $results->fetchAssociative()) { @@ -156,10 +167,8 @@ class GetJobOrderArchiveDataCommand extends Command // all invoice items for a specific invoice too if ($table_name == 'invoice') { - // get invoice item related data - $ii_file = $this->getInvoiceItemArchiveData($q_row, $year); - - $files['invoice_item'] = $ii_file; + // add invoice id to list + $invoice_id_list[] = $q_row['id']; } $fields = []; @@ -173,6 +182,14 @@ class GetJobOrderArchiveDataCommand extends Command $data[$table_name][$q_row['id']] = $fields; } + // get the invoice items for archiving + foreach ($invoice_id_list as $i_id) + { + $ii_file = $this->getInvoiceItemArchiveData($i_id, $year); + + $files['invoice_item'] = $ii_file; + } + // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); @@ -182,14 +199,14 @@ class GetJobOrderArchiveDataCommand extends Command return $files; } - protected function getInvoiceItemArchiveData($row, $year) + protected function getInvoiceItemArchiveData($id, $year) { $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); + $query_stmt->bindValue('id', $id); $results = $query_stmt->executeQuery(); -- 2.43.5 From fde9b367ecbdb9c45a94b1fd2bd2f18e16dad037 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 22 Sep 2023 14:37:54 +0800 Subject: [PATCH 014/119] Set limit to jo query results. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index c1f24cc6..7303b79a 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -66,7 +66,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 150000'; + LIMIT 125000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); -- 2.43.5 From e65083bc4c34844b9f86b02764e36ab65ee84312 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 26 Sep 2023 13:03:47 +0800 Subject: [PATCH 015/119] Add retrieval of ids for deletion. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 7303b79a..d6ba4582 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -66,7 +66,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 125000'; + LIMIT 100000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -151,6 +151,14 @@ class GetJobOrderArchiveDataCommand extends Command // error_log(print_r($archive_files, true)); $this->loadArchiveFiles($archive_files, $year); + + // need to get the list of invoice ids for deletion for invoice items + $invoice_id_list = $this->getInvoiceIds($jo_id_list); + + error_log(print_r($invoice_id_list, true)); + + // at this point, all the job order and related data have been archived into the database + $this->deleteData($jo_id_list, $invoice_id_list); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -256,7 +264,7 @@ class GetJobOrderArchiveDataCommand extends Command $cache_dir = __DIR__ . '/../../var/cache'; $file = $cache_dir . '/' . $table_name . '_archive.tab'; - error_log('opening file for archive - ' . $file); + // error_log('opening file for archive - ' . $file); $fp = fopen($file, $option); if ($fp === false) @@ -753,6 +761,39 @@ class GetJobOrderArchiveDataCommand extends Command } } + protected function deleteData($jo_id_list, $invoice_id_list) + { + $db = $this->em->getConnection(); + + // delete the invoice items first + } + + protected function getInvoiceIds($jo_id_list) + { + $invoice_id_list = []; + + $db = $this->em->getConnection(); + + $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; + + $query_stmt = $db->prepare($query_sql); + + foreach ($jo_id_list as $jo_id) + { + // need to get the invoice ids for the invoice items to delete + $query_stmt->bindValue('id', $jo_id); + + $results = $query_stmt->executeQuery(); + + while ($row = $results->fetchAssociative()) + { + $invoice_id_list[] = $row['id']; + } + } + + return $invoice_id_list; + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); -- 2.43.5 From 645e8a63fcc0a058d3a163052f66455860a27a07 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 26 Sep 2023 16:28:40 +0800 Subject: [PATCH 016/119] Add deletion. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index d6ba4582..cc0fab18 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -39,6 +39,10 @@ class GetJobOrderArchiveDataCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { + $current_datetime = new DateTime('now'); + + error_log('Archive start time ' . $current_datetime->format('Y-m-d H:i')); + // get year to archive $year = $input->getArgument('year'); @@ -61,20 +65,26 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); - // TODO: improve performance. out of memory exception + // set the pdo connection to use unbuffered query so we don't run out of memory + // when processing the job order related tables + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create - LIMIT 100000'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); - $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; + $callback = [$this, 'getRelatedArchiveData']; $this->getArchiveData($query_stmt, $callback, 'job_order', $year); + $current_datetime = new DateTime('now'); + + error_log('Archive end time ' . $current_datetime->format('Y-m-d H:i')); + return 0; } @@ -87,11 +97,11 @@ class GetJobOrderArchiveDataCommand extends Command // delete the related data files foreach ($related_tables as $tname) { - $this->deleteDataFiles($tname); + $this->deleteDataFiles($tname, $year); } // special since this is not directly related to JO but to invoice - $this->deleteDataFiles('invoice_item'); + $this->deleteDataFiles('invoice_item', $year); $archive_files = []; @@ -114,18 +124,21 @@ class GetJobOrderArchiveDataCommand extends Command { foreach ($related_tables as $table_name) { - if (($table_name == 'jo_event') || - ($table_name == 'invoice') || - ($table_name == 'ticket')) - { - $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; - } - else - { - $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + switch ($table_name) { + case 'jo_event': + case 'invoice': + case 'ticket': + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; + break; + case 'jo_rejection': + case 'rider_rating': + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + default: + break; } $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $jo_id); @@ -142,7 +155,7 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); if ($file != null) { @@ -155,7 +168,7 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - error_log(print_r($invoice_id_list, true)); + // error_log(print_r($invoice_id_list, true)); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list); @@ -199,7 +212,7 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + $file = $this->createDataFileRelatedArchiveData($data, $table_name, $year, 'a'); if ($file != null) $files[$table_name] = $file; @@ -210,6 +223,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function getInvoiceItemArchiveData($id, $year) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; @@ -238,23 +252,23 @@ class GetJobOrderArchiveDataCommand extends Command ]; } - $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); + $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', $year, 'a'); return $file; } - protected function deleteDataFiles($tname) + protected function deleteDataFiles($tname, $year) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/' . $tname . '_archive.tab'; + $file = $cache_dir . '/' . $tname . '_archive_' . $year .'.tab'; if (file_exists($file)) unlink($file); } - protected function createDataFileRelatedArchiveData($archive_data, $table_name, $option) + protected function createDataFileRelatedArchiveData($archive_data, $table_name, $year, $option) { if (isset($archive_data[$table_name])) { @@ -263,7 +277,7 @@ class GetJobOrderArchiveDataCommand extends Command // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/' . $table_name . '_archive.tab'; + $file = $cache_dir . '/' . $table_name . '_archive_'. $year . '.tab'; // error_log('opening file for archive - ' . $file); $fp = fopen($file, $option); @@ -766,6 +780,12 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); // delete the invoice items first + $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; + + $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN ($inv_ids)'; + $ii_stmt = $db->prepare($ii_del_sql); + + $ii_stmt->execute($invoice_id_list); } protected function getInvoiceIds($jo_id_list) -- 2.43.5 From d78dc72c35154cfb98048ae598b9e4bb6aff47a8 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Sep 2023 14:54:36 +0800 Subject: [PATCH 017/119] Fix deletion issues for related tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index cc0fab18..3f9d3938 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -133,6 +133,7 @@ class GetJobOrderArchiveDataCommand extends Command case 'jo_rejection': case 'rider_rating': $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + break; default: break; } @@ -171,7 +172,7 @@ class GetJobOrderArchiveDataCommand extends Command // error_log(print_r($invoice_id_list, true)); // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $invoice_id_list); + $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -775,17 +776,48 @@ class GetJobOrderArchiveDataCommand extends Command } } - protected function deleteData($jo_id_list, $invoice_id_list) + protected function deleteData($jo_id_list, $invoice_id_list, $related_tables) { $db = $this->em->getConnection(); // delete the invoice items first $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; - $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN ($inv_ids)'; + $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN (' . $inv_ids . ')'; $ii_stmt = $db->prepare($ii_del_sql); $ii_stmt->execute($invoice_id_list); + + // delete from invoice, jo_rejection, rider_rating, ticket, and jo_event + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; + + foreach ($related_tables as $table_name) + { + switch ($table_name) { + case 'jo_event': + case 'invoice': + case 'ticket': + $related_del_sql = 'DELETE FROM ' . $table_name . ' WHERE job_order_id IN ('. $jo_ids . ')'; + break; + case 'jo_rejection': + case 'rider_rating': + $related_del_sql = 'DELETE FROM ' . $table_name . ' WHERE jo_id IN (' . $jo_ids. ')'; + break; + default: + break; + } + + $related_stmt = $db->prepare($related_del_sql); + + $related_stmt->execute($jo_id_list); + } + + // TODO: hitting a snag here if JO to be deleted is a reference JO for another JO + // delete from job order last + $jo_del_sql = 'DELETE FROM job_order WHERE id IN (' . $jo_ids . ')'; + $jo_stmt = $db->prepare($jo_del_sql); + + $jo_stmt->execute($jo_id_list); } protected function getInvoiceIds($jo_id_list) -- 2.43.5 From 96bd783ae98e5762a1e509bd59a0da025879fccf Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 14:15:41 +0800 Subject: [PATCH 018/119] Add reference_jo_id field to hold the job order id for reference orders. Add a command to decouple reference job order from job order. #762 --- .../SetJobOrderReferenceJOIdCommand.php | 53 +++++++++++++++++++ src/Entity/JobOrder.php | 19 ++++++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/Command/SetJobOrderReferenceJOIdCommand.php diff --git a/src/Command/SetJobOrderReferenceJOIdCommand.php b/src/Command/SetJobOrderReferenceJOIdCommand.php new file mode 100644 index 00000000..20ee236a --- /dev/null +++ b/src/Command/SetJobOrderReferenceJOIdCommand.php @@ -0,0 +1,53 @@ +em = $em; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('joborder:setreferencejoid') + ->setDescription('Set job order reference jo id for existing job orders.') + ->setHelp('Set job order reference jo id for existing job orders. Decoupling job order from reference job order.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // get the job orders where ref_jo is not null + $query = $this->em->createQuery('SELECT jo FROM App\Entity\JobOrder jo WHERE jo.ref_jo IS NOT NULL'); + + $jos = $query->getResult(); + + foreach ($jos as $jo) + { + $ref_jo_id = $jo->getReferenceJO()->getID(); + + error_log('Setting reference jo id ' . $ref_jo_id . ' for job order ' . $jo->getID()); + + $jo->setReferenceJOId($ref_jo_id); + + // set the ref_jo to null to decouple ref jo and jo + $jo->setReferenceJO(null); + } + + $this->em->flush(); + + return 0; + } +} diff --git a/src/Entity/JobOrder.php b/src/Entity/JobOrder.php index c71f1846..a410f9e0 100644 --- a/src/Entity/JobOrder.php +++ b/src/Entity/JobOrder.php @@ -435,6 +435,12 @@ class JobOrder */ protected $inventory_count; + // reference JO id. We are now decoupling job order from itself + /** + * @ORM\Column(type="integer", nullable=true) + */ + protected $reference_jo_id; + public function __construct() { $this->date_create = new DateTime(); @@ -784,7 +790,7 @@ class JobOrder return $this->tickets; } - public function setReferenceJO(JobOrder $ref_jo) + public function setReferenceJO(JobOrder $ref_jo = null) { $this->ref_jo = $ref_jo; return $this; @@ -1237,4 +1243,15 @@ class JobOrder return $this->inventory_count; } + public function setReferenceJOId($reference_jo_id) + { + $this->reference_jo_id = $reference_jo_id; + return $this; + } + + public function getReferenceJOId() + { + return $this->reference_jo_id; + } + } -- 2.43.5 From 4fa5ea156f4c90d326b138c4ed50274e08a9e90a Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 14:41:49 +0800 Subject: [PATCH 019/119] Modify saving of reference job order for job order. #762 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 3e86f434..28eecea6 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -527,7 +527,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if (empty($ref_jo)) { $error_array['ref_jo'] = 'Invalid reference job order specified.'; } else { - $jo->setReferenceJO($ref_jo); + $jo->setReferenceJOId($ref_jo->getID()); } } @@ -2129,7 +2129,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if (empty($ref_jo)) { $error_array['ref_jo'] = 'Invalid reference job order specified.'; } else { - $jo->setReferenceJO($ref_jo); + $jo->setReferenceJOId($ref_jo->getID()); } } -- 2.43.5 From 12d9c14a03501520bab21573e0b4217cef6d7c57 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 16:00:28 +0800 Subject: [PATCH 020/119] Add updating of rider's active and current job orders. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 3f9d3938..563f77d0 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -169,7 +169,13 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // error_log(print_r($invoice_id_list, true)); + // need to get the list of riders whose active_jo_id or current_jo_id is + // set to very old JOs + $rider_id_list = $this->findRiderIDs($jo_id_list); + + // update rider's active_jo_id and current_jo_id to null + // so we can delete the old job orders (foreign key constraint) + $this->updateRiderJobOrders($rider_id_list); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); @@ -812,7 +818,6 @@ class GetJobOrderArchiveDataCommand extends Command $related_stmt->execute($jo_id_list); } - // TODO: hitting a snag here if JO to be deleted is a reference JO for another JO // delete from job order last $jo_del_sql = 'DELETE FROM job_order WHERE id IN (' . $jo_ids . ')'; $jo_stmt = $db->prepare($jo_del_sql); @@ -846,12 +851,51 @@ class GetJobOrderArchiveDataCommand extends Command return $invoice_id_list; } + protected function findRiderIDs($jo_id_list) + { + $rider_id_list = []; + + $db = $this->em->getConnection(); + + $rider_sql = 'SELECT id FROM rider WHERE ((current_jo_id = :jo_id) OR (active_jo_id = :jo_id))'; + $rider_stmt = $db->prepare($rider_sql); + + // find the riders with current_jo_id or active_jo_id are still set to the old JOs + foreach ($jo_id_list as $jo_id) + { + $rider_stmt->bindValue('jo_id', $jo_id); + + $results = $rider_stmt->executeQuery(); + + while ($row = $results->fetchAssociative()) + { + $rider_id_list[] = $row['id']; + } + } + + return $rider_id_list; + } + + protected function updateRiderJobOrders($rider_id_list) + { + $db = $this->em->getConnection(); + + $update_sql = 'UPDATE rider SET current_jo_id = NULL, SET active_jo_id = NULL WHERE id = :id'; + $update_stmt = $db->prepare($update_sql); + + foreach ($rider_id_list as $rider_id) + { + $update_stmt->execute([ + 'id' => $rider_id, + ]); + } + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); // this statement is for job order - // TODO: make for other tables $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From 9bf5d5851a17b2df58f0de9996661811902bb937 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 18:22:56 +0800 Subject: [PATCH 021/119] Add updating of rider's current and active jo ids to null. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 41 ++++--------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 563f77d0..4fe27fb7 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -169,13 +169,9 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // need to get the list of riders whose active_jo_id or current_jo_id is - // set to very old JOs - $rider_id_list = $this->findRiderIDs($jo_id_list); - // update rider's active_jo_id and current_jo_id to null // so we can delete the old job orders (foreign key constraint) - $this->updateRiderJobOrders($rider_id_list); + $this->updateRiderJobOrders($jo_id_list); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); @@ -830,6 +826,7 @@ class GetJobOrderArchiveDataCommand extends Command $invoice_id_list = []; $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; @@ -851,42 +848,18 @@ class GetJobOrderArchiveDataCommand extends Command return $invoice_id_list; } - protected function findRiderIDs($jo_id_list) - { - $rider_id_list = []; - - $db = $this->em->getConnection(); - - $rider_sql = 'SELECT id FROM rider WHERE ((current_jo_id = :jo_id) OR (active_jo_id = :jo_id))'; - $rider_stmt = $db->prepare($rider_sql); - - // find the riders with current_jo_id or active_jo_id are still set to the old JOs - foreach ($jo_id_list as $jo_id) - { - $rider_stmt->bindValue('jo_id', $jo_id); - - $results = $rider_stmt->executeQuery(); - - while ($row = $results->fetchAssociative()) - { - $rider_id_list[] = $row['id']; - } - } - - return $rider_id_list; - } - - protected function updateRiderJobOrders($rider_id_list) + protected function updateRiderJobOrders($jo_id_list) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $update_sql = 'UPDATE rider SET current_jo_id = NULL, SET active_jo_id = NULL WHERE id = :id'; + $update_sql = 'UPDATE rider SET current_jo_id = NULL, active_jo_id = NULL WHERE (current_jo_id = :id OR active_jo_id = :id)'; $update_stmt = $db->prepare($update_sql); - foreach ($rider_id_list as $rider_id) + foreach ($jo_id_list as $jo_id) { $update_stmt->execute([ - 'id' => $rider_id, + 'id' => $jo_id, ]); } } -- 2.43.5 From 3e0084630f57c80e8afa3715fb59050bc0af7598 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 19:07:11 +0800 Subject: [PATCH 022/119] Add TODO for updating rider. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 4fe27fb7..e266f6dd 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -850,6 +850,11 @@ class GetJobOrderArchiveDataCommand extends Command protected function updateRiderJobOrders($jo_id_list) { + // TODO: memory exception while updating rider table. + // need to figure out how to make this not run out of memory. + // first draft had us selecting and finding the rider ids. maybe we should bring + // that back with the set attribute? I can't remember if I ran it with that one :( + // so that updating will have a smaller result set. $db = $this->em->getConnection(); $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); -- 2.43.5 From 67635b07d593c57e5076ff95b5c3d002b9691ce2 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 19:35:10 +0800 Subject: [PATCH 023/119] Modify updating of rider table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e266f6dd..e5ac289d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -850,23 +850,19 @@ class GetJobOrderArchiveDataCommand extends Command protected function updateRiderJobOrders($jo_id_list) { - // TODO: memory exception while updating rider table. - // need to figure out how to make this not run out of memory. - // first draft had us selecting and finding the rider ids. maybe we should bring - // that back with the set attribute? I can't remember if I ran it with that one :( - // so that updating will have a smaller result set. + // TODO: test this $db = $this->em->getConnection(); - $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $update_sql = 'UPDATE rider SET current_jo_id = NULL, active_jo_id = NULL WHERE (current_jo_id = :id OR active_jo_id = :id)'; - $update_stmt = $db->prepare($update_sql); + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; - foreach ($jo_id_list as $jo_id) - { - $update_stmt->execute([ - 'id' => $jo_id, - ]); - } + $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; + $update_curr_stmt = $db->prepare($update_curr_sql); + + $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; + $udpate_active_stmt = $db->prepare($update_active_sql); + + $update_curr_stmt->execute($jo_id_list); + $update_active_stmt->execute($jo_id_list); } protected function loadDataFileForArchiveData($load_stmt) -- 2.43.5 From f78e37657666a61c426cb8d0ffa2af6dbc91fc77 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 29 Sep 2023 20:47:13 +0800 Subject: [PATCH 024/119] Fix issues found during testing. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e5ac289d..1ff9ac6d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -106,6 +106,7 @@ class GetJobOrderArchiveDataCommand extends Command $archive_files = []; $jo_id_list = []; + $ii_id_list = []; while ($row = $results->fetchAssociative()) { @@ -115,6 +116,24 @@ class GetJobOrderArchiveDataCommand extends Command $jo_id_list[] = $row['id']; } + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); + + if ($file != null) + { + $archive_files[$jo_tname] = $file; + } + + // error_log('jo_data total ' . count($jo_data['job_order'])); + // error_log('jo id list total ' . count($jo_id_list)); + + unset($jo_data); + + // load the job order archive file for job order into the database + $this->loadArchiveFiles($archive_files, $year); + + unset($archive_files[$jo_tname]); + // get all related data for job order foreach ($jo_id_list as $jo_id) { @@ -155,26 +174,16 @@ class GetJobOrderArchiveDataCommand extends Command } } - // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); - - if ($file != null) - { - $archive_files[$jo_tname] = $file; - } - - // error_log(print_r($archive_files, true)); + // TODO: can we maybe find a way to not load the archive files successively? + // we get the memory exception after loading the data to the last table, jo_rejection. $this->loadArchiveFiles($archive_files, $year); - // need to get the list of invoice ids for deletion for invoice items - $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // update rider's active_jo_id and current_jo_id to null // so we can delete the old job orders (foreign key constraint) $this->updateRiderJobOrders($jo_id_list); // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); + $this->deleteData($jo_id_list, $related_tables); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -207,6 +216,7 @@ class GetJobOrderArchiveDataCommand extends Command } // get the invoice items for archiving + $ii_id_list = []; foreach ($invoice_id_list as $i_id) { $ii_file = $this->getInvoiceItemArchiveData($i_id, $year); @@ -217,6 +227,8 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, $year, 'a'); + unset($data); + if ($file != null) $files[$table_name] = $file; @@ -236,6 +248,7 @@ class GetJobOrderArchiveDataCommand extends Command $results = $query_stmt->executeQuery(); $ii_data = []; + $ii_id_list = []; while ($ii_row = $results->fetchAssociative()) { $id = $ii_row['id']; @@ -253,10 +266,19 @@ class GetJobOrderArchiveDataCommand extends Command $price, $battery_id ]; + + $ii_id_list[] = $id; } $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', $year, 'a'); + unset($ii_data); + + // special case, delete the invoice items already + // so that we don't have to query for the invoice items to delete + if (count($ii_id_list) > 0) + $this->deleteInvoiceItems($ii_id_list); + return $file; } @@ -778,17 +800,22 @@ class GetJobOrderArchiveDataCommand extends Command } } - protected function deleteData($jo_id_list, $invoice_id_list, $related_tables) + protected function deleteInvoiceItems($ii_id_list) { $db = $this->em->getConnection(); // delete the invoice items first - $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; + $ii_ids = str_repeat('?,', count($ii_id_list) - 1) . '?'; - $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN (' . $inv_ids . ')'; + $ii_del_sql = 'DELETE FROM invoice_item WHERE id IN (' . $ii_ids . ')'; $ii_stmt = $db->prepare($ii_del_sql); - $ii_stmt->execute($invoice_id_list); + $ii_stmt->execute($ii_id_list); + } + + protected function deleteData($jo_id_list, $related_tables) + { + $db = $this->em->getConnection(); // delete from invoice, jo_rejection, rider_rating, ticket, and jo_event $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; @@ -821,36 +848,8 @@ class GetJobOrderArchiveDataCommand extends Command $jo_stmt->execute($jo_id_list); } - protected function getInvoiceIds($jo_id_list) - { - $invoice_id_list = []; - - $db = $this->em->getConnection(); - $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - - $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; - - $query_stmt = $db->prepare($query_sql); - - foreach ($jo_id_list as $jo_id) - { - // need to get the invoice ids for the invoice items to delete - $query_stmt->bindValue('id', $jo_id); - - $results = $query_stmt->executeQuery(); - - while ($row = $results->fetchAssociative()) - { - $invoice_id_list[] = $row['id']; - } - } - - return $invoice_id_list; - } - protected function updateRiderJobOrders($jo_id_list) { - // TODO: test this $db = $this->em->getConnection(); $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; @@ -859,17 +858,20 @@ class GetJobOrderArchiveDataCommand extends Command $update_curr_stmt = $db->prepare($update_curr_sql); $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; - $udpate_active_stmt = $db->prepare($update_active_sql); + $update_active_stmt = $db->prepare($update_active_sql); $update_curr_stmt->execute($jo_id_list); $update_active_stmt->execute($jo_id_list); + + unset($update_curr_stmt); + unset($update_active_stmt); } protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); + $conn->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - // this statement is for job order $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From 85483fb744d963d485de3bd079fc7911e22054c1 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 3 Oct 2023 22:08:46 +0800 Subject: [PATCH 025/119] Added batch update for rider table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 1ff9ac6d..a6540080 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -174,16 +174,23 @@ class GetJobOrderArchiveDataCommand extends Command } } - // TODO: can we maybe find a way to not load the archive files successively? - // we get the memory exception after loading the data to the last table, jo_rejection. $this->loadArchiveFiles($archive_files, $year); - // update rider's active_jo_id and current_jo_id to null - // so we can delete the old job orders (foreign key constraint) - $this->updateRiderJobOrders($jo_id_list); + error_log('Done loading files into database...'); - // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $related_tables); + $jo_id_array = array_chunk($jo_id_list, 10000); + + unset($jo_id_list); + + foreach($jo_id_array as $key => $jo_ids) + { + // update rider's active_jo_id and current_jo_id to null + // so we can delete the old job orders (foreign key constraint) + $this->updateRiderActiveJobOrders($jo_ids); + $this->updateRiderCurrentJobOrders($jo_ids); + + $this->deleteData($jo_ids, $related_tables); + } } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -279,6 +286,8 @@ class GetJobOrderArchiveDataCommand extends Command if (count($ii_id_list) > 0) $this->deleteInvoiceItems($ii_id_list); + unset($ii_id_list); + return $file; } @@ -848,23 +857,38 @@ class GetJobOrderArchiveDataCommand extends Command $jo_stmt->execute($jo_id_list); } - protected function updateRiderJobOrders($jo_id_list) + protected function updateRiderActiveJobOrders($jo_id_list) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; + + $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; + $update_active_stmt = $db->prepare($update_active_sql); + + error_log('Updating active rider job orders...'); + + $update_active_stmt->execute($jo_id_list); + + unset($update_active_stmt); + } + + protected function updateRiderCurrentJobOrders($jo_id_list) + { + $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; $update_curr_stmt = $db->prepare($update_curr_sql); - $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; - $update_active_stmt = $db->prepare($update_active_sql); + error_log('Updating current rider job orders...'); $update_curr_stmt->execute($jo_id_list); - $update_active_stmt->execute($jo_id_list); unset($update_curr_stmt); - unset($update_active_stmt); } protected function loadDataFileForArchiveData($load_stmt) -- 2.43.5 From 4b59380e723ecc497c9d5c9f25b9cf5b2c683857 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 4 Oct 2023 10:08:42 +0800 Subject: [PATCH 026/119] Add fix for missing entries when loading file to database. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index a6540080..cd764e56 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -743,6 +743,7 @@ class GetJobOrderArchiveDataCommand extends Command // load statement for job order $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, customer_id, cvehicle_id, rider_id, date_create, date_schedule, date_fulfill, @coordinates, flag_advance, service_type, @@ -762,6 +763,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; } @@ -769,6 +771,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; } @@ -776,6 +779,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, total_price, status, promo_id, used_customer_tag_id)'; @@ -784,6 +788,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; } @@ -791,6 +796,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, @@ -800,6 +806,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, invoice_id, title, qty, price, battery_id)'; } -- 2.43.5 From 1a0127072348f37776bc1c5dda2a3f4c15871293 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 4 Oct 2023 13:58:53 +0800 Subject: [PATCH 027/119] Fix saving of the enye character. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index cd764e56..b289cff6 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -403,7 +403,8 @@ class GetJobOrderArchiveDataCommand extends Command `initial_concern_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, `gender` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, `caller_classification` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, - `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`))'; + `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -435,7 +436,8 @@ class GetJobOrderArchiveDataCommand extends Command `total_price` decimal(9,2) NOT NULL, `status` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `promo_id` int(11) DEFAULT NULL, - `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -457,7 +459,8 @@ class GetJobOrderArchiveDataCommand extends Command `title` varchar(80) COLLATE utf8_unicode_ci NOT NULL, `qty` smallint(6) NOT NULL, `price` decimal(9,2) NOT NULL, - `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -491,7 +494,8 @@ class GetJobOrderArchiveDataCommand extends Command `subticket_type_id` int(11) DEFAULT NULL, `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, - `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -515,7 +519,8 @@ class GetJobOrderArchiveDataCommand extends Command `date_create` datetime NOT NULL, `reason` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, - `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -538,7 +543,8 @@ class GetJobOrderArchiveDataCommand extends Command `jo_id` int(11) DEFAULT NULL, `date_create` datetime NOT NULL, `rating` int(11) NOT NULL, - `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`))'; + `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -561,7 +567,8 @@ class GetJobOrderArchiveDataCommand extends Command `date_create` datetime NOT NULL, `date_happen` datetime NOT NULL, `type_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL, - `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -741,7 +748,8 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'job_order') { // load statement for job order - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -762,6 +770,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'jo_event') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -770,6 +779,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'jo_rejection') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -778,6 +788,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'invoice') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -787,6 +798,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'rider_rating') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -795,6 +807,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'ticket') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -805,6 +818,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'invoice_item') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -874,7 +888,7 @@ class GetJobOrderArchiveDataCommand extends Command $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; $update_active_stmt = $db->prepare($update_active_sql); - error_log('Updating active rider job orders...'); + // error_log('Updating active rider job orders...'); $update_active_stmt->execute($jo_id_list); @@ -891,7 +905,7 @@ class GetJobOrderArchiveDataCommand extends Command $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; $update_curr_stmt = $db->prepare($update_curr_sql); - error_log('Updating current rider job orders...'); + // error_log('Updating current rider job orders...'); $update_curr_stmt->execute($jo_id_list); -- 2.43.5 From d8bd2803e0805f2f35a3adbbfb44e8cca7590b77 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Mon, 18 Dec 2023 17:17:40 +0800 Subject: [PATCH 028/119] Display inactive batteries on edit vehicle form, exclude inactive batteries on battery recommendations API endpoint #779 --- .../CustomerAppAPI/VehicleController.php | 2 +- templates/vehicle/form.html.twig | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Controller/CustomerAppAPI/VehicleController.php b/src/Controller/CustomerAppAPI/VehicleController.php index bc1e29c2..ba76d7a4 100644 --- a/src/Controller/CustomerAppAPI/VehicleController.php +++ b/src/Controller/CustomerAppAPI/VehicleController.php @@ -254,7 +254,7 @@ class VehicleController extends ApiController // batteries $batt_list = []; - $batts = $vehicle->getBatteries(); + $batts = $vehicle->getActiveBatteries(); foreach ($batts as $batt) { // TODO: Add warranty_tnv to battery information $batt_list[] = [ diff --git a/templates/vehicle/form.html.twig b/templates/vehicle/form.html.twig index 99ecbc0f..e09e275c 100644 --- a/templates/vehicle/form.html.twig +++ b/templates/vehicle/form.html.twig @@ -233,13 +233,14 @@ $(function() { var batteryIds = []; var battMfgModelSize = [] - {% for batt in obj.getActiveBatteries %} + {% for batt in obj.getBatteries %} trow = { id: "{{ batt.getID }}", manufacturer: "{{ batt.getManufacturer.getName|default('') }} ", model: "{{ batt.getModel.getName|default('') }}", size: "{{ batt.getSize.getName|default('') }}", sell_price: "{{ batt.getSellingPrice }}", + flag_active: {{ batt.isActive ? "true" : "false" }}, }; battRows.push(trow); @@ -360,6 +361,21 @@ $(function() { title: 'Model', width: 150 }, + { + field: 'flag_active', + title: 'Active', + template: function (row, index, datatable) { + var tag = ''; + + if (row.flag_active === true) { + tag = 'Yes'; + } else { + tag = 'No'; + } + + return tag; + }, + }, { field: 'sell_price', title: 'Price' -- 2.43.5 From 9447f643126c2ee5aba0ca254fa569f0b856931d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 19 Dec 2023 17:30:38 +0800 Subject: [PATCH 029/119] Create item price, price tier, and item type entities for regional pricing. #780 --- src/Entity/ItemPrice.php | 53 +++++++++++++++++++++++++++++ src/Entity/ItemType.php | 69 +++++++++++++++++++++++++++++++++++++ src/Entity/PriceTier.php | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 src/Entity/ItemPrice.php create mode 100644 src/Entity/ItemType.php create mode 100644 src/Entity/PriceTier.php diff --git a/src/Entity/ItemPrice.php b/src/Entity/ItemPrice.php new file mode 100644 index 00000000..d03cadbf --- /dev/null +++ b/src/Entity/ItemPrice.php @@ -0,0 +1,53 @@ +id; + } +} diff --git a/src/Entity/ItemType.php b/src/Entity/ItemType.php new file mode 100644 index 00000000..204fb9b3 --- /dev/null +++ b/src/Entity/ItemType.php @@ -0,0 +1,69 @@ +code = ''; + } + + public function getID() + { + return $this->id; + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getName() + { + return $this->name; + } + + public function setCode($code) + { + $this->code = $code; + return $this; + } + + public function getCode() + { + return $this->code; + } +} diff --git a/src/Entity/PriceTier.php b/src/Entity/PriceTier.php new file mode 100644 index 00000000..18b735aa --- /dev/null +++ b/src/Entity/PriceTier.php @@ -0,0 +1,73 @@ +meta_areas = []; + + $this->items = new ArrayCollection(); + } + + public function getID() + { + return $this->id; + } + + public function setName($name) + { + $this->name = $name; + return $this; + } + + public function getName() + { + return $this->name; + } + + public function addMetaArea($id, $value) + { + $this->meta_areas[$id] = $value; + } + + public function getAllMetaAreas() + { + return $this->meta_areas; + } +} -- 2.43.5 From fa3cf12be12bb8cc9fd43355a96031997dc70ff1 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 20 Dec 2023 18:15:17 +0800 Subject: [PATCH 030/119] Add controller for price tier. #780 --- config/packages/catalyst_auth.yaml | 42 +++++ config/packages/catalyst_menu.yaml | 26 ++- config/routes/price_tier.yaml | 34 ++++ src/Controller/PriceTierController.php | 244 +++++++++++++++++++++++++ src/Entity/ItemPrice.php | 37 +++- src/Entity/PriceTier.php | 29 ++- src/Entity/SupportedArea.php | 19 ++ templates/price-tier/form.html.twig | 154 ++++++++++++++++ templates/price-tier/list.html.twig | 146 +++++++++++++++ 9 files changed, 713 insertions(+), 18 deletions(-) create mode 100644 config/routes/price_tier.yaml create mode 100644 src/Controller/PriceTierController.php create mode 100644 templates/price-tier/form.html.twig create mode 100644 templates/price-tier/list.html.twig diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index dfaf31e0..9977d263 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -634,6 +634,48 @@ catalyst_auth: - id: service_offering.delete label: Delete + - id: price_tier + label: Price Tier + acls: + - id: price_tier.menu + label: Menu + - id: price_tier.list + label: List + - id: price_tier.add + label: Add + - id: price_tier.update + label: Update + - id: price_tier.delete + label: Delete + + - id: item_type + label: Item Type + acls: + - id: item.type.menu + label: Menu + - id: item.type.list + label: List + - id: item.type.add + label: Add + - id: item.type.update + label: Update + - id: item.type.delete + label: Delete + + - id: item + label: Item + acls: + - id: item.menu + label: Menu + - id: item.list + label: List + - id: item.add + label: Add + - id: item.update + label: Update + - id: item.delete + label: Delete + api: user_entity: "App\\Entity\\ApiUser" acl_data: diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index deb8c43f..a92f2c4e 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -177,7 +177,7 @@ catalyst_menu: acl: support.menu label: '[menu.support]' icon: flaticon-support - order: 10 + order: 11 - id: customer_list acl: customer.list label: '[menu.support.customers]' @@ -223,7 +223,7 @@ catalyst_menu: acl: service.menu label: '[menu.service]' icon: flaticon-squares - order: 11 + order: 12 - id: service_list acl: service.list label: '[menu.service.services]' @@ -233,7 +233,7 @@ catalyst_menu: acl: partner.menu label: '[menu.partner]' icon: flaticon-network - order: 12 + order: 13 - id: partner_list acl: partner.list label: '[menu.partner.partners]' @@ -247,7 +247,7 @@ catalyst_menu: acl: motolite_event.menu label: '[menu.motolite_event]' icon: flaticon-event-calendar-symbol - order: 13 + order: 14 - id: motolite_event_list acl: motolite_event.list label: '[menu.motolite_event.events]' @@ -257,7 +257,7 @@ catalyst_menu: acl: analytics.menu label: '[menu.analytics]' icon: flaticon-graphic - order: 14 + order: 15 - id: analytics_forecast_form acl: analytics.forecast label: '[menu.analytics.forecasting]' @@ -267,7 +267,7 @@ catalyst_menu: acl: database.menu label: '[menu.database]' icon: fa fa-database - order: 15 + order: 16 - id: ticket_type_list acl: ticket_type.menu label: '[menu.database.tickettypes]' @@ -288,3 +288,17 @@ catalyst_menu: acl: service_offering.menu label: '[menu.database.serviceofferings]' parent: database + + - id: item + acl: item.menu + label: Item Management + icon: fa fa-boxes + order: 10 + - id: price_tier_list + acl: price_tier.list + label: Price Tiers + parent: item + - id: item_list + acl: item.list + label: Items + parent: item diff --git a/config/routes/price_tier.yaml b/config/routes/price_tier.yaml new file mode 100644 index 00000000..f0127e12 --- /dev/null +++ b/config/routes/price_tier.yaml @@ -0,0 +1,34 @@ +price_tier_list: + path: /pricetiers + controller: App\Controller\PriceTierController::index + methods: [GET] + +price_tier_rows: + path: /pricetiers/rows + controller: App\Controller\PriceTierController::datatableRows + methods: [POST] + +price_tier_add_form: + path: /pricetiers/newform + controller: App\Controller\PriceTierController::addForm + methods: [GET] + +price_tier_add_submit: + path: /pricetiers + controller: App\Controller\PriceTierController::addSubmit + methods: [POST] + +price_tier_update_form: + path: /pricetiers/{id} + controller: App\Controller\PriceTierController::updateForm + methods: [GET] + +price_tier_update_submit: + path: /pricetiers/{id} + controller: App\Controller\PriceTierController::updateSubmit + methods: [POST] + +price_tier_delete: + path: /pricetiers/{id} + controller: App\Controller\PriceTierController::deleteSubmit + methods: [DELETE] diff --git a/src/Controller/PriceTierController.php b/src/Controller/PriceTierController.php new file mode 100644 index 00000000..cd08f90f --- /dev/null +++ b/src/Controller/PriceTierController.php @@ -0,0 +1,244 @@ +render('price-tier/list.html.twig'); + } + + /** + * @IsGranted("price_tier.list") + */ + public function datatableRows(Request $req) + { + // get query builder + $qb = $this->getDoctrine() + ->getRepository(PriceTier::class) + ->createQueryBuilder('q'); + + // get datatable params + $datatable = $req->request->get('datatable'); + + // count total records + $tquery = $qb->select('COUNT(q)'); + $this->setQueryFilters($datatable, $tquery); + $total = $tquery->getQuery() + ->getSingleScalarResult(); + + // get current page number + $page = $datatable['pagination']['page'] ?? 1; + + $perpage = $datatable['pagination']['perpage']; + $offset = ($page - 1) * $perpage; + + // add metadata + $meta = [ + 'page' => $page, + 'perpage' => $perpage, + 'pages' => ceil($total / $perpage), + 'total' => $total, + 'sort' => 'asc', + 'field' => 'id' + ]; + + // build query + $query = $qb->select('q'); + $this->setQueryFilters($datatable, $query); + + // check if sorting is present, otherwise use default + if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) { + $order = $datatable['sort']['sort'] ?? 'asc'; + $query->orderBy('q.' . $datatable['sort']['field'], $order); + } else { + $query->orderBy('q.id', 'asc'); + } + + // get rows for this page + $obj_rows = $query->setFirstResult($offset) + ->setMaxResults($perpage) + ->getQuery() + ->getResult(); + + // process rows + $rows = []; + foreach ($obj_rows as $orow) { + // add row data + $row['id'] = $orow->getID(); + $row['name'] = $orow->getName(); + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('price_tier.update')) + $row['meta']['update_url'] = $this->generateUrl('price_tier_update_form', ['id' => $row['id']]); + if ($this->isGranted('service_offering.delete')) + $row['meta']['delete_url'] = $this->generateUrl('price_tier_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + /** + * @Menu(selected="price_tier.list") + * @IsGranted("price_tier.add") + */ + public function addForm(EntityManagerInterface $em) + { + $pt = new PriceTier(); + + // get the supported areas + $sets = $this->generateFormSets($em); + + $params = [ + 'obj' => $pt, + 'sets' => $sets, + 'mode' => 'create', + ]; + + // response + return $this->render('price-tier/form.html.twig', $params); + } + + /** + * @IsGranted("price_tier.add") + */ + public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator) + { + $pt = new PriceTier(); + + // TODO: add validation for supported area + $this->setObject($pt, $req); + + // validate + $errors = $validator->validate($pt); + + // initialize error list + $error_array = []; + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // validated! save the entity + $em->persist($pt); + + // set the price tier id for the selected supported areas + $this->updateSupportedAreas($em, $pt, $req); + + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @Menu(selected="price_tier_list") + * @ParamConverter("price_tier", class="App\Entity\PriceTier") + * @IsGranted("price_tier.update") + */ + public function updateForm($id, EntityManagerInterface $em, PriceTier $pt) + { + // get the supported areas + $sets = $this->generateFormSets($em); + + $params = [ + 'obj' => $pt, + 'sets' => $sets, + 'mode' => 'update', + ]; + + // response + return $this->render('price-tier/form.html.twig', $params); + } + + protected function setObject(PriceTier $obj, Request $req) + { + $obj->setName($req->request->get('name')); + } + + public function updateSupportedAreas(EntityManagerInterface $em, PriceTier $obj, Request $req) + { + // get the selected areas + $areas = $req->request->get('areas'); + + foreach ($areas as $area_id) + { + // get supported area + $supported_area = $em->getRepository(SupportedArea::class)->find($area_id); + + if ($supported_area != null) + $supported_area->setPriceTier($obj); + } + } + + protected function generateFormSets(EntityManagerInterface $em) + { + // get the supported areas + // TODO: filter out the supported areas that already have a price tier id? but if we're editing, we need those price tiers + $areas = $em->getRepository(SupportedArea::class)->findAll(); + $areas_set = []; + foreach ($areas as $area) + { + $areas_set[$area->getID()] = $area->getName(); + } + + return [ + 'areas' => $areas_set + ]; + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } +} diff --git a/src/Entity/ItemPrice.php b/src/Entity/ItemPrice.php index d03cadbf..b9f14517 100644 --- a/src/Entity/ItemPrice.php +++ b/src/Entity/ItemPrice.php @@ -20,7 +20,7 @@ class ItemPrice protected $id; /** - * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="items") + * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="item_prices") * @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id") */ protected $price_tier; @@ -44,10 +44,43 @@ class ItemPrice /** * @ORM\Column(type="integer") */ - protected $item_price; + protected $price; public function getID() { return $this->id; } + + public function setPriceTier(PriceTier $price_tier) + { + $this->price_tier = $price_tier; + return $this; + } + + public function getPriceTier() + { + return $this->price_tier; + } + + public function setItemID($item_id) + { + $this->item_id = $item_id; + return $this; + } + + public function getItemID() + { + return $this->item_id; + } + + public function setPrice($price) + { + $this->price = $price; + return $this; + } + + public function getPrice() + { + return $this->price; + } } diff --git a/src/Entity/PriceTier.php b/src/Entity/PriceTier.php index 18b735aa..103b7290 100644 --- a/src/Entity/PriceTier.php +++ b/src/Entity/PriceTier.php @@ -28,21 +28,20 @@ class PriceTier // supported areas under price tier /** - * @ORM\Column(type="json") + * @ORM\OneToMany(targetEntity="SupportedArea", mappedBy="price_tier"); */ - protected $meta_areas; + protected $supported_areas; // items under a price tier /** * @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="price_tier") */ - protected $items; + protected $item_prices; public function __construct() { - $this->meta_areas = []; - - $this->items = new ArrayCollection(); + $this->supported_areas = new ArrayCollection(); + $this->item_prices = new ArrayCollection(); } public function getID() @@ -61,13 +60,23 @@ class PriceTier return $this->name; } - public function addMetaArea($id, $value) + public function getSupportedAreaObjects() { - $this->meta_areas[$id] = $value; + return $this->supported_areas; } - public function getAllMetaAreas() + public function getSupportedAreas() { - return $this->meta_areas; + $str_supported_areas = []; + foreach ($this->supported_areas as $supported_area) + $str_supported_areas[] = $supported_area->getID(); + + return $str_supported_areas; } + + public function getItemPrices() + { + return $this->item_prices; + } + } diff --git a/src/Entity/SupportedArea.php b/src/Entity/SupportedArea.php index 0f70c39e..67d53ed8 100644 --- a/src/Entity/SupportedArea.php +++ b/src/Entity/SupportedArea.php @@ -39,9 +39,17 @@ class SupportedArea */ protected $coverage_area; + /** + * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="supported_areas") + * @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id", nullable=true) + */ + protected $price_tier; + public function __construct() { $this->date_create = new DateTime(); + + $this->price_tier = null; } public function getID() @@ -82,5 +90,16 @@ class SupportedArea { return $this->coverage_area; } + + public function setPriceTier(PriceTier $price_tier) + { + $this->price_tier = $price_tier; + return $this; + } + + public function getPriceTier() + { + return $this->price_tier; + } } diff --git a/templates/price-tier/form.html.twig b/templates/price-tier/form.html.twig new file mode 100644 index 00000000..105d7ec2 --- /dev/null +++ b/templates/price-tier/form.html.twig @@ -0,0 +1,154 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

Price Tiers

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

+ {% if mode == 'update' %} + Edit Price Tier + {{ obj.getName() }} + {% else %} + New Price Tier + {% endif %} +

+
+
+
+
+
+
+ +
+ + +
+
+
+ +
+ {% if sets.areas is empty %} + No supported areas. + {% else %} +
+ {% for id, label in sets.areas %} + + {% endfor %} +
+ {% endif %} + +
+
+
+
+
+
+
+ + Back +
+
+
+
+
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/price-tier/list.html.twig b/templates/price-tier/list.html.twig new file mode 100644 index 00000000..e97eed40 --- /dev/null +++ b/templates/price-tier/list.html.twig @@ -0,0 +1,146 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Price Tiers +

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} -- 2.43.5 From 8c810bf27a86c4b27f6f740e8c93762d1787e410 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 21 Dec 2023 16:24:37 +0800 Subject: [PATCH 031/119] Add validation and deletion for price tier. #780 --- src/Controller/PriceTierController.php | 143 ++++++++++++++++++++++--- src/Entity/PriceTier.php | 6 ++ src/Entity/SupportedArea.php | 2 +- 3 files changed, 134 insertions(+), 17 deletions(-) diff --git a/src/Controller/PriceTierController.php b/src/Controller/PriceTierController.php index cd08f90f..b44a6bb8 100644 --- a/src/Controller/PriceTierController.php +++ b/src/Controller/PriceTierController.php @@ -139,17 +139,18 @@ class PriceTierController extends Controller */ public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator) { + // initialize error list + $error_array = []; + $pt = new PriceTier(); - // TODO: add validation for supported area + $error_array = $this->validateRequest($em, $req); + $this->setObject($pt, $req); // validate $errors = $validator->validate($pt); - // initialize error list - $error_array = []; - // add errors to list foreach ($errors as $error) { $error_array[$error->getPropertyPath()] = $error->getMessage(); @@ -180,13 +181,13 @@ class PriceTierController extends Controller /** * @Menu(selected="price_tier_list") - * @ParamConverter("price_tier", class="App\Entity\PriceTier") + * @ParamConverter("pt", class="App\Entity\PriceTier") * @IsGranted("price_tier.update") */ public function updateForm($id, EntityManagerInterface $em, PriceTier $pt) { // get the supported areas - $sets = $this->generateFormSets($em); + $sets = $this->generateFormSets($em, $pt); $params = [ 'obj' => $pt, @@ -198,31 +199,141 @@ class PriceTierController extends Controller return $this->render('price-tier/form.html.twig', $params); } + /** + * @ParamConverter("pt", class="App\Entity\PriceTier") + * @IsGranted("price_tier.update") + */ + public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, PriceTier $pt) + { + // initialize error list + $error_array = []; + + // clear supported areas of price tier + $this->clearPriceTierSupportedAreas($em, $pt); + + $error_array = $this->validateRequest($em, $req); + $this->setObject($pt, $req); + + // validate + $errors = $validator->validate($pt); + + // 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); + } + + // set the price tier id for the selected supported areas + $this->updateSupportedAreas($em, $pt, $req); + + // validated! save the entity + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @ParamConverter("pt", class="App\Entity\PriceTier") + * @IsGranted("price_tier.delete") + */ + public function deleteSubmit(EntityManagerInterface $em, PriceTier $pt) + { + // clear supported areas of price tier + $this->clearPriceTierSupportedAreas($em, $pt); + + // delete this object + $em->remove($pt); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } + + protected function validateRequest(EntityManagerInterface $em, Request $req) + { + // get areas + $areas = $req->request->get('areas'); + + // check if no areas selected aka empty + if (!empty($areas)) + { + foreach ($areas as $area_id) + { + $supported_area = $em->getRepository(SupportedArea::class)->find($area_id); + + if ($supported_area == null) + return ['areas' => 'Invalid area']; + + // check if supported area already belongs to a price tier + if ($supported_area->getPriceTier() != null) + return ['areas' => 'Area already belongs to a price tier.']; + } + } + + return null; + } + protected function setObject(PriceTier $obj, Request $req) { + // clear supported areas first + $obj->clearSupportedAreas(); + $obj->setName($req->request->get('name')); } - public function updateSupportedAreas(EntityManagerInterface $em, PriceTier $obj, Request $req) + protected function clearPriceTierSupportedAreas(EntityManagerInterface $em, PriceTier $obj) + { + // find the supported areas set with the price tier + $areas = $em->getRepository(SupportedArea::class)->findBy(['price_tier' => $obj]); + + if (!empty($areas)) + { + // set the price tier id for the supported areas to null + foreach ($areas as $area) + { + $area->setPriceTier(null); + } + + $em->flush(); + } + } + + protected function updateSupportedAreas(EntityManagerInterface $em, PriceTier $obj, Request $req) { // get the selected areas $areas = $req->request->get('areas'); - foreach ($areas as $area_id) + // check if no areas selected aka empty + if (!empty($areas)) { - // get supported area - $supported_area = $em->getRepository(SupportedArea::class)->find($area_id); + foreach ($areas as $area_id) + { + // get supported area + $supported_area = $em->getRepository(SupportedArea::class)->find($area_id); - if ($supported_area != null) - $supported_area->setPriceTier($obj); + if ($supported_area != null) + $supported_area->setPriceTier($obj); + } } } - protected function generateFormSets(EntityManagerInterface $em) + protected function generateFormSets(EntityManagerInterface $em, PriceTier $pt = null) { - // get the supported areas - // TODO: filter out the supported areas that already have a price tier id? but if we're editing, we need those price tiers - $areas = $em->getRepository(SupportedArea::class)->findAll(); + // get the supported areas with no price tier id or price tier id is set to the one that is being updated + $areas = $em->getRepository(SupportedArea::class)->findBy(['price_tier' => array(null, $pt)]); $areas_set = []; foreach ($areas as $area) { diff --git a/src/Entity/PriceTier.php b/src/Entity/PriceTier.php index 103b7290..37c8d8f8 100644 --- a/src/Entity/PriceTier.php +++ b/src/Entity/PriceTier.php @@ -74,6 +74,12 @@ class PriceTier return $str_supported_areas; } + public function clearSupportedAreas() + { + $this->supported_areas->clear(); + return $this; + } + public function getItemPrices() { return $this->item_prices; diff --git a/src/Entity/SupportedArea.php b/src/Entity/SupportedArea.php index 67d53ed8..0e176f6a 100644 --- a/src/Entity/SupportedArea.php +++ b/src/Entity/SupportedArea.php @@ -91,7 +91,7 @@ class SupportedArea return $this->coverage_area; } - public function setPriceTier(PriceTier $price_tier) + public function setPriceTier(PriceTier $price_tier = null) { $this->price_tier = $price_tier; return $this; -- 2.43.5 From 58f46fd5bf90c236e7fdbc4984c68567800f7f12 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 21 Dec 2023 23:23:46 -0500 Subject: [PATCH 032/119] Add route and CRUD for item type. #780 --- config/packages/catalyst_auth.yaml | 10 +- config/packages/catalyst_menu.yaml | 4 + config/routes/item_type.yaml | 34 ++++ config/routes/price_tier.yaml | 14 +- src/Controller/ItemTypeController.php | 251 ++++++++++++++++++++++++++ templates/item-type/form.html.twig | 142 +++++++++++++++ templates/item-type/list.html.twig | 146 +++++++++++++++ translations/messages.en.yaml | 1 + 8 files changed, 590 insertions(+), 12 deletions(-) create mode 100644 config/routes/item_type.yaml create mode 100644 src/Controller/ItemTypeController.php create mode 100644 templates/item-type/form.html.twig create mode 100644 templates/item-type/list.html.twig diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index 9977d263..f63c5bc0 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -651,15 +651,15 @@ catalyst_auth: - id: item_type label: Item Type acls: - - id: item.type.menu + - id: item_type.menu label: Menu - - id: item.type.list + - id: item_type.list label: List - - id: item.type.add + - id: item_type.add label: Add - - id: item.type.update + - id: item_type.update label: Update - - id: item.type.delete + - id: item_type.delete label: Delete - id: item diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index a92f2c4e..1c4f7417 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -288,6 +288,10 @@ catalyst_menu: acl: service_offering.menu label: '[menu.database.serviceofferings]' parent: database + - id: item_type_list + acl: item_type.menu + label: '[menu.database.itemtypes]' + parent: database - id: item acl: item.menu diff --git a/config/routes/item_type.yaml b/config/routes/item_type.yaml new file mode 100644 index 00000000..adaa8dee --- /dev/null +++ b/config/routes/item_type.yaml @@ -0,0 +1,34 @@ +item_type_list: + path: /item-types + controller: App\Controller\ItemTypeController::index + methods: [GET] + +item_type_rows: + path: /item-types/rowdata + controller: App\Controller\ItemTypeController::datatableRows + methods: [POST] + +item_type_add_form: + path: /item-types/newform + controller: App\Controller\ItemTypeController::addForm + methods: [GET] + +item_type_add_submit: + path: /item-types + controller: App\Controller\ItemTypeController::addSubmit + methods: [POST] + +item_type_update_form: + path: /item-types/{id} + controller: App\Controller\ItemTypeController::updateForm + methods: [GET] + +item_type_update_submit: + path: /item-types/{id} + controller: App\Controller\ItemTypeController::updateSubmit + methods: [POST] + +item_type_delete: + path: /item-types/{id} + controller: App\Controller\ItemTypeController::deleteSubmit + methods: [DELETE] diff --git a/config/routes/price_tier.yaml b/config/routes/price_tier.yaml index f0127e12..397858d9 100644 --- a/config/routes/price_tier.yaml +++ b/config/routes/price_tier.yaml @@ -1,34 +1,34 @@ price_tier_list: - path: /pricetiers + path: /price-tiers controller: App\Controller\PriceTierController::index methods: [GET] price_tier_rows: - path: /pricetiers/rows + path: /price-tiers/rows controller: App\Controller\PriceTierController::datatableRows methods: [POST] price_tier_add_form: - path: /pricetiers/newform + path: /price-tiers/newform controller: App\Controller\PriceTierController::addForm methods: [GET] price_tier_add_submit: - path: /pricetiers + path: /price-tiers controller: App\Controller\PriceTierController::addSubmit methods: [POST] price_tier_update_form: - path: /pricetiers/{id} + path: /price-tiers/{id} controller: App\Controller\PriceTierController::updateForm methods: [GET] price_tier_update_submit: - path: /pricetiers/{id} + path: /price-tiers/{id} controller: App\Controller\PriceTierController::updateSubmit methods: [POST] price_tier_delete: - path: /pricetiers/{id} + path: /price-tiers/{id} controller: App\Controller\PriceTierController::deleteSubmit methods: [DELETE] diff --git a/src/Controller/ItemTypeController.php b/src/Controller/ItemTypeController.php new file mode 100644 index 00000000..c7c1b110 --- /dev/null +++ b/src/Controller/ItemTypeController.php @@ -0,0 +1,251 @@ +render('item-type/list.html.twig'); + } + + /** + * @IsGranted("item_type.list") + */ + public function datatableRows(Request $req) + { + // get query builder + $qb = $this->getDoctrine() + ->getRepository(ItemType::class) + ->createQueryBuilder('q'); + + // get datatable params + $datatable = $req->request->get('datatable'); + + // count total records + $tquery = $qb->select('COUNT(q)'); + $this->setQueryFilters($datatable, $tquery); + $total = $tquery->getQuery() + ->getSingleScalarResult(); + + // get current page number + $page = $datatable['pagination']['page'] ?? 1; + + $perpage = $datatable['pagination']['perpage']; + $offset = ($page - 1) * $perpage; + + // add metadata + $meta = [ + 'page' => $page, + 'perpage' => $perpage, + 'pages' => ceil($total / $perpage), + 'total' => $total, + 'sort' => 'asc', + 'field' => 'id' + ]; + + // build query + $query = $qb->select('q'); + $this->setQueryFilters($datatable, $query); + + // check if sorting is present, otherwise use default + if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) { + $order = $datatable['sort']['sort'] ?? 'asc'; + $query->orderBy('q.' . $datatable['sort']['field'], $order); + } else { + $query->orderBy('q.id', 'asc'); + } + + // get rows for this page + $obj_rows = $query->setFirstResult($offset) + ->setMaxResults($perpage) + ->getQuery() + ->getResult(); + + // process rows + $rows = []; + foreach ($obj_rows as $orow) { + // add row data + $row['id'] = $orow->getID(); + $row['name'] = $orow->getName(); + + // add row metadata + $row['meta'] = [ + 'update_url' => '', + 'delete_url' => '' + ]; + + // add crud urls + if ($this->isGranted('item_type.update')) + $row['meta']['update_url'] = $this->generateUrl('item_type_update_form', ['id' => $row['id']]); + if ($this->isGranted('item_type.delete')) + $row['meta']['delete_url'] = $this->generateUrl('item_type_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + /** + * @Menu(selected="item_type.list") + * @IsGranted("item_type.add") + */ + public function addForm() + { + $item_type = new ItemType(); + $params = [ + 'obj' => $item_type, + 'mode' => 'create', + ]; + + // response + return $this->render('item-type/form.html.twig', $params); + } + + /** + * @IsGranted("item_type.add") + */ + public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator) + { + $item_type = new ItemType(); + + $this->setObject($item_type, $req); + + // validate + $errors = $validator->validate($item_type); + + // initialize error list + $error_array = []; + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // validated! save the entity + $em->persist($item_type); + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @Menu(selected="item_type_list") + * @ParamConverter("item_type", class="App\Entity\ItemType") + * @IsGranted("item_type.update") + */ + public function updateForm($id, EntityManagerInterface $em, ItemType $item_type) + { + $params = []; + $params['obj'] = $item_type; + $params['mode'] = 'update'; + + // response + return $this->render('item-type/form.html.twig', $params); + } + + /** + * @ParamConverter("item_type", class="App\Entity\ItemType") + * @IsGranted("item_type.update") + */ + public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, ItemType $item_type) + { + $this->setObject($item_type, $req); + + // validate + $errors = $validator->validate($item_type); + + // initialize error list + $error_array = []; + + // add errors to list + foreach ($errors as $error) { + $error_array[$error->getPropertyPath()] = $error->getMessage(); + } + + // check if any errors were found + if (!empty($error_array)) { + // return validation failure response + return $this->json([ + 'success' => false, + 'errors' => $error_array + ], 422); + } + + // validated! save the entity + $em->flush(); + + // return successful response + return $this->json([ + 'success' => 'Changes have been saved!' + ]); + } + + /** + * @ParamConverter("item_type", class="App\Entity\ItemType") + * @IsGranted("item_type.delete") + */ + public function deleteSubmit(EntityManagerInterface $em, ItemType $item_type) + { + // delete this object + $em->remove($item_type); + $em->flush(); + + // response + $response = new Response(); + $response->setStatusCode(Response::HTTP_OK); + $response->send(); + } + + + protected function setObject(ItemType $obj, Request $req) + { + // set and save values + $obj->setName($req->request->get('name')) + ->setCode($req->request->get('code')); + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } +} diff --git a/templates/item-type/form.html.twig b/templates/item-type/form.html.twig new file mode 100644 index 00000000..97d0d9ec --- /dev/null +++ b/templates/item-type/form.html.twig @@ -0,0 +1,142 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

Item Types

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

+ {% if mode == 'update' %} + Edit Item Type + {{ obj.getName() }} + {% else %} + New Item Type + {% endif %} +

+
+
+
+
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + Back +
+
+
+
+
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/item-type/list.html.twig b/templates/item-type/list.html.twig new file mode 100644 index 00000000..cc11e81d --- /dev/null +++ b/templates/item-type/list.html.twig @@ -0,0 +1,146 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

+ Item Types +

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/translations/messages.en.yaml b/translations/messages.en.yaml index 7278212d..8387663e 100644 --- a/translations/messages.en.yaml +++ b/translations/messages.en.yaml @@ -159,6 +159,7 @@ menu.database.subtickettypes: 'Sub Ticket Types' menu.database.emergencytypes: 'Emergency Types' menu.database.ownershiptypes: 'Ownership Types' menu.database.serviceofferings: 'Service Offerings' +menu.database.itemtypes: 'Item Types' # fcm jo status updates jo_fcm_title_outlet_assign: 'Looking for riders' -- 2.43.5 From 5ee41dab327f66fb38930c321366bd5c4c0a95fd Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Fri, 22 Dec 2023 15:30:11 +0800 Subject: [PATCH 033/119] Increase motolite event name field size to 255 #781 --- src/Entity/MotoliteEvent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entity/MotoliteEvent.php b/src/Entity/MotoliteEvent.php index ccdb367b..4c8df366 100644 --- a/src/Entity/MotoliteEvent.php +++ b/src/Entity/MotoliteEvent.php @@ -21,7 +21,7 @@ class MotoliteEvent protected $id; /** - * @ORM\Column(type="string", length=80) + * @ORM\Column(type="string", length=255) * @Assert\NotBlank() */ protected $name; -- 2.43.5 From e4ffcc0c9dcd199bcb46c0a983fdc40a7fe7c136 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Dec 2023 22:15:44 -0500 Subject: [PATCH 034/119] Add controller for item pricing. #780 --- config/packages/catalyst_auth.yaml | 5 + config/packages/catalyst_menu.yaml | 4 + config/routes/item_pricing.yaml | 14 +++ src/Controller/ItemPricingController.php | 76 +++++++++++++ templates/item-pricing/form.html.twig | 129 +++++++++++++++++++++++ 5 files changed, 228 insertions(+) create mode 100644 config/routes/item_pricing.yaml create mode 100644 src/Controller/ItemPricingController.php create mode 100644 templates/item-pricing/form.html.twig diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index f63c5bc0..7e02d5c0 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -675,6 +675,11 @@ catalyst_auth: label: Update - id: item.delete label: Delete + - id: item_pricing + label: Item Pricing + acls: + - id: item_pricing.update + label: Update api: user_entity: "App\\Entity\\ApiUser" diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index 1c4f7417..c861471d 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -302,6 +302,10 @@ catalyst_menu: acl: price_tier.list label: Price Tiers parent: item + - id: item_pricing + acl: item_pricing.update + label: Item Pricing + parent: item - id: item_list acl: item.list label: Items diff --git a/config/routes/item_pricing.yaml b/config/routes/item_pricing.yaml new file mode 100644 index 00000000..df289902 --- /dev/null +++ b/config/routes/item_pricing.yaml @@ -0,0 +1,14 @@ +item_pricing: + path: /item-pricing + controller: App\Controller\ItemPricingController::index + methods: [GET] + +item_pricing_update: + path: /item-pricing + controller: App\Controller\ItemPricingController::formSubmit + methods: [POST] + +item_pricing_prices: + path: /item-pricing/{id}/prices + controller: App\Controller\ItemPricingController::itemPrices + methods: [GET] diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php new file mode 100644 index 00000000..9aba9f68 --- /dev/null +++ b/src/Controller/ItemPricingController.php @@ -0,0 +1,76 @@ +getRepository(PriceTier::class)->findAll(); + + // get all the items/batteries + $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); + + $params = [ + 'sets' => [ + 'price_tiers' => $price_tiers + ], + 'items' => $items, + ]; + + return $this->render('item-pricing/form.html.twig', $params); + } + + /** + * @Menu(selected="item_pricing") + * @IsGranted("item_pricing.update") + */ + public function formSubmit(Request $req, EntityManagerInterface $em) + { + } + + /** + * @IsGranted("item_pricing.update") + */ + public function (EntityManagerInterface $em, $id) + { + $pt_prices = []; + // check if default prices are needed + if ($id != 0) + { + // get the price tier prices + } + else + { + // get the prices from battery + } + + $data_items = []; + + // response + return new JsonResponse([ + 'items' => $data_items, + ]); + } + diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig new file mode 100644 index 00000000..cde71ae6 --- /dev/null +++ b/templates/item-pricing/form.html.twig @@ -0,0 +1,129 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

Item Pricing

+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+ + + + + + + + + + {% for item in items %} + + + + + + {% endfor %} + +
IDNamePrice
{{ item.getID }}{{ item.getModel.getName ~ ' ' ~ item.getSize.getName}} + +
+
+ +
+
+
+
+
+
+
+
+{% endblock %} + +{% block js_end %} + +{% endblock %} -- 2.43.5 From 01e4baa8c4473775899d78c43155ffad6f155fa6 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Dec 2023 20:41:44 -0500 Subject: [PATCH 035/119] Add item price controller. #780 --- config/packages/catalyst_auth.yaml | 14 +-- config/packages/catalyst_menu.yaml | 4 +- config/routes/item_price.yaml | 34 ++++++ src/Controller/ItemPriceController.php | 126 +++++++++++++++++++++++ src/Controller/ItemPricingController.php | 13 ++- 5 files changed, 179 insertions(+), 12 deletions(-) create mode 100644 config/routes/item_price.yaml create mode 100644 src/Controller/ItemPriceController.php diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index 7e02d5c0..e03cdc32 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -662,18 +662,18 @@ catalyst_auth: - id: item_type.delete label: Delete - - id: item - label: Item + - id: item_price + label: Item Price acls: - - id: item.menu + - id: item_price.menu label: Menu - - id: item.list + - id: item_price.list label: List - - id: item.add + - id: item_price.add label: Add - - id: item.update + - id: item_price.update label: Update - - id: item.delete + - id: item_price.delete label: Delete - id: item_pricing label: Item Pricing diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index c861471d..83f7e852 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -306,7 +306,7 @@ catalyst_menu: acl: item_pricing.update label: Item Pricing parent: item - - id: item_list - acl: item.list + - id: item_price_list + acl: item_price.list label: Items parent: item diff --git a/config/routes/item_price.yaml b/config/routes/item_price.yaml new file mode 100644 index 00000000..607dc3cd --- /dev/null +++ b/config/routes/item_price.yaml @@ -0,0 +1,34 @@ +item_price_list: + path: /items + controller: App\Controller\ItemPriceController::index + methods: [GET] + +item_price_rows: + path: /items/rowdata + controller: App\Controller\ItemPriceController::datatableRows + methods: [POST] + +item_price_add_form: + path: /items/newform + controller: App\Controller\ItemPriceController::addForm + methods: [GET] + +item_price_add_submit: + path: /items + controller: App\Controller\ItemPriceController::addSubmit + methods: [POST] + +item_price_update_form: + path: /items/{id} + controller: App\Controller\ItemPriceController::updateForm + methods: [GET] + +item_price_update_submit: + path: /items/{id} + controller: App\Controller\ItemPriceController::updateSubmit + methods: [POST] + +item_price_delete: + path: /items/{id} + controller: App\Controller\ItemPriceController::deleteSubmit + methods: [DELETE] diff --git a/src/Controller/ItemPriceController.php b/src/Controller/ItemPriceController.php new file mode 100644 index 00000000..0a41994c --- /dev/null +++ b/src/Controller/ItemPriceController.php @@ -0,0 +1,126 @@ +render('item-price/list.html.twig'); + } + + /** + * @IsGranted("item_price.list") + */ + public function datatableRows(Request $req) + { + // get query builder + $qb = $this->getDoctrine() + ->getRepository(ItemPrice::class) + ->createQueryBuilder('q'); + + // get datatable params + $datatable = $req->request->get('datatable'); + + // count total records + $tquery = $qb->select('COUNT(q)') + ->innerJoin('q.battery', 'b', 'WITH', 'b.id = q.item_id') + ->innerJoin('q.service_offering', 'so', 'WITH', 'so.id = q.item_id'); + $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') + ->innerJoin('q.battery', 'b', 'WITH', 'b.id = q.item_id') + ->innerJoin('q.service_offering', 'so', 'WITH', 'so.id = q.item_id'); + $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('item_price.update')) + $row['meta']['update_url'] = $this->generateUrl('item_price_update_form', ['id' => $row['id']]); + if ($this->isGranted('item_price.delete')) + $row['meta']['delete_url'] = $this->generateUrl('item_price_delete', ['id' => $row['id']]); + + $rows[] = $row; + } + + // response + return $this->json([ + 'meta' => $meta, + 'data' => $rows + ]); + } + + protected function setQueryFilters($datatable, QueryBuilder $query) + { + if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) { + $query->where('q.name LIKE :filter') + ->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%'); + } + } +} diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index 9aba9f68..ddfd60bf 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -53,13 +53,20 @@ class ItemPricingController extends Controller /** * @IsGranted("item_pricing.update") */ - public function (EntityManagerInterface $em, $id) + public function itemPrices(EntityManagerInterface $em, $id) { $pt_prices = []; // check if default prices are needed if ($id != 0) { - // get the price tier prices + // get the price tier + $pt = $em->getRepository(PriceTier::class)->find($id); + + // get the item prices under the price tier + $pt_item_prices = $pt->getItemPrices(); + foreach ($pt_item_prices as $pt_item_price) + { + } } else { @@ -73,4 +80,4 @@ class ItemPricingController extends Controller 'items' => $data_items, ]); } - +} -- 2.43.5 From 80b9f903247d4d05ccc80161ecbe9e6f0f2e63b6 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Sat, 30 Dec 2023 23:09:27 -0500 Subject: [PATCH 036/119] Rename ItemPriceController to ItemController. #780 --- config/packages/catalyst_auth.yaml | 14 +- config/packages/catalyst_menu.yaml | 6 +- config/routes/item.yaml | 34 ++++ config/routes/item_price.yaml | 34 ---- ...PriceController.php => ItemController.php} | 16 +- src/Entity/{ItemPrice.php => Item.php} | 19 ++- src/Entity/ItemType.php | 11 ++ src/Entity/PriceTier.php | 10 +- templates/item/form.html.twig | 142 +++++++++++++++++ templates/item/list.html.twig | 146 ++++++++++++++++++ templates/price-tier/form.html.twig | 2 +- 11 files changed, 373 insertions(+), 61 deletions(-) create mode 100644 config/routes/item.yaml delete mode 100644 config/routes/item_price.yaml rename src/Controller/{ItemPriceController.php => ItemController.php} (90%) rename src/Entity/{ItemPrice.php => Item.php} (83%) create mode 100644 templates/item/form.html.twig create mode 100644 templates/item/list.html.twig diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index e03cdc32..7e02d5c0 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -662,18 +662,18 @@ catalyst_auth: - id: item_type.delete label: Delete - - id: item_price - label: Item Price + - id: item + label: Item acls: - - id: item_price.menu + - id: item.menu label: Menu - - id: item_price.list + - id: item.list label: List - - id: item_price.add + - id: item.add label: Add - - id: item_price.update + - id: item.update label: Update - - id: item_price.delete + - id: item.delete label: Delete - id: item_pricing label: Item Pricing diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index 83f7e852..a6bd1583 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -297,7 +297,7 @@ catalyst_menu: acl: item.menu label: Item Management icon: fa fa-boxes - order: 10 + order: 10 - id: price_tier_list acl: price_tier.list label: Price Tiers @@ -306,7 +306,7 @@ catalyst_menu: acl: item_pricing.update label: Item Pricing parent: item - - id: item_price_list - acl: item_price.list + - id: item_list + acl: item.list label: Items parent: item diff --git a/config/routes/item.yaml b/config/routes/item.yaml new file mode 100644 index 00000000..89dde4d2 --- /dev/null +++ b/config/routes/item.yaml @@ -0,0 +1,34 @@ +item_list: + path: /items + controller: App\Controller\ItemController::index + methods: [GET] + +item_rows: + path: /items/rowdata + controller: App\Controller\ItemController::datatableRows + methods: [POST] + +item_add_form: + path: /items/newform + controller: App\Controller\ItemController::addForm + methods: [GET] + +item_add_submit: + path: /items + controller: App\Controller\ItemController::addSubmit + methods: [POST] + +item_update_form: + path: /items/{id} + controller: App\Controller\ItemController::updateForm + methods: [GET] + +item_update_submit: + path: /items/{id} + controller: App\Controller\ItemController::updateSubmit + methods: [POST] + +item_delete: + path: /items/{id} + controller: App\Controller\ItemController::deleteSubmit + methods: [DELETE] diff --git a/config/routes/item_price.yaml b/config/routes/item_price.yaml deleted file mode 100644 index 607dc3cd..00000000 --- a/config/routes/item_price.yaml +++ /dev/null @@ -1,34 +0,0 @@ -item_price_list: - path: /items - controller: App\Controller\ItemPriceController::index - methods: [GET] - -item_price_rows: - path: /items/rowdata - controller: App\Controller\ItemPriceController::datatableRows - methods: [POST] - -item_price_add_form: - path: /items/newform - controller: App\Controller\ItemPriceController::addForm - methods: [GET] - -item_price_add_submit: - path: /items - controller: App\Controller\ItemPriceController::addSubmit - methods: [POST] - -item_price_update_form: - path: /items/{id} - controller: App\Controller\ItemPriceController::updateForm - methods: [GET] - -item_price_update_submit: - path: /items/{id} - controller: App\Controller\ItemPriceController::updateSubmit - methods: [POST] - -item_price_delete: - path: /items/{id} - controller: App\Controller\ItemPriceController::deleteSubmit - methods: [DELETE] diff --git a/src/Controller/ItemPriceController.php b/src/Controller/ItemController.php similarity index 90% rename from src/Controller/ItemPriceController.php rename to src/Controller/ItemController.php index 0a41994c..07e66df1 100644 --- a/src/Controller/ItemPriceController.php +++ b/src/Controller/ItemController.php @@ -14,31 +14,31 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; use App\Entity\ItemType; -use App\Entity\ItemPrice; +use App\Entity\Item; use App\Entity\Battery; use App\Entity\ServiceOffering; use Catalyst\MenuBundle\Annotation\Menu; -class ItemPriceController extends Controller +class ItemController extends Controller { /** - * @Menu(selected="item_price_list") - * @IsGranted("item_price.list") + * @Menu(selected="item_list") + * @IsGranted("item.list") */ public function index () { - return $this->render('item-price/list.html.twig'); + return $this->render('item/list.html.twig'); } /** - * @IsGranted("item_price.list") + * @IsGranted("item.list") */ public function datatableRows(Request $req) { // get query builder $qb = $this->getDoctrine() - ->getRepository(ItemPrice::class) + ->getRepository(Item::class) ->createQueryBuilder('q'); // get datatable params @@ -118,6 +118,8 @@ class ItemPriceController extends Controller protected function setQueryFilters($datatable, QueryBuilder $query) { + // TODO: add filter for item type. + // TODO: fix filter for name since name is with the associated entity 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/Entity/ItemPrice.php b/src/Entity/Item.php similarity index 83% rename from src/Entity/ItemPrice.php rename to src/Entity/Item.php index b9f14517..2e5ed091 100644 --- a/src/Entity/ItemPrice.php +++ b/src/Entity/Item.php @@ -6,10 +6,10 @@ use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity - * @ORM\Table(name="item_price") + * @ORM\Table(name="item") */ -class ItemPrice +class Item { // unique id /** @@ -20,14 +20,14 @@ class ItemPrice protected $id; /** - * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="item_prices") + * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="items") * @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id") */ protected $price_tier; // item type /** - * @ORM\ManyToOne(targetEntity="ItemType", inversedBy="item_prices") + * @ORM\ManyToOne(targetEntity="ItemType", inversedBy="items") * @ORM\JoinColumn(name="item_type_id", referencedColumnName="id") */ protected $item_type; @@ -62,6 +62,17 @@ class ItemPrice return $this->price_tier; } + public function setItemType(ItemType $item_type) + { + $this->item_type = $item_type; + return $this; + } + + public function getItemType() + { + return $this->item_type; + } + public function setItemID($item_id) { $this->item_id = $item_id; diff --git a/src/Entity/ItemType.php b/src/Entity/ItemType.php index 204fb9b3..3ef422d8 100644 --- a/src/Entity/ItemType.php +++ b/src/Entity/ItemType.php @@ -35,6 +35,12 @@ class ItemType */ protected $code; + // items under an item type + /** + * @ORM\OneToMany(targetEntity="Item", mappedBy="item_type") + */ + protected $items; + public function __construct() { $this->code = ''; @@ -66,4 +72,9 @@ class ItemType { return $this->code; } + + public function getItems() + { + return $this->items; + } } diff --git a/src/Entity/PriceTier.php b/src/Entity/PriceTier.php index 37c8d8f8..d929fc8f 100644 --- a/src/Entity/PriceTier.php +++ b/src/Entity/PriceTier.php @@ -34,14 +34,14 @@ class PriceTier // items under a price tier /** - * @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="price_tier") + * @ORM\OneToMany(targetEntity="Item", mappedBy="price_tier") */ - protected $item_prices; + protected $items; public function __construct() { $this->supported_areas = new ArrayCollection(); - $this->item_prices = new ArrayCollection(); + $this->items = new ArrayCollection(); } public function getID() @@ -80,9 +80,9 @@ class PriceTier return $this; } - public function getItemPrices() + public function getItems() { - return $this->item_prices; + return $this->items; } } diff --git a/templates/item/form.html.twig b/templates/item/form.html.twig new file mode 100644 index 00000000..97d0d9ec --- /dev/null +++ b/templates/item/form.html.twig @@ -0,0 +1,142 @@ +{% extends 'base.html.twig' %} + +{% block body %} + +
+
+
+

Item Types

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

+ {% if mode == 'update' %} + Edit Item Type + {{ obj.getName() }} + {% else %} + New Item Type + {% endif %} +

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

+ Items +

+
+
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/price-tier/form.html.twig b/templates/price-tier/form.html.twig index 105d7ec2..0056cdc8 100644 --- a/templates/price-tier/form.html.twig +++ b/templates/price-tier/form.html.twig @@ -49,7 +49,7 @@
{% if sets.areas is empty %} - No supported areas. + No available supported areas. {% else %}
{% for id, label in sets.areas %} -- 2.43.5 From c17be92f0a9d24c7e5541345a9f7e6f659d26996 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Sun, 31 Dec 2023 00:46:12 -0500 Subject: [PATCH 037/119] Fix errors for item query. #780 --- src/Controller/ItemController.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Controller/ItemController.php b/src/Controller/ItemController.php index 07e66df1..88cc769c 100644 --- a/src/Controller/ItemController.php +++ b/src/Controller/ItemController.php @@ -5,6 +5,7 @@ namespace App\Controller; use Doctrine\ORM\Query; use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query\Expr\Join; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -37,7 +38,7 @@ class ItemController extends Controller public function datatableRows(Request $req) { // get query builder - $qb = $this->getDoctrine() + $total_qb = $this->getDoctrine() ->getRepository(Item::class) ->createQueryBuilder('q'); @@ -45,9 +46,9 @@ class ItemController extends Controller $datatable = $req->request->get('datatable'); // count total records - $tquery = $qb->select('COUNT(q)') - ->innerJoin('q.battery', 'b', 'WITH', 'b.id = q.item_id') - ->innerJoin('q.service_offering', 'so', 'WITH', 'so.id = q.item_id'); + $tquery = $total_qb->select('COUNT(q)') + ->leftJoin(Battery::class, 'battery', Join::WITH, 'battery.id = q.item_id') + ->leftJoin(ServiceOffering::class, 'so', Join::WITH, 'so.id = q.item_id'); $this->setQueryFilters($datatable, $tquery); $total = $tquery->getQuery() ->getSingleScalarResult(); @@ -68,10 +69,15 @@ class ItemController extends Controller 'field' => 'id' ]; + // reset query builder + $qb = $this->getDoctrine() + ->getRepository(Item::class) + ->createQueryBuilder('q'); + // build query $query = $qb->select('q') - ->innerJoin('q.battery', 'b', 'WITH', 'b.id = q.item_id') - ->innerJoin('q.service_offering', 'so', 'WITH', 'so.id = q.item_id'); + ->leftJoin(Battery::class, 'battery', Join::WITH, 'battery.id = q.item_id') + ->leftJoin(ServiceOffering::class, 'so', Join::WITH, 'so.id = q.item_id'); $this->setQueryFilters($datatable, $query); // check if sorting is present, otherwise use default -- 2.43.5 From f65ca190107f7bb70052cdce0ae65671257d2e6d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 9 Jan 2024 17:39:29 +0800 Subject: [PATCH 038/119] Load service offering into Item Pricing page. #780 --- config/routes/item_pricing.yaml | 2 +- src/Controller/ItemController.php | 54 ++++++++++++++++++++ src/Controller/ItemPricingController.php | 57 ++++++++++++++++++--- templates/item-pricing/form.html.twig | 37 ++++++++++++-- templates/item/form.html.twig | 65 ++++++++++++++++++------ 5 files changed, 188 insertions(+), 27 deletions(-) diff --git a/config/routes/item_pricing.yaml b/config/routes/item_pricing.yaml index df289902..a557a1ec 100644 --- a/config/routes/item_pricing.yaml +++ b/config/routes/item_pricing.yaml @@ -9,6 +9,6 @@ item_pricing_update: methods: [POST] item_pricing_prices: - path: /item-pricing/{id}/prices + path: /item-pricing/{pt_id}/{it_id}/prices controller: App\Controller\ItemPricingController::itemPrices methods: [GET] diff --git a/src/Controller/ItemController.php b/src/Controller/ItemController.php index 88cc769c..7e9cd277 100644 --- a/src/Controller/ItemController.php +++ b/src/Controller/ItemController.php @@ -122,6 +122,60 @@ class ItemController extends Controller ]); } + /** + * @Menu(selected="item.list") + * @IsGranted("item.add") + */ + public function addForm(EntityManagerInterface $em) + { + $item = new Item(); + + // get the sets for the dropdowns + $sets = $this->generateFormSets($em); + + $params = [ + 'obj' => $item, + 'sets' => $sets, + 'mode' => 'create', + ]; + + // response + return $this->render('item/form.html.twig', $params); + } + + protected function generateFormSets(EntityManagerInterface $em) + { + // item types + $item_types = $em->getRepository(ItemType::class)->findby([], ['name' => 'asc']); + $item_type_set = []; + foreach ($item_types as $it) + { + $item_type_set[$it->getID()] = $it->getName(); + } + + // batteries + $batts = $em->getRepository(Battery::class)->findAll(); + $batt_set = []; + foreach ($batts as $batt) + { + $batt_set[$batt->getID()] = $batt->getModel()->getName() . ' ' . $batt->getSize()->getName(); + } + + // service offerings + $services = $em->getRepository(ServiceOffering::class)->findBy([],['name' => 'asc']); + $service_set = []; + foreach ($services as $service) + { + $service_set[$service->getID()] = $service->getName(); + } + + return [ + 'item_types' => $item_type_set, + 'batteries' => $batt_set, + 'services' => $service_set, + ]; + } + protected function setQueryFilters($datatable, QueryBuilder $query) { // TODO: add filter for item type. diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index ddfd60bf..537ae2a6 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -17,6 +17,8 @@ use Catalyst\MenuBundle\Annotation\Menu; use App\Entity\PriceTier; use App\Entity\Battery; +use App\Entity\ServiceOffering; +use App\Entity\ItemType; class ItemPricingController extends Controller { @@ -29,12 +31,16 @@ class ItemPricingController extends Controller // get all the price tiers $price_tiers = $em->getRepository(PriceTier::class)->findAll(); + // get all item types + $item_types = $em->getRepository(ItemType::class)->findBy([], ['name' => 'asc']); + // get all the items/batteries - $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); + $items = $this->getAllItems($em); $params = [ 'sets' => [ - 'price_tiers' => $price_tiers + 'price_tiers' => $price_tiers, + 'item_types' => $item_types, ], 'items' => $items, ]; @@ -53,7 +59,7 @@ class ItemPricingController extends Controller /** * @IsGranted("item_pricing.update") */ - public function itemPrices(EntityManagerInterface $em, $id) + public function itemPrices(EntityManagerInterface $em, $pt_id, $it_id) { $pt_prices = []; // check if default prices are needed @@ -62,9 +68,9 @@ class ItemPricingController extends Controller // get the price tier $pt = $em->getRepository(PriceTier::class)->find($id); - // get the item prices under the price tier - $pt_item_prices = $pt->getItemPrices(); - foreach ($pt_item_prices as $pt_item_price) + // get the items under the price tier + $pt_items = $pt->getItems(); + foreach ($pt_items as $pt_item) { } } @@ -80,4 +86,43 @@ class ItemPricingController extends Controller 'items' => $data_items, ]); } + + protected function getAllItems(EntityManagerInterface $em) + { + // get the item type for battery + $batt_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + + // get the item type for service offering + $service_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + + // get all active batteries + $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); + foreach ($batts as $batt) + { + $batt_set[$batt->getID()] = [ + 'name' => $batt->getModel()->getName() . ' ' . $batt->getSize()->getName(), + 'item_type_id' => $batt_item_type->getID(), + 'item_type' => $batt_item_type->getName(), + 'price' => $batt->getSellingPrice(), + ]; + } + + // get all service offerings + $services = $em->getRepository(ServiceOffering::class)->findBy([], ['name' => 'asc']); + $service_set = []; + foreach ($services as $service) + { + $service_set[$service->getID()] = [ + 'name' => $service->getName(), + 'item_type_id' => $service_item_type->getID(), + 'item_type' => $service_item_type->getName(), + 'price' => $service->getFee(), + ]; + } + + return [ + 'batteries' => $batt_set, + 'services' => $service_set, + ]; + } } diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index cde71ae6..d9387dac 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -34,6 +34,17 @@
+
+
+
+ +
+
+
@@ -46,19 +57,34 @@ ID Name + Item Type ID + Item Type Price - {% for item in items %} + {% for id, item in items.batteries %} - {{ item.getID }} - {{ item.getModel.getName ~ ' ' ~ item.getSize.getName}} + {{ id }} + {{ item.name }} + {{ item.item_type_id }} + {{ item.item_type }} - + - {% endfor %} + {% endfor %} + {% for id, item in items.services %} + + {{ id }} + {{ item.name}} + {{ item.item_type_id }} + {{ item.item_type}} + + + + + {% endfor %}
@@ -116,6 +142,7 @@ function update_table(data) { item_html += ''; item_html += '' + item.id + ''; item_html += '' + item.name + ''; + item_html += '' + item.item_type_id + ''; item_html += ''; item_html += ''; item_html += ''; diff --git a/templates/item/form.html.twig b/templates/item/form.html.twig index 97d0d9ec..f7a76ce1 100644 --- a/templates/item/form.html.twig +++ b/templates/item/form.html.twig @@ -5,7 +5,7 @@
-

Item Types

+

Items

@@ -23,33 +23,53 @@

{% if mode == 'update' %} - Edit Item Type + Edit Item {{ obj.getName() }} {% else %} - New Item Type + New Item {% endif %}

-
+
-
-
-
@@ -58,7 +78,7 @@
- Back + Back
@@ -90,7 +110,7 @@ $(function() { text: 'Your changes have been saved!', type: 'success', onClose: function() { - window.location.href = "{{ url('item_type_list') }}"; + window.location.href = "{{ url('item_list') }}"; } }); }).fail(function(response) { @@ -138,5 +158,20 @@ $(function() { $(".form-control-feedback[data-field]").addClass('hide'); } }); + +$('#item-type').change(function(e) { + console.log('item type change ' + e.target.value); + if (e.target.value === '1') { + // display battery row + $('#battery-row').removeClass("hide"); + + // hide service offering rows + } else { + // display service offering row + + // hide battery row + $('#battery-row').addClass("hide"); + } +}) {% endblock %} -- 2.43.5 From 7f4675a8a23d73eeefc90073cac6dcd7d6b0bb5d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 10 Jan 2024 17:23:15 +0800 Subject: [PATCH 039/119] Add item type dropdown to form. #780 --- src/Controller/ItemPricingController.php | 44 ++++++++++++++----- templates/item-pricing/form.html.twig | 55 +++++++++++++----------- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index 537ae2a6..158d3787 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -7,6 +7,7 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -35,7 +36,8 @@ class ItemPricingController extends Controller $item_types = $em->getRepository(ItemType::class)->findBy([], ['name' => 'asc']); // get all the items/batteries - $items = $this->getAllItems($em); + // load only batteries upon initial loading + $items = $this->getBatteries($em); $params = [ 'sets' => [ @@ -62,21 +64,37 @@ class ItemPricingController extends Controller public function itemPrices(EntityManagerInterface $em, $pt_id, $it_id) { $pt_prices = []; + + // get the item type + $it = $em->getRepository(ItemType::class)->find($it_id); + // check if default prices are needed - if ($id != 0) + if ($pt_id != 0) { // get the price tier - $pt = $em->getRepository(PriceTier::class)->find($id); + $pt = $em->getRepository(PriceTier::class)->find($pt_id); // get the items under the price tier $pt_items = $pt->getItems(); foreach ($pt_items as $pt_item) { + // make item price hash + $pt_prices[$pt_item->->getID()] = $pt_item->getPrice(); } } else { - // get the prices from battery + // get the prices from battery or service offering, depending on item type + if ($it->getCode() == 'battery') + { + // get batteries + $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); + } + else + { + // get service offerings + $items = $em->getRepository(ServiceOffering::class)->findBy([], ['name' => 'asc']); + } } $data_items = []; @@ -87,14 +105,11 @@ class ItemPricingController extends Controller ]); } - protected function getAllItems(EntityManagerInterface $em) + protected function getBatteries(EntityManagerInterface $em) { // get the item type for battery $batt_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); - // get the item type for service offering - $service_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); - // get all active batteries $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); foreach ($batts as $batt) @@ -107,6 +122,16 @@ class ItemPricingController extends Controller ]; } + return [ + 'items' => $batt_set, + ]; + } + + protected function getServiceOfferings(EntityeManagerInterface $em) + { + // get the item type for service offering + $service_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + // get all service offerings $services = $em->getRepository(ServiceOffering::class)->findBy([], ['name' => 'asc']); $service_set = []; @@ -121,8 +146,7 @@ class ItemPricingController extends Controller } return [ - 'batteries' => $batt_set, - 'services' => $service_set, + 'items' => $service_set, ]; } } diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index d9387dac..ed41d9e3 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -25,8 +25,8 @@
- + {% for price_tier in sets.price_tiers %} {% endfor %} @@ -37,7 +37,7 @@
- {% for item_type in sets.item_types %} {% endfor %} @@ -63,7 +63,7 @@ - {% for id, item in items.batteries %} + {% for id, item in items.items %} {{ id }} {{ item.name }} @@ -74,17 +74,6 @@ {% endfor %} - {% for id, item in items.services %} - - {{ id }} - {{ item.name}} - {{ item.item_type_id }} - {{ item.item_type}} - - - - - {% endfor %}
@@ -99,21 +88,36 @@
{% endblock %} -{% block js_end %} +{% block scripts %} {% endblock %} -- 2.43.5 From b59239055460f7f4db1a29ccb749688f698f5ea7 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 11 Jan 2024 16:48:23 +0800 Subject: [PATCH 040/119] Add response when displaying item prices. #780 --- src/Controller/ItemPricingController.php | 31 +++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index 158d3787..bcecd5ea 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -79,7 +79,7 @@ class ItemPricingController extends Controller foreach ($pt_items as $pt_item) { // make item price hash - $pt_prices[$pt_item->->getID()] = $pt_item->getPrice(); + $pt_prices[$pt_item->getID()] = $pt_item->getPrice(); } } else @@ -98,6 +98,35 @@ class ItemPricingController extends Controller } $data_items = []; + foreach ($items as $item) + { + $item_id = $item->getID(); + + // get default price + if ($it->getCode() == 'battery') + $price = $item->getSellingPrice(); + else + $price = $item->getFee(); + + // check if tier has price for item + if (isset($pt_prices[$item_id])) + { + $price = $pt_prices[$item_id]; + + // actual price + $actual_price = number_format($price / 100, 2, '.', ''); + } + + $actual_price = $price; + + // TODO: recheck this + $data_items[] = [ + 'id' => $item_id, + 'name' => '', + 'item_type' => '', + 'price' = $actual_price, + ]; + } // response return new JsonResponse([ -- 2.43.5 From bfe7a5fbf67c5c1271cc3bcb6c655241a884f5c3 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 15 Jan 2024 15:23:07 +0800 Subject: [PATCH 041/119] Fix display of item prices per tier. #780 --- src/Controller/ItemPricingController.php | 14 ++++++++++---- templates/item-pricing/form.html.twig | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index bcecd5ea..38bc0ce3 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -104,9 +104,15 @@ class ItemPricingController extends Controller // get default price if ($it->getCode() == 'battery') + { $price = $item->getSellingPrice(); + $name = $item->getModel()->getName() . ' ' . $item->getSize()->getName(); + } else + { $price = $item->getFee(); + $name = $item->getName(); + } // check if tier has price for item if (isset($pt_prices[$item_id])) @@ -119,12 +125,12 @@ class ItemPricingController extends Controller $actual_price = $price; - // TODO: recheck this $data_items[] = [ 'id' => $item_id, - 'name' => '', - 'item_type' => '', - 'price' = $actual_price, + 'name' => $name, + 'item_type_id' => $it->getID(), + 'item_type' => $it->getName(), + 'price' => $actual_price, ]; } diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index ed41d9e3..c27179a3 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -74,7 +74,7 @@ {% endfor %} - +
@@ -147,8 +147,9 @@ function update_table(data) { item_html += '' + item.id + ''; item_html += '' + item.name + ''; item_html += '' + item.item_type_id + ''; + item_html += '' + item.item_type + ''; item_html += ''; - item_html += ''; + item_html += ''; item_html += ''; item_html += ''; } -- 2.43.5 From 022336ad8f778f72e2a2474f55054848abbb530d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 15 Jan 2024 17:21:31 +0800 Subject: [PATCH 042/119] Add saving of prices. #780 --- src/Controller/ItemPricingController.php | 66 +++++++++++++++++++----- templates/item-pricing/form.html.twig | 4 +- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index 38bc0ce3..f7fd78ec 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -56,6 +56,48 @@ class ItemPricingController extends Controller */ public function formSubmit(Request $req, EntityManagerInterface $em) { + $pt_id = $req->request->get('price_tier_id'); + $it_id = $req->request->get('item_type_id'); + $prices = $req->request->get('price'); + + // get the item type + $item_type = $em->getRepository(ItemType::class)->find($it_id); + + if ($pt_id == 0) + { + // default price tier, update battery or service offering, depending on item type + // NOTE: battery and service offering prices or fees are stored as decimal. + if ($item_type->getCode() == 'battery') + { + // get batteries + $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']); + } + else + { + // get service offerings + $items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']); + } + + foreach ($items as $item) + { + $item_id = $item->getID(); + if (isset[$prices[$item_id]]) + { + // check item type + if ($item_type->getCode() == 'battery') + $item->setSellingPrice($prices[$item_id]); + else + $item->setFee($prices[$item_id]); + } + } + } + else + { + // get the price tier + $price_tier = $em->getRepository(PriceTier::class)->find($pt_id); + + // TODO: finish this + } } /** @@ -82,19 +124,17 @@ class ItemPricingController extends Controller $pt_prices[$pt_item->getID()] = $pt_item->getPrice(); } } + + // get the prices from battery or service offering, depending on item type + if ($it->getCode() == 'battery') + { + // get batteries + $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']); + } else { - // get the prices from battery or service offering, depending on item type - if ($it->getCode() == 'battery') - { - // get batteries - $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); - } - else - { - // get service offerings - $items = $em->getRepository(ServiceOffering::class)->findBy([], ['name' => 'asc']); - } + // get service offerings + $items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']); } $data_items = []; @@ -146,7 +186,7 @@ class ItemPricingController extends Controller $batt_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); // get all active batteries - $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true]); + $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']); foreach ($batts as $batt) { $batt_set[$batt->getID()] = [ @@ -168,7 +208,7 @@ class ItemPricingController extends Controller $service_item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); // get all service offerings - $services = $em->getRepository(ServiceOffering::class)->findBy([], ['name' => 'asc']); + $services = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']); $service_set = []; foreach ($services as $service) { diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index c27179a3..0afd23e3 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -51,6 +51,7 @@
+
@@ -94,7 +95,6 @@ initialize(); function initialize() { - console.log('initialize'); init_price_tier_dropdown(); init_item_type_dropdown(); } @@ -126,6 +126,8 @@ function load_prices(price_tier_id, item_type_id) { update_table(JSON.parse(req.responseText)); var pt_field = document.getElementById('price-tier-id'); pt_field.value = price_tier_id; + var it_field = document.getElementById('item-type-id'); + it_field.value = item_type_id; } else { // console.log('could not load tier prices'); } -- 2.43.5 From 6d7c8c5b532809757bab2f89c06daee791724683 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 16 Jan 2024 16:28:26 +0800 Subject: [PATCH 043/119] Add saving of item prices for price tier. #780 --- config/packages/catalyst_auth.yaml | 8 - config/packages/catalyst_menu.yaml | 4 - config/routes/item.yaml | 34 ---- src/Controller/ItemController.php | 188 ----------------------- src/Controller/ItemPricingController.php | 63 ++++++-- src/Entity/{Item.php => ItemPrice.php} | 4 +- src/Entity/ItemType.php | 2 +- src/Entity/PriceTier.php | 8 +- 8 files changed, 56 insertions(+), 255 deletions(-) delete mode 100644 config/routes/item.yaml delete mode 100644 src/Controller/ItemController.php rename src/Entity/{Item.php => ItemPrice.php} (98%) diff --git a/config/packages/catalyst_auth.yaml b/config/packages/catalyst_auth.yaml index 7e02d5c0..9707fc93 100644 --- a/config/packages/catalyst_auth.yaml +++ b/config/packages/catalyst_auth.yaml @@ -667,14 +667,6 @@ catalyst_auth: acls: - id: item.menu label: Menu - - id: item.list - label: List - - id: item.add - label: Add - - id: item.update - label: Update - - id: item.delete - label: Delete - id: item_pricing label: Item Pricing acls: diff --git a/config/packages/catalyst_menu.yaml b/config/packages/catalyst_menu.yaml index a6bd1583..7972a414 100644 --- a/config/packages/catalyst_menu.yaml +++ b/config/packages/catalyst_menu.yaml @@ -306,7 +306,3 @@ catalyst_menu: acl: item_pricing.update label: Item Pricing parent: item - - id: item_list - acl: item.list - label: Items - parent: item diff --git a/config/routes/item.yaml b/config/routes/item.yaml deleted file mode 100644 index 89dde4d2..00000000 --- a/config/routes/item.yaml +++ /dev/null @@ -1,34 +0,0 @@ -item_list: - path: /items - controller: App\Controller\ItemController::index - methods: [GET] - -item_rows: - path: /items/rowdata - controller: App\Controller\ItemController::datatableRows - methods: [POST] - -item_add_form: - path: /items/newform - controller: App\Controller\ItemController::addForm - methods: [GET] - -item_add_submit: - path: /items - controller: App\Controller\ItemController::addSubmit - methods: [POST] - -item_update_form: - path: /items/{id} - controller: App\Controller\ItemController::updateForm - methods: [GET] - -item_update_submit: - path: /items/{id} - controller: App\Controller\ItemController::updateSubmit - methods: [POST] - -item_delete: - path: /items/{id} - controller: App\Controller\ItemController::deleteSubmit - methods: [DELETE] diff --git a/src/Controller/ItemController.php b/src/Controller/ItemController.php deleted file mode 100644 index 7e9cd277..00000000 --- a/src/Controller/ItemController.php +++ /dev/null @@ -1,188 +0,0 @@ -render('item/list.html.twig'); - } - - /** - * @IsGranted("item.list") - */ - public function datatableRows(Request $req) - { - // get query builder - $total_qb = $this->getDoctrine() - ->getRepository(Item::class) - ->createQueryBuilder('q'); - - // get datatable params - $datatable = $req->request->get('datatable'); - - // count total records - $tquery = $total_qb->select('COUNT(q)') - ->leftJoin(Battery::class, 'battery', Join::WITH, 'battery.id = q.item_id') - ->leftJoin(ServiceOffering::class, 'so', Join::WITH, 'so.id = q.item_id'); - $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' - ]; - - // reset query builder - $qb = $this->getDoctrine() - ->getRepository(Item::class) - ->createQueryBuilder('q'); - - // build query - $query = $qb->select('q') - ->leftJoin(Battery::class, 'battery', Join::WITH, 'battery.id = q.item_id') - ->leftJoin(ServiceOffering::class, 'so', Join::WITH, 'so.id = q.item_id'); - $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('item_price.update')) - $row['meta']['update_url'] = $this->generateUrl('item_price_update_form', ['id' => $row['id']]); - if ($this->isGranted('item_price.delete')) - $row['meta']['delete_url'] = $this->generateUrl('item_price_delete', ['id' => $row['id']]); - - $rows[] = $row; - } - - // response - return $this->json([ - 'meta' => $meta, - 'data' => $rows - ]); - } - - /** - * @Menu(selected="item.list") - * @IsGranted("item.add") - */ - public function addForm(EntityManagerInterface $em) - { - $item = new Item(); - - // get the sets for the dropdowns - $sets = $this->generateFormSets($em); - - $params = [ - 'obj' => $item, - 'sets' => $sets, - 'mode' => 'create', - ]; - - // response - return $this->render('item/form.html.twig', $params); - } - - protected function generateFormSets(EntityManagerInterface $em) - { - // item types - $item_types = $em->getRepository(ItemType::class)->findby([], ['name' => 'asc']); - $item_type_set = []; - foreach ($item_types as $it) - { - $item_type_set[$it->getID()] = $it->getName(); - } - - // batteries - $batts = $em->getRepository(Battery::class)->findAll(); - $batt_set = []; - foreach ($batts as $batt) - { - $batt_set[$batt->getID()] = $batt->getModel()->getName() . ' ' . $batt->getSize()->getName(); - } - - // service offerings - $services = $em->getRepository(ServiceOffering::class)->findBy([],['name' => 'asc']); - $service_set = []; - foreach ($services as $service) - { - $service_set[$service->getID()] = $service->getName(); - } - - return [ - 'item_types' => $item_type_set, - 'batteries' => $batt_set, - 'services' => $service_set, - ]; - } - - protected function setQueryFilters($datatable, QueryBuilder $query) - { - // TODO: add filter for item type. - // TODO: fix filter for name since name is with the associated entity - 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/ItemPricingController.php b/src/Controller/ItemPricingController.php index f7fd78ec..ac093e82 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -63,25 +63,26 @@ class ItemPricingController extends Controller // get the item type $item_type = $em->getRepository(ItemType::class)->find($it_id); + if ($item_type->getCode() == 'battery') + { + // get batteries + $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']); + } + else + { + // get service offerings + $items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']); + } + + // on default price tier if ($pt_id == 0) { // default price tier, update battery or service offering, depending on item type // NOTE: battery and service offering prices or fees are stored as decimal. - if ($item_type->getCode() == 'battery') - { - // get batteries - $items = $em->getRepository(Battery::class)->findBy(['flag_active' => true], ['id' => 'asc']); - } - else - { - // get service offerings - $items = $em->getRepository(ServiceOffering::class)->findBy([], ['id' => 'asc']); - } - foreach ($items as $item) { $item_id = $item->getID(); - if (isset[$prices[$item_id]]) + if (isset($prices[$item_id])) { // check item type if ($item_type->getCode() == 'battery') @@ -96,8 +97,42 @@ class ItemPricingController extends Controller // get the price tier $price_tier = $em->getRepository(PriceTier::class)->find($pt_id); - // TODO: finish this + $item_prices = $price_tier->getItems(); + + // clear the tier's item prices + foreach ($item_prices as $ip) + { + $em->remove($ip); + } + + // update the tier's item prices + foreach ($items as $item) + { + $item_id = $item->getID(); + + $item_price = new ItemPrice(); + + $item_price->setItemType($item_type) + ->setPriceTier($price_tier) + ->setItemID($item_id); + + if (isset($prices[$item_id])) + { + $item_price->setPrice($price[$item_id] * 100); + } + else + { + $item_price->setPrice($item->getPrice() * 100); + } + + // save + $em->persist($item_price); + } } + + $em->flush(); + + return $this->redirectToRoute('item_pricing'); } /** @@ -117,7 +152,7 @@ class ItemPricingController extends Controller $pt = $em->getRepository(PriceTier::class)->find($pt_id); // get the items under the price tier - $pt_items = $pt->getItems(); + $pt_items = $pt->getItemPrices(); foreach ($pt_items as $pt_item) { // make item price hash diff --git a/src/Entity/Item.php b/src/Entity/ItemPrice.php similarity index 98% rename from src/Entity/Item.php rename to src/Entity/ItemPrice.php index 2e5ed091..143833ee 100644 --- a/src/Entity/Item.php +++ b/src/Entity/ItemPrice.php @@ -9,7 +9,7 @@ use Doctrine\ORM\Mapping as ORM; * @ORM\Table(name="item") */ -class Item +class ItemPrice { // unique id /** @@ -20,7 +20,7 @@ class Item protected $id; /** - * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="items") + * @ORM\ManyToOne(targetEntity="PriceTier", inversedBy="item_prices") * @ORM\JoinColumn(name="price_tier_id", referencedColumnName="id") */ protected $price_tier; diff --git a/src/Entity/ItemType.php b/src/Entity/ItemType.php index 3ef422d8..8c24e65c 100644 --- a/src/Entity/ItemType.php +++ b/src/Entity/ItemType.php @@ -37,7 +37,7 @@ class ItemType // items under an item type /** - * @ORM\OneToMany(targetEntity="Item", mappedBy="item_type") + * @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="item_type") */ protected $items; diff --git a/src/Entity/PriceTier.php b/src/Entity/PriceTier.php index d929fc8f..1e2599a5 100644 --- a/src/Entity/PriceTier.php +++ b/src/Entity/PriceTier.php @@ -34,9 +34,9 @@ class PriceTier // items under a price tier /** - * @ORM\OneToMany(targetEntity="Item", mappedBy="price_tier") + * @ORM\OneToMany(targetEntity="ItemPrice", mappedBy="price_tier") */ - protected $items; + protected $item_prices; public function __construct() { @@ -80,9 +80,9 @@ class PriceTier return $this; } - public function getItems() + public function getItemPrices() { - return $this->items; + return $this->item_prices; } } -- 2.43.5 From 9de6fa7999c7465ffad6ba0bb649a1f7529a822b Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 17 Jan 2024 14:25:28 +0800 Subject: [PATCH 044/119] Fix issues found during saving of item prices. #780 --- src/Controller/ItemPricingController.php | 16 +++++++++++----- src/Entity/ItemPrice.php | 2 +- templates/item-pricing/form.html.twig | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index ac093e82..f5e2a532 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -20,6 +20,7 @@ use App\Entity\PriceTier; use App\Entity\Battery; use App\Entity\ServiceOffering; use App\Entity\ItemType; +use App\Entity\ItemPrice; class ItemPricingController extends Controller { @@ -39,12 +40,16 @@ class ItemPricingController extends Controller // load only batteries upon initial loading $items = $this->getBatteries($em); + // set the default item type to battery + $default_it = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + $params = [ 'sets' => [ 'price_tiers' => $price_tiers, 'item_types' => $item_types, ], 'items' => $items, + 'default_item_type_id' => $default_it->getID(), ]; return $this->render('item-pricing/form.html.twig', $params); @@ -97,7 +102,7 @@ class ItemPricingController extends Controller // get the price tier $price_tier = $em->getRepository(PriceTier::class)->find($pt_id); - $item_prices = $price_tier->getItems(); + $item_prices = $price_tier->getItemPrices(); // clear the tier's item prices foreach ($item_prices as $ip) @@ -118,7 +123,7 @@ class ItemPricingController extends Controller if (isset($prices[$item_id])) { - $item_price->setPrice($price[$item_id] * 100); + $item_price->setPrice($prices[$item_id] * 100); } else { @@ -153,10 +158,11 @@ class ItemPricingController extends Controller // get the items under the price tier $pt_items = $pt->getItemPrices(); + foreach ($pt_items as $pt_item) { // make item price hash - $pt_prices[$pt_item->getID()] = $pt_item->getPrice(); + $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); } } @@ -192,10 +198,10 @@ class ItemPricingController extends Controller // check if tier has price for item if (isset($pt_prices[$item_id])) { - $price = $pt_prices[$item_id]; + $pt_price = $pt_prices[$item_id]; // actual price - $actual_price = number_format($price / 100, 2, '.', ''); + $price = number_format($pt_price / 100, 2, '.', ''); } $actual_price = $price; diff --git a/src/Entity/ItemPrice.php b/src/Entity/ItemPrice.php index 143833ee..48130468 100644 --- a/src/Entity/ItemPrice.php +++ b/src/Entity/ItemPrice.php @@ -6,7 +6,7 @@ use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity - * @ORM\Table(name="item") + * @ORM\Table(name="item_price") */ class ItemPrice diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index 0afd23e3..4572a46a 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -51,7 +51,7 @@ - +
@@ -118,6 +118,7 @@ function init_item_type_dropdown() { } function load_prices(price_tier_id, item_type_id) { + console.log('loading prices'); var req = new XMLHttpRequest(); req.onreadystatechange = function() { // process response -- 2.43.5 From ee033ddd552719e99b8a90acd1770d964b193600 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 17 Jan 2024 15:31:20 +0800 Subject: [PATCH 045/119] Fix issues found during testing. #780 --- src/Controller/ItemPricingController.php | 5 +++-- templates/item-pricing/form.html.twig | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Controller/ItemPricingController.php b/src/Controller/ItemPricingController.php index f5e2a532..3129f362 100644 --- a/src/Controller/ItemPricingController.php +++ b/src/Controller/ItemPricingController.php @@ -104,10 +104,11 @@ class ItemPricingController extends Controller $item_prices = $price_tier->getItemPrices(); - // clear the tier's item prices + // clear the tier's item prices for the specific item type foreach ($item_prices as $ip) { - $em->remove($ip); + if ($ip->getItemType() == $item_type) + $em->remove($ip); } // update the tier's item prices diff --git a/templates/item-pricing/form.html.twig b/templates/item-pricing/form.html.twig index 4572a46a..d6099390 100644 --- a/templates/item-pricing/form.html.twig +++ b/templates/item-pricing/form.html.twig @@ -118,7 +118,6 @@ function init_item_type_dropdown() { } function load_prices(price_tier_id, item_type_id) { - console.log('loading prices'); var req = new XMLHttpRequest(); req.onreadystatechange = function() { // process response -- 2.43.5 From 70ee7fdd8972da0e400f3b36da6d1908478eee7b Mon Sep 17 00:00:00 2001 From: root Date: Fri, 19 Jan 2024 04:14:06 -0500 Subject: [PATCH 046/119] Add invoice rule for price tier. #782 --- src/InvoiceRule/PriceTier.php | 157 +++++++++++++++++++++++++++++++++ src/Ramcar/InvoiceCriteria.php | 12 +++ 2 files changed, 169 insertions(+) create mode 100644 src/InvoiceRule/PriceTier.php diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php new file mode 100644 index 00000000..4db12b55 --- /dev/null +++ b/src/InvoiceRule/PriceTier.php @@ -0,0 +1,157 @@ +em = $em; + } + + public function getID() + { + return 'price_tier'; + } + + public function compute($criteria, &$total) + { + $pt_id = $criteria->getPriceTier(); + + // get the service type + $service_type = $criteria->getServiceType(); + + // get price tier + $pt = $em->getRepository(PTEntity::class)->find($pt_id); + + // price tier is default + if ($pt == null) + { + // check if service type is battery sales + if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + { + $items = $this->processBatteryEntries($criteria, $total); + } + } + else + { + // get items in price tier + $pt_items = $pt->getItemPrices(); + + foreach ($pt_items as $pt_item) + { + // make item price hash + $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); + } + } + + return $items; + } + + public function validatePromo($criteria, $promo_id) + { + return false; + } + + public function validateInvoiceItems($criteria, $invoice_items) + { + // check service type. Only battery sales and battery warranty should have invoice items. + $stype = $criteria->getServiceType(); + if (($stype != ServiceType::BATTERY_REPLACEMENT_NEW) && + ($stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)) + return null; + + // return error if there's a problem, false otherwise + if (!empty($invoice_items)) + { + // check if this is a valid battery + foreach ($invoice_items as $item) + { + $battery = $this->em->getRepository(Battery::class)->find($item['battery']); + + if (empty($battery)) + { + $error = 'Invalid battery specified.'; + return $error; + } + + // quantity + $qty = $item['quantity']; + if ($qty < 1) + continue; + + // if this is a trade in, add trade in + if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) + $trade_in = $item['trade_in']; + else + $trade_in = null; + + $criteria->addEntry($battery, $trade_in, $qty); + } + } + + return null; + } + + protected function processBatteryEntries($criteria, &$total) + { + $items = []; + + // get the entries + $entries = $criteria->getEntries(); + foreach($entries as $entry) + { + $batt = $entry['battery']; + $qty = $entry['qty']; + $trade_in = null; + + if (isset($entry['trade_in'])) + $trade_in = $entry['trade_in']; + + $size = $batt->getSize(); + + if ($trade_in == null) + { + // battery purchase + $price = $batt->getSellingPrice(); + + $items[] = [ + 'service_type' => $this->getID(), + 'battery' => $batt, + 'qty' => $qty, + 'title' => $this->getTitle($criteria->getServiceType(), $batt), + 'price' => $price, + ]; + + $qty_price = bcmul($price, $qty, 2); + + $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); + $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); + } + } + + return $items; + } + + protected function getTitle($service_type, $battery) + { + $title =''; + + // TODO: check for service type + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + + return $title; + } + +} diff --git a/src/Ramcar/InvoiceCriteria.php b/src/Ramcar/InvoiceCriteria.php index b27395da..18ebd82a 100644 --- a/src/Ramcar/InvoiceCriteria.php +++ b/src/Ramcar/InvoiceCriteria.php @@ -17,6 +17,7 @@ class InvoiceCriteria protected $service_charges; protected $flag_taxable; protected $source; // use Ramcar's TransactionOrigin + protected $price_tier; // entries are battery and trade-in combos protected $entries; @@ -32,6 +33,7 @@ class InvoiceCriteria $this->service_charges = []; $this->flag_taxable = false; $this->source = ''; + $this->price_tier = 0; // set to default } public function setServiceType($stype) @@ -179,4 +181,14 @@ class InvoiceCriteria return $this->source; } + public function setPriceTier($price_tier) + { + $this->price_tier = $price_tier; + return $this; + } + + public function getPriceTier() + { + return $this->price_tier; + } } -- 2.43.5 From 29ad8d57a44ad1990cfb0e33990b52895f305892 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 22 Jan 2024 04:24:41 -0500 Subject: [PATCH 047/119] Add processing of battery entries and invoice item titles. #782 --- src/InvoiceRule/PriceTier.php | 77 +++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php index 4db12b55..7db80ccc 100644 --- a/src/InvoiceRule/PriceTier.php +++ b/src/InvoiceRule/PriceTier.php @@ -38,11 +38,18 @@ class PriceTier implements InvoiceRuleInterface // price tier is default if ($pt == null) { - // check if service type is battery sales - if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + // check if service type is battery sales and battery warranty (sometimes they add a battery + // for battery warranty + if (($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) || + ($service_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY)) { $items = $this->processBatteryEntries($criteria, $total); } + else + { + // TODO: process the service fees + $items = $this->processServiceEntries($criteria, $total); + } } else { @@ -54,6 +61,8 @@ class PriceTier implements InvoiceRuleInterface // make item price hash $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); } + + // TODO: finish this } return $items; @@ -123,14 +132,17 @@ class PriceTier implements InvoiceRuleInterface if ($trade_in == null) { - // battery purchase - $price = $batt->getSellingPrice(); + // check if battery purchase or battery replacement + if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) + $price = $batt->getSellingPrice(); + else + $price = 0; $items[] = [ 'service_type' => $this->getID(), 'battery' => $batt, 'qty' => $qty, - 'title' => $this->getTitle($criteria->getServiceType(), $batt), + 'title' => $this->getItemTitle($criteria->getServiceType(), $batt), 'price' => $price, ]; @@ -144,12 +156,63 @@ class PriceTier implements InvoiceRuleInterface return $items; } - protected function getTitle($service_type, $battery) + protected function processServiceEntries($criteria, &$total) + { + } + + protected function getItemTitle($service_type, $battery) { $title =''; // TODO: check for service type - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + switch ($service_type) { + case (ServiceType::BATTERY_REPLACEMENT_NEW): + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); + break; + case (ServiceType::BATTERY_REPLACEMENT_WARRANTY): + $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; + break; + default: + $title = ''; + break; + } + + return $title; + + protected function getServiceTitle($service_type, $fuel_type) + { + $title = ''; + + switch ($service_type) { + case (ServiceType::JUMPSTART_TROUBLESHOOT): + case (ServiceType::JUMPSTART_WARRANTY): + $title = 'Service - Troubleshooting fee'; + break; + case (ServiceType::OVERHEAT_ASSISTANCE): + $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); + break; + case (ServiceType::POST_RECHARGED): + $title = 'Recharge fee'; + break; + case (ServiceType::POST_REPLACEMENT): + $title = 'Battery replacement'; + break; + case (ServiceType::TIRE_REPAIR): + $title = 'Service - Flat Tire'; + break; + case (ServiceType::EMERGENCY_REFUEL): + $title = '4L - ' . ucfirst($fuel_type); + break; + default: + $title = ''; + } + + return $title; + } + + protected function getServiceCoolantTitle() + { + $title = '4L Coolant'; return $title; } -- 2.43.5 From b6763bfd3e41452a48048407120fa187f7058fcd Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 24 Jan 2024 02:24:13 -0500 Subject: [PATCH 048/119] Add price tier checking for battery sales. #782 --- config/services.yaml | 5 ++ src/Controller/JobOrderController.php | 22 ++++++- src/InvoiceRule/BatterySales.php | 38 +++++++++++- .../InvoiceGenerator/CMBInvoiceGenerator.php | 2 +- .../InvoiceGenerator/ResqInvoiceGenerator.php | 2 +- src/Service/InvoiceGeneratorInterface.php | 3 +- src/Service/InvoiceManager.php | 12 ++-- .../JobOrderHandler/ResqJobOrderHandler.php | 9 ++- src/Service/PriceTierManager.php | 58 +++++++++++++++++++ templates/job-order/form.html.twig | 6 +- 10 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 src/Service/PriceTierManager.php diff --git a/config/services.yaml b/config/services.yaml index b19ecabc..d20db360 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -310,3 +310,8 @@ services: arguments: $server_key: "%env(FCM_SERVER_KEY)%" $sender_id: "%env(FCM_SENDER_ID)%" + + # price tier manager + App\Service\PriceTierManager: + arguments: + $em: "@doctrine.orm.entity_manager" diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 91921a0f..17c62a45 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -30,6 +30,7 @@ use App\Service\HubSelector; use App\Service\RiderTracker; use App\Service\MotivConnector; +use App\Service\PriceTierManager; use App\Service\GeofenceTracker; use Symfony\Component\HttpFoundation\Request; @@ -42,6 +43,8 @@ use Doctrine\ORM\EntityManagerInterface; use Catalyst\MenuBundle\Annotation\Menu; +use CrEOF\Spatial\PHP\Types\Geometry\Point; + class JobOrderController extends Controller { public function getJobOrders(Request $req, JobOrderHandlerInterface $jo_handler) @@ -741,7 +744,7 @@ class JobOrderController extends Controller } - public function generateInvoice(Request $req, InvoiceGeneratorInterface $ic) + public function generateInvoice(Request $req, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // error_log('generating invoice...'); $error = false; @@ -752,6 +755,19 @@ class JobOrderController extends Controller $cvid = $req->request->get('cvid'); $service_charges = $req->request->get('service_charges', []); + // coordinates + // need to check if lng and lat are set + $lng = $req->request->get('coord_lng', 0); + $lat = $req->request->get('coord_lat', 0); + + $price_tier = 0; + if (($lng != 0) && ($lat != 0)) + { + $coordinates = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat')); + $price_tier = $pt_manager->getPriceTier($coordinates); + } + + $em = $this->getDoctrine()->getManager(); // get customer vehicle @@ -767,8 +783,8 @@ class JobOrderController extends Controller $criteria->setServiceType($stype) ->setCustomerVehicle($cv) ->setIsTaxable() - ->setSource(TransactionOrigin::CALL); - + ->setSource(TransactionOrigin::CALL) + ->setPriceTier($price_tier); /* // if it's a jumpstart or troubleshoot only, we know what to charge already diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php index 45b060d1..3ff9a995 100644 --- a/src/InvoiceRule/BatterySales.php +++ b/src/InvoiceRule/BatterySales.php @@ -10,14 +10,19 @@ use App\Ramcar\TradeInType; use App\Ramcar\ServiceType; use App\Entity\Battery; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class BatterySales implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -28,6 +33,9 @@ class BatterySales implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt = $criteria->getPriceTier(); + + error_log('price tier ' . $pt); $items = []; if ($stype == $this->getID()) @@ -47,8 +55,13 @@ class BatterySales implements InvoiceRuleInterface if ($trade_in == null) { - // battery purchase - $price = $batt->getSellingPrice(); + // check if price tier has item price for battery + $pt_price = $this->getPriceTierItemPrice($pt, $batt); + + if ($pt_price == null) + $price = $batt->getSellingPrice(); + else + $price = $pt_price; $items[] = [ 'service_type' => $this->getID(), @@ -114,6 +127,25 @@ class BatterySales implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $batt) + { + // price tier is default + if ($pt_id == 0) + return null; + + // find the item type battery + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $batt->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTitle($battery) { $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); diff --git a/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php b/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php index 5dc86f8d..c1f40509 100644 --- a/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php +++ b/src/Service/InvoiceGenerator/CMBInvoiceGenerator.php @@ -134,7 +134,7 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface } // generate invoice criteria - public function generateInvoiceCriteria($jo, $discount, $invoice_items, $source = null, &$error_array) + public function generateInvoiceCriteria($jo, $discount, $invoice_items, $price_tier = null, $source = null, &$error_array) { $em = $this->em; diff --git a/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php b/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php index 3809133b..efe0a9de 100644 --- a/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php +++ b/src/Service/InvoiceGenerator/ResqInvoiceGenerator.php @@ -144,7 +144,7 @@ class ResqInvoiceGenerator implements InvoiceGeneratorInterface } // generate invoice criteria - public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source = null, &$error_array) + public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $price_tier = null, $source = null, &$error_array) { $em = $this->em; diff --git a/src/Service/InvoiceGeneratorInterface.php b/src/Service/InvoiceGeneratorInterface.php index e2cb2cc3..4c46c38f 100644 --- a/src/Service/InvoiceGeneratorInterface.php +++ b/src/Service/InvoiceGeneratorInterface.php @@ -4,6 +4,7 @@ namespace App\Service; use App\Entity\Invoice; use App\Entity\JobOrder; +use App\Entity\PriceTier; use App\Ramcar\InvoiceCriteria; @@ -13,7 +14,7 @@ interface InvoiceGeneratorInterface public function generateInvoice(InvoiceCriteria $criteria); // generate invoice criteria - public function generateInvoiceCriteria(JobOrder $jo, int $promo_id, array $invoice_items, $source, array &$error_array); + public function generateInvoiceCriteria(JobOrder $jo, int $promo_id, array $invoice_items, $source, PriceTier $price_tier, array &$error_array); // prepare draft for invoice public function generateDraftInvoice(InvoiceCriteria $criteria, int $promo_id, array $service_charges, array $items); diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 65fc3a43..93d6bafd 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -10,6 +10,7 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRule; use App\Service\InvoiceGeneratorInterface; +use App\Service\PriceTierManager; use App\Ramcar\InvoiceCriteria; use App\Ramcar\InvoiceStatus; @@ -28,12 +29,14 @@ class InvoiceManager implements InvoiceGeneratorInterface protected $em; protected $validator; protected $available_rules; + protected $pt_manager; - public function __construct(EntityManagerInterface $em, Security $security, ValidatorInterface $validator) + public function __construct(EntityManagerInterface $em, Security $security, ValidatorInterface $validator, PriceTierManager $pt_manager) { $this->em = $em; $this->security = $security; $this->validator = $validator; + $this->pt_manager = $pt_manager; $this->available_rules = $this->getAvailableRules(); } @@ -42,7 +45,7 @@ class InvoiceManager implements InvoiceGeneratorInterface { // TODO: get list of invoice rules from .env or a json file? return [ - new InvoiceRule\BatterySales($this->em), + new InvoiceRule\BatterySales($this->em, $this->pt_manager), new InvoiceRule\BatteryReplacementWarranty($this->em), new InvoiceRule\Jumpstart($this->em), new InvoiceRule\JumpstartWarranty($this->em), @@ -58,12 +61,13 @@ class InvoiceManager implements InvoiceGeneratorInterface } // this is called when JO is submitted - public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, &$error_array) + public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, &$error_array) { // instantiate the invoice criteria $criteria = new InvoiceCriteria(); $criteria->setServiceType($jo->getServiceType()) - ->setCustomerVehicle($jo->getCustomerVehicle()); + ->setCustomerVehicle($jo->getCustomerVehicle()) + ->setPriceTier($price_tier); // set if taxable // NOTE: ideally, this should be a parameter when calling generateInvoiceCriteria. But that diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 361c0b22..28e9035d 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -69,6 +69,7 @@ use App\Service\HubSelector; use App\Service\HubDistributor; use App\Service\HubFilteringGeoChecker; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use CrEOF\Spatial\PHP\Types\Geometry\Point; @@ -96,6 +97,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface protected $cust_distance_limit; protected $hub_filter_enable; protected $jo_manager; + protected $pt_manager; protected $template_hash; @@ -104,7 +106,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah, string $country_code, WarrantyHandler $wh, RisingTideGateway $rt, PromoLogger $promo_logger, HubDistributor $hub_dist, HubFilteringGeoChecker $hub_geofence, - string $cust_distance_limit, string $hub_filter_enabled, JobOrderManager $jo_manager) + string $cust_distance_limit, string $hub_filter_enabled, JobOrderManager $jo_manager, PriceTierManager $pt_manager) { $this->em = $em; $this->ic = $ic; @@ -121,6 +123,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $this->cust_distance_limit = $cust_distance_limit; $this->hub_filter_enabled = $hub_filter_enabled; $this->jo_manager = $jo_manager; + $this->pt_manager = $pt_manager; $this->loadTemplates(); } @@ -585,7 +588,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $jo->getSource(); - $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $error_array); + // TODO: set the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php new file mode 100644 index 00000000..e4174e78 --- /dev/null +++ b/src/Service/PriceTierManager.php @@ -0,0 +1,58 @@ +em = $em; + } + + public function getItemPrice($pt_id, $item_type_id, $item_id) + { + // find the item price, given the price tier, battery id, and item type (battery) + $db_conn = $this->em->getConnection(); + + $ip_sql = 'SELECT ip.price AS price + FROM item_price ip + WHERE ip.price_tier_id = :pt_id + AND ip.item_type_id = :it_id + AND ip.item_id = :item_id'; + + $ip_stmt = $db_conn->prepare($ip_sql); + $ip_stmt->bindValue('pt_id', $pt_id); + $ip_stmt->bindValue('it_id', $item_type_id); + $ip_stmt->bindValue('item_id', $item_id); + + $ip_result = $ip_stmt->executeQuery(); + + $actual_price = 0; + // go through rows + while ($row = $ip_result->fetchAssociative()) + { + // get the price + $price = $row['price']; + + // actual price + $actual_price = number_format($price / 100, 2, '.', ''); + } + + return $actual_price; + } + + public function getPriceTier(Point $point) + { + // TODO: get location's price tier, given a set of coordinates + // for now, hardcoded for testing purposes + return 1; + } +} diff --git a/templates/job-order/form.html.twig b/templates/job-order/form.html.twig index ca68e922..375e0353 100644 --- a/templates/job-order/form.html.twig +++ b/templates/job-order/form.html.twig @@ -1761,6 +1761,8 @@ $(function() { var table = $("#invoice-table tbody"); var stype = $("#service_type").val(); var cvid = $("#customer-vehicle").val(); + var lng = $("#map_lng").val(); + var lat = $("#map_lat").val(); console.log(JSON.stringify(invoiceItems)); @@ -1772,7 +1774,9 @@ $(function() { 'stype': stype, 'items': invoiceItems, 'promo': promo, - 'cvid': cvid + 'cvid': cvid, + 'coord_lng': lng, + 'coord_lat': lat, } }).done(function(response) { // mark as invoice changed -- 2.43.5 From c5b395d720589b6296c58bc158a80e211d8a3e7d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 24 Jan 2024 04:02:14 -0500 Subject: [PATCH 049/119] Add price tier for battery replacement warranty. #782 --- .../BatteryReplacementWarranty.php | 41 ++++++++++++++++++- src/InvoiceRule/BatterySales.php | 2 - src/Service/InvoiceManager.php | 2 +- src/Service/PriceTierManager.php | 4 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/InvoiceRule/BatteryReplacementWarranty.php b/src/InvoiceRule/BatteryReplacementWarranty.php index ee1497b5..8c2dafd4 100644 --- a/src/InvoiceRule/BatteryReplacementWarranty.php +++ b/src/InvoiceRule/BatteryReplacementWarranty.php @@ -11,14 +11,19 @@ use App\Ramcar\TradeInType; use App\Entity\Battery; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class BatteryReplacementWarranty implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,6 +34,7 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) @@ -40,7 +46,14 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface { $batt = $entry['battery']; $qty = 1; - $price = $this->getServiceTypeFee(); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $items[] = [ 'service_type' => $this->getID(), @@ -117,6 +130,30 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'battery_replacement_warranty_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + + protected function getTitle($battery) { $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php index 3ff9a995..645e545b 100644 --- a/src/InvoiceRule/BatterySales.php +++ b/src/InvoiceRule/BatterySales.php @@ -35,8 +35,6 @@ class BatterySales implements InvoiceRuleInterface $stype = $criteria->getServiceType(); $pt = $criteria->getPriceTier(); - error_log('price tier ' . $pt); - $items = []; if ($stype == $this->getID()) { diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 93d6bafd..6e37a207 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -46,7 +46,7 @@ class InvoiceManager implements InvoiceGeneratorInterface // TODO: get list of invoice rules from .env or a json file? return [ new InvoiceRule\BatterySales($this->em, $this->pt_manager), - new InvoiceRule\BatteryReplacementWarranty($this->em), + new InvoiceRule\BatteryReplacementWarranty($this->em, $this->pt_manager), new InvoiceRule\Jumpstart($this->em), new InvoiceRule\JumpstartWarranty($this->em), new InvoiceRule\PostRecharged($this->em), diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index e4174e78..c572af76 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -35,7 +35,9 @@ class PriceTierManager $ip_result = $ip_stmt->executeQuery(); - $actual_price = 0; + // results found + $actual_price = null; + // go through rows while ($row = $ip_result->fetchAssociative()) { -- 2.43.5 From bc6364ace52058a4e343c784c07016a55731bcea Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 02:11:05 -0500 Subject: [PATCH 050/119] Add price tier to invoice rules. #782 --- .../BatteryReplacementWarranty.php | 4 + src/InvoiceRule/Fuel.php | 94 +++++++- src/InvoiceRule/Jumpstart.php | 60 ++++- src/InvoiceRule/JumpstartWarranty.php | 47 +++- src/InvoiceRule/Overheat.php | 55 ++++- src/InvoiceRule/PostRecharged.php | 47 +++- src/InvoiceRule/PostReplacement.php | 47 +++- src/InvoiceRule/PriceTier.php | 220 ------------------ src/InvoiceRule/TireRepair.php | 54 ++++- src/Service/InvoiceManager.php | 14 +- 10 files changed, 386 insertions(+), 256 deletions(-) delete mode 100644 src/InvoiceRule/PriceTier.php diff --git a/src/InvoiceRule/BatteryReplacementWarranty.php b/src/InvoiceRule/BatteryReplacementWarranty.php index 8c2dafd4..46ba5e8a 100644 --- a/src/InvoiceRule/BatteryReplacementWarranty.php +++ b/src/InvoiceRule/BatteryReplacementWarranty.php @@ -145,6 +145,10 @@ class BatteryReplacementWarranty implements InvoiceRuleInterface $code = 'battery_replacement_warranty_fee'; $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + // check if service is null. If null, return null + if ($service == null) + return null; + $item_type_id = $item_type->getID(); $item_id = $service->getID(); diff --git a/src/InvoiceRule/Fuel.php b/src/InvoiceRule/Fuel.php index f843e1c0..691a1ba2 100644 --- a/src/InvoiceRule/Fuel.php +++ b/src/InvoiceRule/Fuel.php @@ -11,14 +11,19 @@ use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Fuel implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,6 +34,7 @@ class Fuel implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; @@ -36,7 +42,13 @@ class Fuel implements InvoiceRuleInterface { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $service_price = $this->getServiceTypeFee($cv); + else + $service_price = $pt_price; $ftype = $cv->getFuelType(); @@ -46,10 +58,10 @@ class Fuel implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle($ftype), - 'price' => $fee, + 'price' => $service_price, ]; - $qty_fee = bcmul($qty, $fee, 2); + $qty_fee = bcmul($qty, $service_price, 2); $total_price = $qty_fee; switch ($ftype) @@ -57,7 +69,15 @@ class Fuel implements InvoiceRuleInterface case FuelType::GAS: case FuelType::DIESEL: $qty = 1; - $price = $this->getFuelFee($ftype); + + // check if price tier has item price for fuel type + $pt_price = $this->getPriceTierFuelItemPrice($pt_id, $ftype); + + if ($pt_price == null) + $price = $this->getFuelFee($ftype); + else + $price = $pt_price; + $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, @@ -138,6 +158,70 @@ class Fuel implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + else + $code = 'fuel_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + + protected function getPriceTierFuelItemPrice($pt_id, $fuel_type) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = ''; + if ($fuel_type == FuelType::GAS) + $code = 'fuel_gas_fee'; + if ($fuel_type == FuelType::DIESEL) + $code = 'fuel_diesel_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTitle($fuel_type) { $title = '4L - ' . ucfirst($fuel_type); diff --git a/src/InvoiceRule/Jumpstart.php b/src/InvoiceRule/Jumpstart.php index dce41d99..d2e89b0a 100644 --- a/src/InvoiceRule/Jumpstart.php +++ b/src/InvoiceRule/Jumpstart.php @@ -8,16 +8,21 @@ use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; use App\Ramcar\TransactionOrigin; +use App\Service\PriceTierManager; + class Jumpstart implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,13 +34,21 @@ class Jumpstart implements InvoiceRuleInterface { $stype = $criteria->getServiceType(); $source = $criteria->getSource(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($source, $cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $source, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($source, $cv); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -43,10 +56,10 @@ class Jumpstart implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -86,6 +99,45 @@ class Jumpstart implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $source, $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + // check the source of JO + // (1) if from app, service fee is 0 if motolite user. jumpstart fee for app if non-motolite user. + // (2) any other source, jumpstart fees are charged whether motolite user or not + if ($source == TransactionOrigin::MOBILE_APP) + { + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + else + $code = 'jumpstart_fee_mobile_app'; + } + else + $code = 'jumpstart_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Troubleshooting fee'; diff --git a/src/InvoiceRule/JumpstartWarranty.php b/src/InvoiceRule/JumpstartWarranty.php index 9423da44..4c6ac387 100644 --- a/src/InvoiceRule/JumpstartWarranty.php +++ b/src/InvoiceRule/JumpstartWarranty.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class JumpstartWarranty implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,12 +30,19 @@ class JumpstartWarranty implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -38,10 +50,10 @@ class JumpstartWarranty implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -72,6 +84,33 @@ class JumpstartWarranty implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'jumpstart_warranty_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Troubleshooting fee'; diff --git a/src/InvoiceRule/Overheat.php b/src/InvoiceRule/Overheat.php index 4c06bddb..af0ce182 100644 --- a/src/InvoiceRule/Overheat.php +++ b/src/InvoiceRule/Overheat.php @@ -10,14 +10,19 @@ use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Overheat implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -29,13 +34,22 @@ class Overheat implements InvoiceRuleInterface { $stype = $criteria->getServiceType(); $has_coolant = $criteria->hasCoolant(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($cv); + else + + $price = $pt_price; // add the service fee to items $qty = 1; @@ -43,10 +57,10 @@ class Overheat implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_fee = bcmul($qty, $fee, 2); + $qty_fee = bcmul($qty, $price, 2); $total_price = $qty_fee; if ($has_coolant) @@ -112,6 +126,39 @@ class Overheat implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'overheat_fee'; + + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); diff --git a/src/InvoiceRule/PostRecharged.php b/src/InvoiceRule/PostRecharged.php index 808f2340..b0b20995 100644 --- a/src/InvoiceRule/PostRecharged.php +++ b/src/InvoiceRule/PostRecharged.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class PostRecharged implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,22 +30,29 @@ class PostRecharged implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $qty = 1; $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -72,6 +84,33 @@ class PostRecharged implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'post_recharged_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Recharge fee'; diff --git a/src/InvoiceRule/PostReplacement.php b/src/InvoiceRule/PostReplacement.php index aba6d9aa..774b61de 100644 --- a/src/InvoiceRule/PostReplacement.php +++ b/src/InvoiceRule/PostReplacement.php @@ -7,14 +7,19 @@ use Doctrine\ORM\EntityManagerInterface; use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class PostReplacement implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -25,22 +30,29 @@ class PostReplacement implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { - $fee = $this->getServiceTypeFee(); + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id); + + if ($pt_price == null) + $price = $this->getServiceTypeFee(); + else + $price = $pt_price; $qty = 1; $items[] = [ 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -71,6 +83,33 @@ class PostReplacement implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'post_replacement_fee'; + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Battery replacement'; diff --git a/src/InvoiceRule/PriceTier.php b/src/InvoiceRule/PriceTier.php deleted file mode 100644 index 7db80ccc..00000000 --- a/src/InvoiceRule/PriceTier.php +++ /dev/null @@ -1,220 +0,0 @@ -em = $em; - } - - public function getID() - { - return 'price_tier'; - } - - public function compute($criteria, &$total) - { - $pt_id = $criteria->getPriceTier(); - - // get the service type - $service_type = $criteria->getServiceType(); - - // get price tier - $pt = $em->getRepository(PTEntity::class)->find($pt_id); - - // price tier is default - if ($pt == null) - { - // check if service type is battery sales and battery warranty (sometimes they add a battery - // for battery warranty - if (($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) || - ($service_type == ServiceType::BATTERY_REPLACEMENT_WARRANTY)) - { - $items = $this->processBatteryEntries($criteria, $total); - } - else - { - // TODO: process the service fees - $items = $this->processServiceEntries($criteria, $total); - } - } - else - { - // get items in price tier - $pt_items = $pt->getItemPrices(); - - foreach ($pt_items as $pt_item) - { - // make item price hash - $pt_prices[$pt_item->getItemID()] = $pt_item->getPrice(); - } - - // TODO: finish this - } - - return $items; - } - - public function validatePromo($criteria, $promo_id) - { - return false; - } - - public function validateInvoiceItems($criteria, $invoice_items) - { - // check service type. Only battery sales and battery warranty should have invoice items. - $stype = $criteria->getServiceType(); - if (($stype != ServiceType::BATTERY_REPLACEMENT_NEW) && - ($stype != ServiceType::BATTERY_REPLACEMENT_WARRANTY)) - return null; - - // return error if there's a problem, false otherwise - if (!empty($invoice_items)) - { - // check if this is a valid battery - foreach ($invoice_items as $item) - { - $battery = $this->em->getRepository(Battery::class)->find($item['battery']); - - if (empty($battery)) - { - $error = 'Invalid battery specified.'; - return $error; - } - - // quantity - $qty = $item['quantity']; - if ($qty < 1) - continue; - - // if this is a trade in, add trade in - if (!empty($item['trade_in']) && TradeInType::validate($item['trade_in'])) - $trade_in = $item['trade_in']; - else - $trade_in = null; - - $criteria->addEntry($battery, $trade_in, $qty); - } - } - - return null; - } - - protected function processBatteryEntries($criteria, &$total) - { - $items = []; - - // get the entries - $entries = $criteria->getEntries(); - foreach($entries as $entry) - { - $batt = $entry['battery']; - $qty = $entry['qty']; - $trade_in = null; - - if (isset($entry['trade_in'])) - $trade_in = $entry['trade_in']; - - $size = $batt->getSize(); - - if ($trade_in == null) - { - // check if battery purchase or battery replacement - if ($service_type == ServiceType::BATTERY_REPLACEMENT_NEW) - $price = $batt->getSellingPrice(); - else - $price = 0; - - $items[] = [ - 'service_type' => $this->getID(), - 'battery' => $batt, - 'qty' => $qty, - 'title' => $this->getItemTitle($criteria->getServiceType(), $batt), - 'price' => $price, - ]; - - $qty_price = bcmul($price, $qty, 2); - - $total['sell_price'] = bcadd($total['sell_price'], $qty_price, 2); - $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); - } - } - - return $items; - } - - protected function processServiceEntries($criteria, &$total) - { - } - - protected function getItemTitle($service_type, $battery) - { - $title =''; - - // TODO: check for service type - switch ($service_type) { - case (ServiceType::BATTERY_REPLACEMENT_NEW): - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName(); - break; - case (ServiceType::BATTERY_REPLACEMENT_WARRANTY): - $title = $battery->getModel()->getName() . ' ' . $battery->getSize()->getName() . ' - Service Unit'; - break; - default: - $title = ''; - break; - } - - return $title; - - protected function getServiceTitle($service_type, $fuel_type) - { - $title = ''; - - switch ($service_type) { - case (ServiceType::JUMPSTART_TROUBLESHOOT): - case (ServiceType::JUMPSTART_WARRANTY): - $title = 'Service - Troubleshooting fee'; - break; - case (ServiceType::OVERHEAT_ASSISTANCE): - $title = 'Service - ' . ServiceType::getName(ServiceType::OVERHEAT_ASSISTANCE); - break; - case (ServiceType::POST_RECHARGED): - $title = 'Recharge fee'; - break; - case (ServiceType::POST_REPLACEMENT): - $title = 'Battery replacement'; - break; - case (ServiceType::TIRE_REPAIR): - $title = 'Service - Flat Tire'; - break; - case (ServiceType::EMERGENCY_REFUEL): - $title = '4L - ' . ucfirst($fuel_type); - break; - default: - $title = ''; - } - - return $title; - } - - protected function getServiceCoolantTitle() - { - $title = '4L Coolant'; - - return $title; - } - -} diff --git a/src/InvoiceRule/TireRepair.php b/src/InvoiceRule/TireRepair.php index 755c11bd..96d3c525 100644 --- a/src/InvoiceRule/TireRepair.php +++ b/src/InvoiceRule/TireRepair.php @@ -8,14 +8,19 @@ use App\InvoiceRuleInterface; use App\Entity\ServiceOffering; use App\Entity\CustomerVehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class TireRepair implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -26,13 +31,21 @@ class TireRepair implements InvoiceRuleInterface public function compute($criteria, &$total) { $stype = $criteria->getServiceType(); + $pt_id = $criteria->getPriceTier(); $items = []; if ($stype == $this->getID()) { $cv = $criteria->getCustomerVehicle(); - $fee = $this->getServiceTypeFee($cv); + + // check if price tier has item price + $pt_price = $this->getPriceTierItemPrice($pt_id, $cv); + + if ($pt_price == null) + $price = $this->getServiceTypeFee($cv); + else + $price = $pt_price; // add the service fee to items $qty = 1; @@ -40,10 +53,10 @@ class TireRepair implements InvoiceRuleInterface 'service_type' => $this->getID(), 'qty' => $qty, 'title' => $this->getServiceTitle(), - 'price' => $fee, + 'price' => $price, ]; - $qty_price = bcmul($fee, $qty, 2); + $qty_price = bcmul($price, $qty, 2); $total['total_price'] = bcadd($total['total_price'], $qty_price, 2); } @@ -79,6 +92,39 @@ class TireRepair implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) + { + // price_tier is default + if ($pt_id == 0) + return null; + + // find the item type for service offering + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'service_offering']); + if ($item_type == null) + return null; + + // find the service offering + $code = 'tire_repair_fee'; + + // check if customer vehicle has a motolite battery + // if yes, set the code to the motolite user service fee + if ($cv->hasMotoliteBattery()) + $code = 'motolite_user_service_fee'; + + $service = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); + + // check if service is null. If null, return null + if ($service == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $service->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getServiceTitle() { $title = 'Service - Flat Tire'; diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index 6e37a207..f46c95ab 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -47,13 +47,13 @@ class InvoiceManager implements InvoiceGeneratorInterface return [ new InvoiceRule\BatterySales($this->em, $this->pt_manager), new InvoiceRule\BatteryReplacementWarranty($this->em, $this->pt_manager), - new InvoiceRule\Jumpstart($this->em), - new InvoiceRule\JumpstartWarranty($this->em), - new InvoiceRule\PostRecharged($this->em), - new InvoiceRule\PostReplacement($this->em), - new InvoiceRule\Overheat($this->em), - new InvoiceRule\Fuel($this->em), - new InvoiceRule\TireRepair($this->em), + new InvoiceRule\Jumpstart($this->em, $this->pt_manager), + new InvoiceRule\JumpstartWarranty($this->em, $this->pt_manager), + new InvoiceRule\PostRecharged($this->em, $this->pt_manager), + new InvoiceRule\PostReplacement($this->em, $this->pt_manager), + new InvoiceRule\Overheat($this->em, $this->pt_manager), + new InvoiceRule\Fuel($this->em, $this->pt_manager), + new InvoiceRule\TireRepair($this->em, $this->pt_manager), new InvoiceRule\DiscountType($this->em), new InvoiceRule\TradeIn(), new InvoiceRule\Tax($this->em), -- 2.43.5 From 57fd7fe5ac1e3c49e7e608d6b5c71556f3a46c2c Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 02:23:47 -0500 Subject: [PATCH 051/119] Fix issues found during testing. #782 --- src/InvoiceRule/Fuel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InvoiceRule/Fuel.php b/src/InvoiceRule/Fuel.php index 691a1ba2..e4f365b9 100644 --- a/src/InvoiceRule/Fuel.php +++ b/src/InvoiceRule/Fuel.php @@ -158,7 +158,7 @@ class Fuel implements InvoiceRuleInterface return null; } - protected function getPriceTierItemPrice($pt_id) + protected function getPriceTierItemPrice($pt_id, CustomerVehicle $cv) { // price_tier is default if ($pt_id == 0) -- 2.43.5 From c136b0666ba4f3601e9db88baa0441079cc72f3f Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 25 Jan 2024 03:08:00 -0500 Subject: [PATCH 052/119] Fix issues found during testing. #782 --- src/InvoiceRule/Tax.php | 35 +++++++++++++++++-- src/Service/InvoiceManager.php | 2 +- .../JobOrderHandler/ResqJobOrderHandler.php | 10 ++++-- src/Service/PriceTierManager.php | 25 ++++++++++--- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/InvoiceRule/Tax.php b/src/InvoiceRule/Tax.php index b1e6a600..50834e44 100644 --- a/src/InvoiceRule/Tax.php +++ b/src/InvoiceRule/Tax.php @@ -9,14 +9,19 @@ use App\InvoiceRuleInterface; use App\Ramcar\ServiceType; use App\Entity\ServiceOffering; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; class Tax implements InvoiceRuleInterface { protected $em; + protected $pt_manager; - public function __construct(EntityManagerInterface $em) + public function __construct(EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->em = $em; + $this->pt_manager = $pt_manager; } public function getID() @@ -40,6 +45,7 @@ class Tax implements InvoiceRuleInterface // compute tax per item if service type is battery sales $stype = $criteria->getServiceType(); + $pt = $criteria->getPriceTier(); if ($stype == ServiceType::BATTERY_REPLACEMENT_NEW) { @@ -58,7 +64,13 @@ class Tax implements InvoiceRuleInterface $battery = $entry['battery']; $qty = $entry['qty']; - $price = $battery->getSellingPrice(); + // check if price tier has item price for battery + $pt_price = $this->getPriceTierItemPrice($pt, $battery); + + if ($pt_price == null) + $price = $battery->getSellingPrice(); + else + $price = $pt_price; $vat = $this->getTaxAmount($price, $tax_rate); @@ -96,6 +108,25 @@ class Tax implements InvoiceRuleInterface return null; } + protected function getPriceTierItemPrice($pt_id, $batt) + { + // price tier is default + if ($pt_id == 0) + return null; + + // find the item type battery + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + return null; + + $item_type_id = $item_type->getID(); + $item_id = $batt->getID(); + + $price = $this->pt_manager->getItemPrice($pt_id, $item_type_id, $item_id); + + return $price; + } + protected function getTaxAmount($price, $tax_rate) { $vat_ex_price = $this->getTaxExclusivePrice($price, $tax_rate); diff --git a/src/Service/InvoiceManager.php b/src/Service/InvoiceManager.php index f46c95ab..8f655224 100644 --- a/src/Service/InvoiceManager.php +++ b/src/Service/InvoiceManager.php @@ -56,7 +56,7 @@ class InvoiceManager implements InvoiceGeneratorInterface new InvoiceRule\TireRepair($this->em, $this->pt_manager), new InvoiceRule\DiscountType($this->em), new InvoiceRule\TradeIn(), - new InvoiceRule\Tax($this->em), + new InvoiceRule\Tax($this->em, $this->pt_manager), ]; } diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 28e9035d..c7c38100 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -588,7 +588,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $jo->getSource(); - // TODO: set the price tier according to location. + // get the price tier according to location. $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } @@ -822,7 +822,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface { $source = $obj->getSource(); - $this->ic->generateInvoiceCriteria($obj, $promo_id, $invoice_items, $source, $error_array); + // get the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($obj->getCoordinates()); + $this->ic->generateInvoiceCriteria($obj, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate @@ -2170,7 +2172,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // NOTE: this is CMB code but for compilation purposes we need to add this $source = $jo->getSource(); - $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $error_array); + // get the price tier according to location. + $price_tier = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $source, $price_tier, $error_array); } // validate diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index c572af76..1d8bb60c 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -51,10 +51,27 @@ class PriceTierManager return $actual_price; } - public function getPriceTier(Point $point) + public function getPriceTier(Point $coordinates) { - // TODO: get location's price tier, given a set of coordinates - // for now, hardcoded for testing purposes - return 1; + $price_tier_id = 0; + + $long = $coordinates->getLongitude(); + $lat = $coordinates->getLatitude(); + + // get location's price tier, given a set of coordinates + $query = $this->em->createQuery('SELECT s from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true'); + $area = $query->setParameter('long', $long) + ->setParameter('lat', $lat) + ->setMaxResults(1) + ->getOneOrNullResult(); + + if ($area != null) + { + $price_tier = $area->getPriceTier(); + if ($price_tier != null) + $price_tier_id = $price_tier->getID(); + } + + return $price_tier_id; } } -- 2.43.5 From 213171f4b7e2bd07a65dd826cd0983d2a04b9ab4 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 26 Jan 2024 04:44:13 -0500 Subject: [PATCH 053/119] Add price tiering for Resq 2 App and TAPI. #782 --- src/Controller/APIController.php | 5 +++ src/Controller/CAPI/RiderAppController.php | 7 ++- .../CustomerAppAPI/InvoiceController.php | 45 ++++++++++++++++++- .../CustomerAppAPI/JobOrderController.php | 15 ++++++- src/Controller/TAPI/JobOrderController.php | 16 ++++++- src/Service/PriceTierManager.php | 31 +++++++------ 6 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 16a9cdf5..0eb148c5 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -50,6 +50,7 @@ use App\Service\HubFilterLogger; use App\Service\HubFilteringGeoChecker; use App\Service\HashGenerator; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Entity\MobileSession; use App\Entity\Customer; @@ -2911,6 +2912,10 @@ class APIController extends Controller implements LoggedController // old app doesn't have separate jumpstart $icrit->setSource(TransactionOrigin::CALL); + // set price tier + $pt_id = $this->pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // check promo $promo_id = $req->request->get('promo_id'); if (!empty($promo_id)) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index d29f6a04..6cce3745 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -34,6 +34,7 @@ use App\Service\JobOrderHandlerInterface; use App\Service\InvoiceGeneratorInterface; use App\Service\RisingTideGateway; use App\Service\RiderTracker; +use App\Service\PriceTierManager; use App\Ramcar\ServiceType; use App\Ramcar\TradeInType; @@ -1099,7 +1100,7 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Batteries found.', $data); } - public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) + public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // $this->debugRequest($req); @@ -1203,6 +1204,10 @@ class RiderAppController extends ApiController $crit->setHasCoolant($jo->hasCoolant()); $crit->setIsTaxable(); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + if ($promo != null) $crit->addPromo($promo); diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index a5c3a8b8..14f1a87e 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -4,18 +4,22 @@ namespace App\Controller\CustomerAppAPI; use Symfony\Component\HttpFoundation\Request; use Catalyst\ApiBundle\Component\Response as ApiResponse; +use CrEOF\Spatial\PHP\Types\Geometry\Point; use App\Service\InvoiceGeneratorInterface; +use App\Service\PriceTierManager; use App\Ramcar\InvoiceCriteria; use App\Ramcar\TradeInType; use App\Ramcar\TransactionOrigin; use App\Entity\CustomerVehicle; use App\Entity\Promo; use App\Entity\Battery; +use App\Entity\Customer; +use App\Entity\CustomerMetadata; class InvoiceController extends ApiController { - public function getEstimate(Request $req, InvoiceGeneratorInterface $ic) + public function getEstimate(Request $req, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { // $this->debugRequest($req); @@ -36,6 +40,9 @@ class InvoiceController extends ApiController return new ApiResponse(false, 'No customer information found.'); } + // get customer location from customer_metadata using customer id + $coordinates = $this->getCustomerMetadata($cust); + // make invoice criteria $icrit = new InvoiceCriteria(); $icrit->setServiceType($req->request->get('service_type')); @@ -113,6 +120,18 @@ class InvoiceController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = 0; + if ($coordinates != null) + { + error_log('coordinates are not null'); + $pt_id = $pt_manager->getPriceTier($coordinates); + } + else + error_log('null?'); + + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); @@ -148,4 +167,28 @@ class InvoiceController extends ApiController // response return new ApiResponse(true, '', $data); } + + protected function getCustomerMetadata(Customer $cust) + { + $coordinates = null; + + // check if customer already has existing metadata + $c_meta = $this->em->getRepository(CustomerMetadata::class)->findOneBy(['customer' => $cust]); + if ($c_meta != null) + { + $meta_data = $c_meta->getAllMetaInfo(); + foreach ($meta_data as $m_info) + { + if ((isset($m_info['longitude'])) && (isset($m_info['latitude']))) + { + $lng = $m_info['longitude']; + $lat = $m_info['latitude']; + + $coordinates = new Point($lng, $lat); + } + } + } + + return $coordinates; + } } diff --git a/src/Controller/CustomerAppAPI/JobOrderController.php b/src/Controller/CustomerAppAPI/JobOrderController.php index 143f2a2e..fa5a9a85 100644 --- a/src/Controller/CustomerAppAPI/JobOrderController.php +++ b/src/Controller/CustomerAppAPI/JobOrderController.php @@ -21,6 +21,7 @@ use App\Service\HubDistributor; use App\Service\HubFilterLogger; use App\Service\HubFilteringGeoChecker; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Ramcar\ServiceType; use App\Ramcar\APIRiderStatus; use App\Ramcar\InvoiceCriteria; @@ -484,7 +485,8 @@ class JobOrderController extends ApiController HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubFilteringGeoChecker $hub_geofence, - JobOrderManager $jo_manager + JobOrderManager $jo_manager, + PriceTierManager $pt_manager ) { // validate params $validity = $this->validateRequest($req, [ @@ -698,6 +700,10 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); $jo->setInvoice($invoice); @@ -970,7 +976,8 @@ class JobOrderController extends ApiController HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, HubFilteringGeoChecker $hub_geofence, - JobOrderManager $jo_manager + JobOrderManager $jo_manager, + PriceTierManager $pt_manager ) { // validate params $validity = $this->validateRequest($req, [ @@ -1127,6 +1134,10 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::MOBILE_APP); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // send to invoice generator $invoice = $ic->generateInvoice($icrit); $jo->setInvoice($invoice); diff --git a/src/Controller/TAPI/JobOrderController.php b/src/Controller/TAPI/JobOrderController.php index f7541b50..ae4d5a61 100644 --- a/src/Controller/TAPI/JobOrderController.php +++ b/src/Controller/TAPI/JobOrderController.php @@ -46,6 +46,7 @@ use App\Service\RiderTracker; use App\Service\PromoLogger; use App\Service\MapTools; use App\Service\JobOrderManager; +use App\Service\PriceTierManager; use App\Entity\JobOrder; use App\Entity\CustomerVehicle; @@ -79,7 +80,8 @@ class JobOrderController extends ApiController FCMSender $fcmclient, RiderAssignmentHandlerInterface $rah, PromoLogger $promo_logger, HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger, - HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em, JobOrderManager $jo_manager) + HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em, JobOrderManager $jo_manager, + PriceTierManager $pt_manager) { $this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.'); @@ -165,7 +167,17 @@ class JobOrderController extends ApiController // set JO source $icrit->setSource(TransactionOrigin::THIRD_PARTY); - $icrit->addEntry($data['batt'], $data['trade_in_type'], 1); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + + // add the actual battery item first + $icrit->addEntry($data['batt'], null, 1); + + // if we have a trade in, add it as well, assuming trade in battery == battery purchased + if (!empty($data['trade_in_type'])) { + $icrit->addEntry($data['batt'], $data['trade_in_type'], 1); + } // send to invoice generator $invoice = $ic->generateInvoice($icrit); diff --git a/src/Service/PriceTierManager.php b/src/Service/PriceTierManager.php index 1d8bb60c..62d657f4 100644 --- a/src/Service/PriceTierManager.php +++ b/src/Service/PriceTierManager.php @@ -55,21 +55,24 @@ class PriceTierManager { $price_tier_id = 0; - $long = $coordinates->getLongitude(); - $lat = $coordinates->getLatitude(); - - // get location's price tier, given a set of coordinates - $query = $this->em->createQuery('SELECT s from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true'); - $area = $query->setParameter('long', $long) - ->setParameter('lat', $lat) - ->setMaxResults(1) - ->getOneOrNullResult(); - - if ($area != null) + if ($coordinates != null) { - $price_tier = $area->getPriceTier(); - if ($price_tier != null) - $price_tier_id = $price_tier->getID(); + $long = $coordinates->getLongitude(); + $lat = $coordinates->getLatitude(); + + // get location's price tier, given a set of coordinates + $query = $this->em->createQuery('SELECT s from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true'); + $area = $query->setParameter('long', $long) + ->setParameter('lat', $lat) + ->setMaxResults(1) + ->getOneOrNullResult(); + + if ($area != null) + { + $price_tier = $area->getPriceTier(); + if ($price_tier != null) + $price_tier_id = $price_tier->getID(); + } } return $price_tier_id; -- 2.43.5 From 20f5bb08e02e16d26085d3a75856b1f0b1af0f22 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 26 Jan 2024 04:50:54 -0500 Subject: [PATCH 054/119] Add checking for longitude and latitude when calling getEstimate. #782 --- src/Controller/CustomerAppAPI/InvoiceController.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Controller/CustomerAppAPI/InvoiceController.php b/src/Controller/CustomerAppAPI/InvoiceController.php index 14f1a87e..2e9779eb 100644 --- a/src/Controller/CustomerAppAPI/InvoiceController.php +++ b/src/Controller/CustomerAppAPI/InvoiceController.php @@ -41,7 +41,16 @@ class InvoiceController extends ApiController } // get customer location from customer_metadata using customer id - $coordinates = $this->getCustomerMetadata($cust); + $lng = $req->request->get('longitude'); + $lat = $req->request->get('latitude'); + + if ((empty($lng)) || (empty($lat))) + { + // use customer metadata location as basis + $coordinates = $this->getCustomerMetadata($cust); + } + else + $coordinates = new Point($lng, $lat); // make invoice criteria $icrit = new InvoiceCriteria(); -- 2.43.5 From d4eae00902393cd67cad6d5c1deab5d7970fe65d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Sun, 28 Jan 2024 22:21:34 -0500 Subject: [PATCH 055/119] Add sql for item types. #782 --- utils/item_types/item_types.sql | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 utils/item_types/item_types.sql diff --git a/utils/item_types/item_types.sql b/utils/item_types/item_types.sql new file mode 100644 index 00000000..7c5aeeba --- /dev/null +++ b/utils/item_types/item_types.sql @@ -0,0 +1,53 @@ +-- MySQL dump 10.19 Distrib 10.3.39-MariaDB, for Linux (x86_64) +-- +-- Host: localhost Database: resq +-- ------------------------------------------------------ +-- Server version 10.3.39-MariaDB + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `item_type` +-- + +DROP TABLE IF EXISTS `item_type`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `item_type` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(80) NOT NULL, + `code` varchar(80) NOT NULL, + PRIMARY KEY (`id`), + KEY `item_type_idx` (`code`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `item_type` +-- + +LOCK TABLES `item_type` WRITE; +/*!40000 ALTER TABLE `item_type` DISABLE KEYS */; +INSERT INTO `item_type` VALUES (1,'Battery','battery'),(2,'Service Offering','service_offering'); +/*!40000 ALTER TABLE `item_type` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2024-01-28 20:59:44 -- 2.43.5 From b123be25cc806bc052dea92d1490802f061f422b Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 30 Jan 2024 03:42:05 +0800 Subject: [PATCH 056/119] Add battery sizes endpoint to rider api #783 --- config/routes/capi_rider.yaml | 6 +++++ src/Controller/CAPI/RiderAppController.php | 27 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/config/routes/capi_rider.yaml b/config/routes/capi_rider.yaml index 6ef2e92a..8fc40654 100644 --- a/config/routes/capi_rider.yaml +++ b/config/routes/capi_rider.yaml @@ -94,3 +94,9 @@ capi_rider_jo_start: path: /rider_api/start controller: App\Controller\CAPI\RiderAppController::startJobOrder methods: [POST] + +# trade-ins +capi_rider_battery_sizes: + path: /rider_api/battery_sizes + controller: App\Controller\CAPI\RiderAppController::getBatterySizes + methods: [GET] \ No newline at end of file diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index d29f6a04..ea3128fd 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -758,6 +758,33 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Rider arrive at hub.', $data); } + public function getBatterySizes(Request $req, EntityManagerInterface $em) + { + // get capi user + $capi_user = $this->getUser(); + if ($capi_user == null) + return new APIResponse(false, 'User not found.'); + + // get rider id from capi user metadata + $rider = $this->getRiderFromCAPI($capi_user, $em); + if ($rider == null) + return new APIResponse(false, 'No rider found.'); + + // get sizes + $qb = $em->getRepository(BatterySize::class) + ->createQueryBuilder('bs'); + + $sizes = $qb->select('bs.id, bs.name') + ->orderBy('bs.name', 'asc') + ->getQuery() + ->getResult(); + + // response + return new APIResponse(true, '', [ + 'sizes' => $sizes, + ]); + } + public function payment(Request $req, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler, RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, TranslatorInterface $translator) { -- 2.43.5 From 0e2afaa4001ae3e56866bbfc952a79143d8a5ef1 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 01:30:09 -0500 Subject: [PATCH 057/119] Add new fields for transaction origin. #784 --- src/Ramcar/TransactionOrigin.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index a204b35f..2a742c0a 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -17,6 +17,10 @@ class TransactionOrigin extends NameValue const YOKOHAMA_TWITTER = 'yokohama_twitter'; const YOKOHAMA_INSTAGRAM = 'yokohama_instagram'; const YOKOHAMA_CAROUSELL = 'yokohama_carousell'; + const HOTLINE_MANILA = 'hotline_manila'; + const HOTLINE_CEBU = 'hotline_cebu'; + const FACEBOOK_MANILA = 'facebook_manila'; + const FACEBOOK_CEBU = 'facebook_cebu'; // TODO: for now, resq also gets the walk-in option // resq also gets new YOKOHAMA options @@ -34,5 +38,9 @@ class TransactionOrigin extends NameValue 'yokohama_twitter' => 'Yokohama Twitter', 'yokohama_instagram' => 'Yokohama Instagram', 'yokohama_carousell' => 'Yokohama Carousell', + 'hotline_manila' => 'Hotline Manila', + 'hotline_cebu' => 'Hotline Cebu', + 'facebook_manila' => 'Facebook Manila', + 'facebook_cebu' => 'Facebook Cebu' ]; } -- 2.43.5 From 9b52d4578f13f46f25d07794b31610c9f039ffbb Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:02:24 -0500 Subject: [PATCH 058/119] Add checking for discount rejection reason. #785 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 361c0b22..38571fdd 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -4252,6 +4252,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if ($rejection->getReason() == JORejectionReason::ADMINISTRATIVE) return null; + // check if reason is discount + if ($rejection->getReason() == JORejectionReason::DISCOUNT) + return null; + // sms content // Job Order # - can get from jo // Order Date and Time - get from jo -- 2.43.5 From f7c8034538693fa1453754a78931628be5d861a2 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:12:08 -0500 Subject: [PATCH 059/119] Comment out the geofence call for admin panel. #786 --- templates/job-order/form.html.twig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/templates/job-order/form.html.twig b/templates/job-order/form.html.twig index ca68e922..d0d7e834 100644 --- a/templates/job-order/form.html.twig +++ b/templates/job-order/form.html.twig @@ -1231,6 +1231,8 @@ $(function() { function selectPoint(lat, lng) { // check if point is in coverage area + // commenting out the geofence call for CRM + /* $.ajax({ method: "GET", url: "{{ url('jo_geofence') }}", @@ -1248,7 +1250,7 @@ $(function() { type: 'warning', }); } - }); + }); */ // clear markers markerLayerGroup.clearLayers(); -- 2.43.5 From 5717eddaa04f17802f0982d18fd356417f11bf63 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 30 Jan 2024 02:24:08 -0500 Subject: [PATCH 060/119] Update geofence message in the app. #787 --- src/Controller/CustomerAppAPI/ApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/CustomerAppAPI/ApiController.php b/src/Controller/CustomerAppAPI/ApiController.php index 6a25eb80..fdc0ec59 100644 --- a/src/Controller/CustomerAppAPI/ApiController.php +++ b/src/Controller/CustomerAppAPI/ApiController.php @@ -162,6 +162,6 @@ class ApiController extends BaseApiController protected function getGeoErrorMessage() { - return 'Oops! Our service is limited to some areas in Metro Manila, Laguna, Cavite, Pampanga and Baguio only. We will update you as soon as we are able to cover your area'; + return 'Our services are currently limited to some areas in Metro Manila, Baguio, Batangas, Laguna, Cavite, Pampanga, and Palawan. We will update you as soon as we are available in your area. Thank you for understanding. Keep safe!'; } } -- 2.43.5 From 33eaf9bbff1965ce6b65714bb332dae77f86b90a Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Wed, 31 Jan 2024 22:05:42 +0800 Subject: [PATCH 061/119] Fix transaction origin list to replace existing facebook and hotline with manila entries #784 --- src/Ramcar/TransactionOrigin.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Ramcar/TransactionOrigin.php b/src/Ramcar/TransactionOrigin.php index 2a742c0a..7f459e96 100644 --- a/src/Ramcar/TransactionOrigin.php +++ b/src/Ramcar/TransactionOrigin.php @@ -17,17 +17,17 @@ class TransactionOrigin extends NameValue const YOKOHAMA_TWITTER = 'yokohama_twitter'; const YOKOHAMA_INSTAGRAM = 'yokohama_instagram'; const YOKOHAMA_CAROUSELL = 'yokohama_carousell'; - const HOTLINE_MANILA = 'hotline_manila'; const HOTLINE_CEBU = 'hotline_cebu'; - const FACEBOOK_MANILA = 'facebook_manila'; const FACEBOOK_CEBU = 'facebook_cebu'; // TODO: for now, resq also gets the walk-in option // resq also gets new YOKOHAMA options const COLLECTION = [ - 'call' => 'Hotline', + 'call' => 'Hotline Manila', + 'hotline_cebu' => 'Hotline Cebu', 'online' => 'Online', - 'facebook' => 'Facebook', + 'facebook' => 'Facebook Manila', + 'facebook_cebu' => 'Facebook Cebu', 'vip' => 'VIP', 'mobile_app' => 'Mobile App', 'walk_in' => 'Walk-in', @@ -37,10 +37,6 @@ class TransactionOrigin extends NameValue 'yokohama_op_facebook' => 'Yokohama OP Facebook', 'yokohama_twitter' => 'Yokohama Twitter', 'yokohama_instagram' => 'Yokohama Instagram', - 'yokohama_carousell' => 'Yokohama Carousell', - 'hotline_manila' => 'Hotline Manila', - 'hotline_cebu' => 'Hotline Cebu', - 'facebook_manila' => 'Facebook Manila', - 'facebook_cebu' => 'Facebook Cebu' + 'yokohama_carousell' => 'Yokohama Carousell' ]; } -- 2.43.5 From 0e5365a0151ed4d5c0506553b0dd878d2f287520 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 31 Jan 2024 20:13:41 -0500 Subject: [PATCH 062/119] Comment out geofence message when viewing JO. Initialize branch_codes array. #788 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 1 + templates/job-order/form.view.html.twig | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 38571fdd..ed10c764 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -2910,6 +2910,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface $params['status_cancelled'] = JOStatus::CANCELLED; $params['hubs'] = []; + $branch_codes = []; // format duration and distance into friendly time foreach ($hubs as $hub) { // duration diff --git a/templates/job-order/form.view.html.twig b/templates/job-order/form.view.html.twig index cc463f11..33d6fc5b 100644 --- a/templates/job-order/form.view.html.twig +++ b/templates/job-order/form.view.html.twig @@ -635,6 +635,8 @@ $(function() { function selectPoint(lat, lng) { // check if point is in coverage area + // commenting out the geofence call for CRM + /* $.ajax({ method: "GET", url: "{{ url('jo_geofence') }}", @@ -652,7 +654,7 @@ $(function() { type: 'warning', }); } - }); + }); */ // clear markers markerLayerGroup.clearLayers(); -- 2.43.5 From ae46d64f5b3720ed42c68fc0b55302dfd50be562 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 1 Feb 2024 03:10:16 -0500 Subject: [PATCH 063/119] Add API call to return battery data given a serial. #783 --- config/routes/capi_rider.yaml | 7 +++- src/Controller/CAPI/RiderAppController.php | 40 ++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/config/routes/capi_rider.yaml b/config/routes/capi_rider.yaml index 8fc40654..67c7fa64 100644 --- a/config/routes/capi_rider.yaml +++ b/config/routes/capi_rider.yaml @@ -99,4 +99,9 @@ capi_rider_jo_start: capi_rider_battery_sizes: path: /rider_api/battery_sizes controller: App\Controller\CAPI\RiderAppController::getBatterySizes - methods: [GET] \ No newline at end of file + methods: [GET] + +capi_rider_battery_info: + path: /rider_api/battery/{serial} + controller: App\Controller\CAPI\RiderAppController::getBatteryInfo + methods: [GET] diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index ea3128fd..513bd3c3 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1126,6 +1126,46 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Batteries found.', $data); } + public function getBatteryInfo(Request $req, $serial, EntityManagerInterface $em) + { + if (empty($serial)) + { + return new APIResponse(false, 'Missing parameter(s): serial'); + } + + // get capi user + $capi_user = $this->getUser(); + if ($capi_user == null) + return new APIResponse(false, 'User not found.'); + + // get rider id from capi user metadata + $rider = $this->getRiderFromCAPI($capi_user, $em); + if ($rider == null) + return new APIResponse(false, 'No rider found.'); + + // find battery given serial/sap_code and flag_active is true + $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true, 'sap_code' => $serial]); + + $batt_data = []; + foreach ($batts as $batt) + { + $batt_data[] = [ + 'id' => $batt->getID(), + 'model_id' => $batt->getModel()->getID(), + 'model_name' => $batt->getModel()->getName(), + 'size_id' => $batt->getSize()->getID(), + 'size_name' => $batt->getSize()->getName(), + 'selling_price' => $batt->getSellingPrice(), + ]; + } + + $data = [ + 'batteries' => $batt_data, + ]; + + return new APIResponse(true, 'Battery info found.', $data); + } + public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) { // $this->debugRequest($req); -- 2.43.5 From 86744afde3bffd30f8b873a5469f370bcbc20a7d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 1 Feb 2024 04:24:09 -0500 Subject: [PATCH 064/119] Add serial as a parameter when rider fulfills a job order. #783 --- src/Controller/CAPI/RiderAppController.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 513bd3c3..ae1d5ee3 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -804,6 +804,15 @@ class RiderAppController extends ApiController if (!empty($msg)) return new APIResponse(false, $msg); + // need to check if service type is battery sales + // if so, serial is a required parameter + $serial = $req->request->get('serial', ''); + if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) + { + if (empty($serial)) + return new APIResponse(false, 'Missing parameter(s): serial'); + } + // set invoice to paid $jo->getInvoice()->setStatus(InvoiceStatus::PAID); @@ -855,7 +864,6 @@ class RiderAppController extends ApiController // create warranty if($jo_handler->checkIfNewBattery($jo)) { - $serial = null; $warranty_class = $jo->getWarrantyClass(); $first_name = $jo->getCustomer()->getFirstName(); $last_name = $jo->getCustomer()->getLastName(); -- 2.43.5 From c9057b9617368a208cea8d29a3663cac76838d3a Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 2 Feb 2024 04:50:03 -0500 Subject: [PATCH 065/119] Add API call to update invoice. #783 --- config/routes/capi_rider.yaml | 5 + src/Controller/CAPI/RiderAppController.php | 179 +++++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/config/routes/capi_rider.yaml b/config/routes/capi_rider.yaml index 67c7fa64..9866bb82 100644 --- a/config/routes/capi_rider.yaml +++ b/config/routes/capi_rider.yaml @@ -105,3 +105,8 @@ capi_rider_battery_info: path: /rider_api/battery/{serial} controller: App\Controller\CAPI\RiderAppController::getBatteryInfo methods: [GET] + +capi_rider_update_jo: + path: /rider_api/job_order/update + controller: App\Controller\CAPI\RiderAppController::updateJobOrder + methods: [POST] diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index ae1d5ee3..48d328bd 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1174,6 +1174,44 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Battery info found.', $data); } + public function updateJobOrder(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) + { + $items = json_decode(file_get_contents('php://input'), true); + + // get job order id + if (!isset($items['jo_id'])) + return new APIResponse(false, 'Missing parameter(s): jo_id'); + + $jo_id = $items['jo_id']; + if (empty($jo_id) || $jo_id == null) + return new APIResponse(false, 'Missing parameter(s): jo_id'); + + // validate the trade in items first + $ti_items = $items['trade_in_items']; + $msg = $this->validateTradeInItems($em, $ti_items); + if (!empty($msg)) + return new APIResponse(false, $msg); + + // get capi user + $capi_user = $this->getUser(); + if ($capi_user == null) + return new APIResponse(false, 'User not found.'); + + // get rider id from capi user metadata + $rider = $this->getRiderFromCAPI($capi_user, $em); + if ($rider == null) + return new APIResponse(false, 'No rider found.'); + + // need to get the existing invoice items using jo id and invoice id + $existing_ii = $this->getInvoiceItems($em, $jo_id); + + // $this->generateUpdatedInvoice($em, $jo_id, $existing_ii, $trade_in_items); + + $data = []; + + return new APIResponse(true, 'Job order updated.', $data); + } + public function changeService(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) { // $this->debugRequest($req); @@ -1316,6 +1354,147 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Job order service changed.', $data); } + protected function generateUpdatedInvoice(EntityManagerInterface $em, $jo_id, $existing_ii, $trade_in_items) + { + // get the job order since we need info in the JO for the invoice criteria + $jo = $em->getRepository(JobOrder::class)->find($jo_id); + + // get the service type + $stype = $jo->getServiceType(); + + // get the source + $source = $jo->getSource(); + + // get the customer vehicle + $cv = $jo->getCustomerVehicle(); + + // get the promo id from existing invoice item + $promo_id = $existing_ii['promo_id']; + if ($promo_id = null) + $promo = null; + else + $promo = $em->getRepository(Promo::class)->find($promo_id); + + // populate Invoice Criteria + $icrit = new InvoiceCriteria(); + $icrit->setServiceType($stype) + ->setCustomerVehicle($cv) + ->setSource($source) + ->setIsTaxable(); + + // at this point, all information should be valid + // assuming JO information is already valid since this + // is in the system already + // add promo if any to criteria + $icrit->addPromo($promo); + + // get the battery purchased from existing invoice items + // add the batteries ordered to criteria + $ii_items = $existing_ii['invoice_items']; + foreach ($ii_items as $ii_item) + { + $batt_id = $ii_item['batt_id']; + $qty = $ii_item['qty']; + + $battery = $em->getRepository(Battery::class)->find($batt_id); + + $icrit->addEntry($battery, null, $qty); + } + + // add the trade in items to the criteria + foreach ($trade_in_items as $ti_item) + { + // TODO: need to discuss how to store since what we have is battery size + // and we're supposed to store battery + } + + // call generateInvoice + $invoice = $ic->generateInvoice($icrit); + + // remove previous invoice + $old_invoice = $jo->getInvoice(); + $em->remove($old_invoice); + $em->flush(); + + // save new invoice + $jo->setInvoice($invoice); + $em->persist($invoice); + + // log event? + $event = new JOEvent(); + $event->setDateHappen(new DateTime()) + ->setTypeID(JOEventType::RIDER_EDIT) + ->setJobOrder($jo) + ->setRider($jo->getRider()); + $em->persist($event); + + $em->flush(); + } + + protected function getInvoiceItems(EntityManagerInterface $em, $jo_id) + { + $conn = $em->getConnection(); + + // need to get the ordered battery id and quantity from invoice item + // and the promo from invoice + $query_sql = 'SELECT ii.battery_id AS battery_id, ii.qty AS qty, i.promo_id AS promo_id + FROM invoice_item ii, invoice i + WHERE ii.invoice_id = i.id + AND i.job_order_id = :jo_id + AND ii.battery_id IS NOT NULL'; + + $query_stmt = $conn->prepare($query_sql); + $query_stmt->bindValue('jo_id', $jo_id); + + $results = $query_stmt->executeQuery(); + + $promo_id = null; + $invoice_items = []; + while ($row = $results->fetchAssociative()) + { + $promo_id = $row['promo_id']; + $invoice_items[] = [ + 'batt_id' => $row['battery_id'], + 'qty' => $row['qty'], + 'trade_in' => '' + ]; + } + + $data = [ + 'promo_id' => $promo_id, + 'invoice_items' => $invoice_items + ]; + + return $data; + } + + protected function validateTradeInItems(EntityManagerInterface $em, $ti_items) + { + $msg = ''; + foreach ($ti_items as $ti_item) + { + $bs_id = $ti_item['battery_size_id']; + $ti_type = $ti_item['trade_in_type']; + + // validate the battery size id + $batt_size = $em->getRepository(BatterySize::class)->find($bs_id); + if ($batt_size == null) + { + $msg = 'Invalid battery size for trade in: ' . $bs_id; + return $msg; + } + + // validate the trade in type + if (!TradeInType::validate($ti_type)) + { + $msg = 'Invalid trade in type: ' . $ti_type; + return $msg; + } + } + + return $msg; + } + protected function getCAPIUser($id, EntityManagerInterface $em) { $capi_user = $em->getRepository(APIUser::class)->find($id); -- 2.43.5 From 8ca7292a258a5dc25097d51a9122b7ab82cb66db Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 5 Feb 2024 03:06:06 -0500 Subject: [PATCH 066/119] Add processing of trade in items from rider app. #783 --- src/Controller/CAPI/RiderAppController.php | 17 +++++++++------ src/InvoiceRule/BatterySales.php | 11 ++++++---- src/InvoiceRule/TradeIn.php | 24 ++++++++++++++-------- src/Ramcar/InvoiceCriteria.php | 11 ++++++++++ 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 48d328bd..6dc409d6 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -23,6 +23,7 @@ use App\Entity\BatterySize; use App\Entity\RiderAPISession; use App\Entity\User; use App\Entity\ApiUser as APIUser; +use App\Entity\JobOrder; use App\Service\RedisClientProvider; use App\Service\RiderCache; @@ -1205,10 +1206,9 @@ class RiderAppController extends ApiController // need to get the existing invoice items using jo id and invoice id $existing_ii = $this->getInvoiceItems($em, $jo_id); - // $this->generateUpdatedInvoice($em, $jo_id, $existing_ii, $trade_in_items); + $this->generateUpdatedInvoice($em, $ic, $jo_id, $existing_ii, $ti_items); $data = []; - return new APIResponse(true, 'Job order updated.', $data); } @@ -1354,7 +1354,7 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Job order service changed.', $data); } - protected function generateUpdatedInvoice(EntityManagerInterface $em, $jo_id, $existing_ii, $trade_in_items) + protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, $jo_id, $existing_ii, $trade_in_items) { // get the job order since we need info in the JO for the invoice criteria $jo = $em->getRepository(JobOrder::class)->find($jo_id); @@ -1370,7 +1370,7 @@ class RiderAppController extends ApiController // get the promo id from existing invoice item $promo_id = $existing_ii['promo_id']; - if ($promo_id = null) + if ($promo_id == null) $promo = null; else $promo = $em->getRepository(Promo::class)->find($promo_id); @@ -1404,8 +1404,13 @@ class RiderAppController extends ApiController // add the trade in items to the criteria foreach ($trade_in_items as $ti_item) { - // TODO: need to discuss how to store since what we have is battery size - // and we're supposed to store battery + $batt_size_id = $ti_item['battery_size_id']; + $qty = $ti_item['qty']; + $trade_in_type = $ti_item['trade_in_type']; + + $batt_size = $em->getRepository(BatterySize::class)->find($batt_size_id); + + $icrit->addTradeInEntry($batt_size, $trade_in_type, $qty); } // call generateInvoice diff --git a/src/InvoiceRule/BatterySales.php b/src/InvoiceRule/BatterySales.php index 45b060d1..97551cb7 100644 --- a/src/InvoiceRule/BatterySales.php +++ b/src/InvoiceRule/BatterySales.php @@ -36,18 +36,21 @@ class BatterySales implements InvoiceRuleInterface $entries = $criteria->getEntries(); foreach($entries as $entry) { - $batt = $entry['battery']; $qty = $entry['qty']; $trade_in = null; + // check if entry is for trade in if (isset($entry['trade_in'])) $trade_in = $entry['trade_in']; - $size = $batt->getSize(); - + // entry is a battery purchase if ($trade_in == null) { - // battery purchase + // safe to get entry with battery key since CRM and apps + // will set this for a battery purchase and trade_in will + // will not be set + $batt = $entry['battery']; + $price = $batt->getSellingPrice(); $items[] = [ diff --git a/src/InvoiceRule/TradeIn.php b/src/InvoiceRule/TradeIn.php index 8e3c6063..224bf098 100644 --- a/src/InvoiceRule/TradeIn.php +++ b/src/InvoiceRule/TradeIn.php @@ -21,7 +21,6 @@ class TradeIn implements InvoiceRuleInterface $entries = $criteria->getEntries(); foreach($entries as $entry) { - $batt = $entry['battery']; $qty = $entry['qty']; $trade_in_type = null; @@ -30,7 +29,18 @@ class TradeIn implements InvoiceRuleInterface if ($trade_in_type != null) { - $ti_rate = $this->getTradeInRate($batt, $trade_in_type); + // at this point, entry is a trade in + // need to check if battery (coming from CRM) is set + // or battery_size is set (coming from rider app) + if (isset($entry['battery'])) + { + $battery = $entry['battery']; + $batt_size = $battery->getSize(); + } + else + $batt_size = $entry['battery_size']; + + $ti_rate = $this->getTradeInRate($batt_size, $trade_in_type); $qty_ti = bcmul($ti_rate, $qty, 2); @@ -41,7 +51,7 @@ class TradeIn implements InvoiceRuleInterface $items[] = [ 'qty' => $qty, - 'title' => $this->getTitle($batt, $trade_in_type), + 'title' => $this->getTitle($batt_size, $trade_in_type), 'price' => $price, ]; } @@ -60,10 +70,8 @@ class TradeIn implements InvoiceRuleInterface return null; } - protected function getTradeInRate($battery, $trade_in_type) + protected function getTradeInRate($size, $trade_in_type) { - $size = $battery->getSize(); - switch ($trade_in_type) { case TradeInType::MOTOLITE: @@ -77,9 +85,9 @@ class TradeIn implements InvoiceRuleInterface return 0; } - protected function getTitle($battery, $trade_in_type) + protected function getTitle($battery_size, $trade_in_type) { - $title = 'Trade-in ' . TradeInType::getName($trade_in_type) . ' ' . $battery->getSize()->getName() . ' battery'; + $title = 'Trade-in ' . TradeInType::getName($trade_in_type) . ' ' . $battery_size->getName() . ' battery'; return $title; } diff --git a/src/Ramcar/InvoiceCriteria.php b/src/Ramcar/InvoiceCriteria.php index b27395da..8b1ee18b 100644 --- a/src/Ramcar/InvoiceCriteria.php +++ b/src/Ramcar/InvoiceCriteria.php @@ -108,6 +108,17 @@ class InvoiceCriteria $this->entries[] = $entry; } + public function addTradeInEntry($battery_size, $trade_in, $qty) + { + $entry = [ + 'battery_size' => $battery_size, + 'trade_in' => $trade_in, + 'qty' => $qty + ]; + + $this->entries[] = $entry; + } + public function getEntries() { return $this->entries; -- 2.43.5 From 8860796db2eed66465e4a891146e17551f160eca Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Wed, 7 Feb 2024 15:02:47 +0800 Subject: [PATCH 067/119] Add endpoint for rider app trade-in types #783 --- config/routes/capi_rider.yaml | 5 +++++ src/Controller/CAPI/RiderAppController.php | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/config/routes/capi_rider.yaml b/config/routes/capi_rider.yaml index 9866bb82..798da1da 100644 --- a/config/routes/capi_rider.yaml +++ b/config/routes/capi_rider.yaml @@ -101,6 +101,11 @@ capi_rider_battery_sizes: controller: App\Controller\CAPI\RiderAppController::getBatterySizes methods: [GET] +capi_rider_trade_in_types: + path: /rider_api/trade_in_types + controller: App\Controller\CAPI\RiderAppController::getTradeInTypes + methods: [GET] + capi_rider_battery_info: path: /rider_api/battery/{serial} controller: App\Controller\CAPI\RiderAppController::getBatteryInfo diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 6dc409d6..945c4ec8 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -786,6 +786,27 @@ class RiderAppController extends ApiController ]); } + public function getTradeInTypes(Request $req, EntityManagerInterface $em) + { + // get capi user + $capi_user = $this->getUser(); + if ($capi_user == null) + return new APIResponse(false, 'User not found.'); + + // get rider id from capi user metadata + $rider = $this->getRiderFromCAPI($capi_user, $em); + if ($rider == null) + return new APIResponse(false, 'No rider found.'); + + // get trade-in types + $types = TradeInType::getCollection(); + + // response + return new APIResponse(true, '', [ + 'types' => $types, + ]); + } + public function payment(Request $req, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler, RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, MQTTClientApiv2 $mclientv2, FCMSender $fcmclient, TranslatorInterface $translator) { -- 2.43.5 From eebd1d93c473510400f9f336a945a662f064d43a Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 8 Feb 2024 23:17:32 +0800 Subject: [PATCH 068/119] Fix battery info endpoint to work with warranty serials instead #783 --- src/Controller/CAPI/RiderAppController.php | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 945c4ec8..19a8cd7e 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -24,7 +24,8 @@ use App\Entity\RiderAPISession; use App\Entity\User; use App\Entity\ApiUser as APIUser; use App\Entity\JobOrder; - +use App\Entity\SAPBattery; +use App\Entity\WarrantySerial; use App\Service\RedisClientProvider; use App\Service\RiderCache; use App\Service\MQTTClient; @@ -1174,26 +1175,28 @@ class RiderAppController extends ApiController return new APIResponse(false, 'No rider found.'); // find battery given serial/sap_code and flag_active is true - $batts = $em->getRepository(Battery::class)->findBy(['flag_active' => true, 'sap_code' => $serial]); + $serial = $em->getRepository(WarrantySerial::class)->find($serial); - $batt_data = []; - foreach ($batts as $batt) - { - $batt_data[] = [ - 'id' => $batt->getID(), - 'model_id' => $batt->getModel()->getID(), - 'model_name' => $batt->getModel()->getName(), - 'size_id' => $batt->getSize()->getID(), - 'size_name' => $batt->getSize()->getName(), - 'selling_price' => $batt->getSellingPrice(), - ]; + if (empty($serial)) { + return new APIResponse(false, 'Warranty serial number not found.'); } - $data = [ - 'batteries' => $batt_data, + $sap_battery = $em->getRepository(SAPBattery::class)->find($serial->getSKU()); + + if (empty($sap_battery)) { + return new APIResponse(false, 'No battery info found.'); + } + + $battery = [ + 'id' => $sap_battery->getID(), + 'brand' => $sap_battery->getBrand()->getName(), + 'size' => $sap_battery->getSize()->getName(), + 'container_size' => $sap_battery->getContainerSize()->getName(), ]; - return new APIResponse(true, 'Battery info found.', $data); + return new APIResponse(true, 'Battery info found.', [ + 'battery' => $battery, + ]); } public function updateJobOrder(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) -- 2.43.5 From abf4bbfe222c53bc4d2d2deedbb10082bf270067 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 12 Feb 2024 03:46:26 -0500 Subject: [PATCH 069/119] Add checking for promo. #783 --- src/Controller/CAPI/RiderAppController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 19a8cd7e..c88aa72d 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1410,7 +1410,8 @@ class RiderAppController extends ApiController // assuming JO information is already valid since this // is in the system already // add promo if any to criteria - $icrit->addPromo($promo); + if ($promo != null) + $icrit->addPromo($promo); // get the battery purchased from existing invoice items // add the batteries ordered to criteria -- 2.43.5 From 010bdca4587dc4fa730f7fbe8db9905d11abd4e7 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 12 Feb 2024 06:19:00 -0500 Subject: [PATCH 070/119] Add updating of other fields when updating job order. Fix issue found during testing in invoice rule. #783 --- src/Controller/CAPI/RiderAppController.php | 110 +++++++++++++++++---- src/InvoiceRule/Overheat.php | 2 +- 2 files changed, 93 insertions(+), 19 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index c88aa72d..a980be2f 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1207,15 +1207,81 @@ class RiderAppController extends ApiController if (!isset($items['jo_id'])) return new APIResponse(false, 'Missing parameter(s): jo_id'); + // validate jo_id $jo_id = $items['jo_id']; if (empty($jo_id) || $jo_id == null) return new APIResponse(false, 'Missing parameter(s): jo_id'); - // validate the trade in items first - $ti_items = $items['trade_in_items']; - $msg = $this->validateTradeInItems($em, $ti_items); - if (!empty($msg)) - return new APIResponse(false, $msg); + // get the job order + $jo = $em->getRepository(JobOrder::class)->find($jo_id); + + // check if we have trade in items + $ti_items = []; + if (isset($items['trade_in_items'])) + { + // validate the trade in items first + $ti_items = $items['trade_in_items']; + $msg = $this->validateTradeInItems($em, $ti_items); + if (!empty($msg)) + return new APIResponse(false, $msg); + } + + // get the service type + if (!isset($items['stype_id'])) + return new APIResponse(false, 'Missing parameter(s): stype_id'); + + // validate service type + $stype_id = $items['stype_id']; + if (!ServiceType::validate($stype_id)) + return new APIResponse(false, 'Invalid service type - ' . $stype_id); + + // save service type + $jo->setServiceType($stype_id); + + // validate promo if any. Promo not required + $promo = null; + if (isset($items['promo_id'])) + { + $promo_id = $items['promo_id']; + $promo = $em->getRepository(Promo::class)->find($promo_id); + if ($promo == null) + return new APIResponse(false, 'Invalid promo id - ' . $promo_id); + } + + // get other parameters, if any: has motolite battery, has warranty doc, with coolant, payment method + if (isset($items['flag_motolite_battery'])) + { + // get customer vehicle from jo + $cv = $jo->getCustomerVehicle(); + $has_motolite = $items['flag_motolite_battery']; + if ($has_motolite == 'true') + $cv->setHasMotoliteBattery(true); + else + $cv->setHasMotoliteBattery(false); + + $em->persist($cv); + + } + if (isset($items['flag_warranty_doc'])) + { + // TODO: what do we do? + } + if (isset($items['flag_coolant'])) + { + $has_coolant = $items['flag_coolant']; + if ($has_coolant == 'true') + $jo->setHasCoolant(true); + else + $jo->setHasCoolant(false); + + } + if (isset($items['mode_of_payment'])) + { + $payment_method = $items['payment_method']; + if (!ModeOfPayment::validate($payment_method)) + $payment_method = ModeOfPayment::CASH; + $jo->setModeOfPayment($payemnt_method); + } // get capi user $capi_user = $this->getUser(); @@ -1228,9 +1294,9 @@ class RiderAppController extends ApiController return new APIResponse(false, 'No rider found.'); // need to get the existing invoice items using jo id and invoice id - $existing_ii = $this->getInvoiceItems($em, $jo_id); + $existing_ii = $this->getInvoiceItems($em, $jo); - $this->generateUpdatedInvoice($em, $ic, $jo_id, $existing_ii, $ti_items); + $this->generateUpdatedInvoice($em, $ic, $jo, $existing_ii, $ti_items, $promo); $data = []; return new APIResponse(true, 'Job order updated.', $data); @@ -1378,11 +1444,9 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Job order service changed.', $data); } - protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, $jo_id, $existing_ii, $trade_in_items) + protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, JobOrder $jo, + $existing_ii, $trade_in_items, $promo) { - // get the job order since we need info in the JO for the invoice criteria - $jo = $em->getRepository(JobOrder::class)->find($jo_id); - // get the service type $stype = $jo->getServiceType(); @@ -1392,18 +1456,27 @@ class RiderAppController extends ApiController // get the customer vehicle $cv = $jo->getCustomerVehicle(); - // get the promo id from existing invoice item - $promo_id = $existing_ii['promo_id']; - if ($promo_id == null) - $promo = null; - else - $promo = $em->getRepository(Promo::class)->find($promo_id); + // get coolant if any + $flag_coolant = $jo->hasCoolant(); + + // check if new promo is null + if ($promo == null) + { + // promo not updated from app so check existing invoice + // get the promo id from existing invoice item + $promo_id = $existing_ii['promo_id']; + if ($promo_id == null) + $promo = null; + else + $promo = $em->getRepository(Promo::class)->find($promo_id); + } // populate Invoice Criteria $icrit = new InvoiceCriteria(); $icrit->setServiceType($stype) ->setCustomerVehicle($cv) ->setSource($source) + ->setHasCoolant($flag_coolant) ->setIsTaxable(); // at this point, all information should be valid @@ -1461,8 +1534,9 @@ class RiderAppController extends ApiController $em->flush(); } - protected function getInvoiceItems(EntityManagerInterface $em, $jo_id) + protected function getInvoiceItems(EntityManagerInterface $em, JobOrder $jo) { + $jo_id = $jo->getID(); $conn = $em->getConnection(); // need to get the ordered battery id and quantity from invoice item diff --git a/src/InvoiceRule/Overheat.php b/src/InvoiceRule/Overheat.php index 4c06bddb..d33c219e 100644 --- a/src/InvoiceRule/Overheat.php +++ b/src/InvoiceRule/Overheat.php @@ -94,7 +94,7 @@ class Overheat implements InvoiceRuleInterface // find the service fee using the code // if we can't find the fee, return 0 - $fee = $this->em->getRepository(ServiceOffering::class)->findOneBy($code); + $fee = $this->em->getRepository(ServiceOffering::class)->findOneBy(['code' => $code]); if ($fee == null) return 0; -- 2.43.5 From 4d89e7420f142cdd3323bd3dfd8d570506848067 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 20 Feb 2024 02:09:57 -0500 Subject: [PATCH 071/119] Add checking for location and price tier when getting list of compatible batteries. #780 --- config/routes/tapi.yaml | 2 +- .../CustomerAppAPI/VehicleController.php | 41 +++++++++++++++-- src/Controller/TAPI/BatteryController.php | 44 +++++++++++++++++-- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/config/routes/tapi.yaml b/config/routes/tapi.yaml index afa2f084..5bf1a503 100644 --- a/config/routes/tapi.yaml +++ b/config/routes/tapi.yaml @@ -51,7 +51,7 @@ tapi_vehicle_make_list: tapi_battery_list: path: /tapi/vehicles/{vid}/compatible_batteries controller: App\Controller\TAPI\BatteryController::getCompatibleBatteries - methods: [GET] + methods: [POST] # promos tapi_promo_list: diff --git a/src/Controller/CustomerAppAPI/VehicleController.php b/src/Controller/CustomerAppAPI/VehicleController.php index ba76d7a4..c8fd15e9 100644 --- a/src/Controller/CustomerAppAPI/VehicleController.php +++ b/src/Controller/CustomerAppAPI/VehicleController.php @@ -4,16 +4,19 @@ namespace App\Controller\CustomerAppAPI; use Symfony\Component\HttpFoundation\Request; use Catalyst\ApiBundle\Component\Response as ApiResponse; +use CrEOF\Spatial\PHP\Types\Geometry\Point; use App\Entity\CustomerVehicle; use App\Entity\JobOrder; use App\Entity\VehicleManufacturer; use App\Entity\Vehicle; +use App\Entity\ItemType; use App\Ramcar\JOStatus; use App\Ramcar\ServiceType; use App\Ramcar\TradeInType; use App\Ramcar\InsuranceApplicationStatus; use App\Service\PayMongoConnector; +use App\Service\PriceTierManager; use DateTime; class VehicleController extends ApiController @@ -237,7 +240,7 @@ class VehicleController extends ApiController ]); } - public function getCompatibleBatteries(Request $req, $vid) + public function getCompatibleBatteries(Request $req, $vid, PriceTierManager $pt_manager) { // validate params $validity = $this->validateRequest($req); @@ -252,11 +255,43 @@ class VehicleController extends ApiController return new ApiResponse(false, 'Invalid vehicle.'); } + // get location from request + $lng = $req->query->get('longitude', ''); + $lat = $req->query->get('latitude', ''); + + $batts = $vehicle->getActiveBatteries(); + $pt_id = 0; + if ((!(empty($lng))) && (!(empty($lat)))) + { + // get the price tier + $coordinates = new Point($lng, $lat); + + $pt_id = $pt_manager->getPriceTier($coordinates); + } + // batteries $batt_list = []; - $batts = $vehicle->getActiveBatteries(); foreach ($batts as $batt) { // TODO: Add warranty_tnv to battery information + // check if customer location is in a price tier location + if ($pt_id == 0) + $price = $batt->getSellingPrice(); + else + { + // get item type for battery + $item_type = $this->em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + $price = $batt->getSellingPrice(); + else + { + $item_type_id = $item_type->getID(); + $batt_id = $batt->getID(); + + // find the item price given price tier id and battery id + $price = $pt_manager->getItemPrice($pt_id, $item_type_id, $batt_id); + } + } + $batt_list[] = [ 'id' => $batt->getID(), 'mfg_id' => $batt->getManufacturer()->getID(), @@ -265,7 +300,7 @@ class VehicleController extends ApiController 'model_name' => $batt->getModel()->getName(), 'size_id' => $batt->getSize()->getID(), 'size_name' => $batt->getSize()->getName(), - 'price' => $batt->getSellingPrice(), + 'price' => $price, 'wty_private' => $batt->getWarrantyPrivate(), 'wty_commercial' => $batt->getWarrantyCommercial(), 'image_url' => $this->getBatteryImageURL($req, $batt), diff --git a/src/Controller/TAPI/BatteryController.php b/src/Controller/TAPI/BatteryController.php index 0705a3ab..0d38dd5f 100644 --- a/src/Controller/TAPI/BatteryController.php +++ b/src/Controller/TAPI/BatteryController.php @@ -13,6 +13,11 @@ use Catalyst\ApiBundle\Component\Response as APIResponse; use App\Ramcar\APIResult; use App\Entity\Vehicle; +use App\Entity\ItemType; + +use App\Service\PriceTierManager; + +use CrEOF\Spatial\PHP\Types\Geometry\Point; use Catalyst\AuthBundle\Service\ACLGenerator as ACLGenerator; @@ -25,7 +30,7 @@ class BatteryController extends ApiController $this->acl_gen = $acl_gen; } - public function getCompatibleBatteries(Request $req, $vid, EntityManagerInterface $em) + public function getCompatibleBatteries(Request $req, $vid, EntityManagerInterface $em, PriceTierManager $pt_manager) { $this->denyAccessUnlessGranted('tapi_battery_compatible.list', null, 'No access.'); @@ -43,13 +48,44 @@ class BatteryController extends ApiController return new APIResponse(false, $message); } + // get location from request + $lng = $req->request->get('longitude', ''); + $lat = $req->request->get('latitude', ''); + + $batts = $vehicle->getActiveBatteries(); + $pt_id = 0; + if ((!(empty($lng))) && (!(empty($lat)))) + { + // get the price tier + $coordinates = new Point($lng, $lat); + + $pt_id = $pt_manager->getPriceTier($coordinates); + } + // batteries $batt_list = []; - // $batts = $vehicle->getBatteries(); - $batts = $vehicle->getActiveBatteries(); foreach ($batts as $batt) { // TODO: Add warranty_tnv to battery information + // check if customer location is in a price tier location + if ($pt_id == 0) + $price = $batt->getSellingPrice(); + else + { + // get item type for battery + $item_type = $em->getRepository(ItemType::class)->findOneBy(['code' => 'battery']); + if ($item_type == null) + $price = $batt->getSellingPrice(); + else + { + $item_type_id = $item_type->getID(); + $batt_id = $batt->getID(); + + // find the item price given price tier id and battery id + $price = $pt_manager->getItemPrice($pt_id, $item_type_id, $batt_id); + } + } + $batt_list[] = [ 'id' => $batt->getID(), 'mfg_id' => $batt->getManufacturer()->getID(), @@ -58,7 +94,7 @@ class BatteryController extends ApiController 'model_name' => $batt->getModel()->getName(), 'size_id' => $batt->getSize()->getID(), 'size_name' => $batt->getSize()->getName(), - 'price' => $batt->getSellingPrice(), + 'price' => $price, 'wty_private' => $batt->getWarrantyPrivate(), 'wty_commercial' => $batt->getWarrantyCommercial(), 'image_url' => $this->getBatteryImageURL($req, $batt), -- 2.43.5 From 7a5583d840d5bf3c2c7f6782512c8d5fbd21b07c Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 22 Feb 2024 16:08:36 +0800 Subject: [PATCH 072/119] Include trade in type and container size to battery info rider api call #783 --- src/Controller/CAPI/RiderAppController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index a980be2f..cf0b26ab 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1191,6 +1191,8 @@ class RiderAppController extends ApiController 'id' => $sap_battery->getID(), 'brand' => $sap_battery->getBrand()->getName(), 'size' => $sap_battery->getSize()->getName(), + 'size_id' => $sap_battery->getSize()->getID(), + 'trade_in_type' => TradeInType::MOTOLITE, 'container_size' => $sap_battery->getContainerSize()->getName(), ]; -- 2.43.5 From 270a4cfb1082a041ff8daae760e7e45e173638a0 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 22 Feb 2024 16:51:26 +0800 Subject: [PATCH 073/119] Add endpoint for insurance premiums banner #791 --- .gitignore | 1 + config/routes/apiv2.yaml | 5 +++++ config/services.yaml | 1 + .../CustomerAppAPI/InsuranceController.php | 14 ++++++++++++++ 4 files changed, 21 insertions(+) diff --git a/.gitignore b/.gitignore index cf3b012e..c99c0c14 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ *.swp /public/warranty_uploads/* +.vscode diff --git a/config/routes/apiv2.yaml b/config/routes/apiv2.yaml index 9f183530..deb3b11b 100644 --- a/config/routes/apiv2.yaml +++ b/config/routes/apiv2.yaml @@ -303,3 +303,8 @@ apiv2_insurance_application_create: path: /apiv2/insurance/application controller: App\Controller\CustomerAppAPI\InsuranceController::createApplication methods: [POST] + +apiv2_insurance_premiums_banner: + path: /apiv2/insurance/premiums_banner + controller: App\Controller\CustomerAppAPI\InsuranceController::getPremiumsBanner + methods: [GET] \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml index b19ecabc..4cd646ec 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -15,6 +15,7 @@ parameters: api_version: "%env(API_VERSION)%" android_app_version: "%env(ANDROID_APP_VERSION)%" ios_app_version: "%env(IOS_APP_VERSION)%" + insurance_premiums_banner_url: "%env(INSURANCE_PREMIUMS_BANNER_URL)%" services: # default configuration for services in *this* file diff --git a/src/Controller/CustomerAppAPI/InsuranceController.php b/src/Controller/CustomerAppAPI/InsuranceController.php index a3c5624a..8685060b 100644 --- a/src/Controller/CustomerAppAPI/InsuranceController.php +++ b/src/Controller/CustomerAppAPI/InsuranceController.php @@ -293,6 +293,20 @@ class InsuranceController extends ApiController ]); } + public function getPremiumsBanner(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + return new ApiResponse(true, '', [ + 'url' => $this->getParameter('insurance_premiums_banner_url'), + ]); + } + protected function getLineType($mv_type_id, $vehicle_use_type, $is_public = false) { $line = ''; -- 2.43.5 From 78a43ae85cab59d4e9413df4f1160722892112f4 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Fri, 23 Feb 2024 16:53:04 +0800 Subject: [PATCH 074/119] Add insurance body types endpoint #791 --- config/routes/apiv2.yaml | 5 +++++ .../CustomerAppAPI/InsuranceController.php | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/config/routes/apiv2.yaml b/config/routes/apiv2.yaml index deb3b11b..dc603c9f 100644 --- a/config/routes/apiv2.yaml +++ b/config/routes/apiv2.yaml @@ -307,4 +307,9 @@ apiv2_insurance_application_create: apiv2_insurance_premiums_banner: path: /apiv2/insurance/premiums_banner controller: App\Controller\CustomerAppAPI\InsuranceController::getPremiumsBanner + methods: [GET] + +apiv2_insurance_body_types: + path: /apiv2/insurance/body_types + controller: App\Controller\CustomerAppAPI\InsuranceController::getBodyTypes methods: [GET] \ No newline at end of file diff --git a/src/Controller/CustomerAppAPI/InsuranceController.php b/src/Controller/CustomerAppAPI/InsuranceController.php index 8685060b..cc7832eb 100644 --- a/src/Controller/CustomerAppAPI/InsuranceController.php +++ b/src/Controller/CustomerAppAPI/InsuranceController.php @@ -307,6 +307,27 @@ class InsuranceController extends ApiController ]); } + public function getBodyTypes(Request $req) + { + // validate params + $validity = $this->validateRequest($req); + + if (!$validity['is_valid']) { + return new ApiResponse(false, $validity['error']); + } + + // TODO: if this changes often, make an entity and make it manageable on CRM + $body_types = [ + 'SEDAN' => 'Sedan', + 'SUV' => 'SUV', + 'TRUCK' => 'Truck', + ]; + + return new ApiResponse(true, '', [ + 'body_types' => $body_types, + ]); + } + protected function getLineType($mv_type_id, $vehicle_use_type, $is_public = false) { $line = ''; -- 2.43.5 From 4dd8efd95a4f648a2811a08f3b659f5d3e398bb8 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Fri, 23 Feb 2024 18:39:21 +0800 Subject: [PATCH 075/119] Fix returned format of body types endpoint #791 --- .../CustomerAppAPI/InsuranceController.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Controller/CustomerAppAPI/InsuranceController.php b/src/Controller/CustomerAppAPI/InsuranceController.php index cc7832eb..9d302549 100644 --- a/src/Controller/CustomerAppAPI/InsuranceController.php +++ b/src/Controller/CustomerAppAPI/InsuranceController.php @@ -318,9 +318,18 @@ class InsuranceController extends ApiController // TODO: if this changes often, make an entity and make it manageable on CRM $body_types = [ - 'SEDAN' => 'Sedan', - 'SUV' => 'SUV', - 'TRUCK' => 'Truck', + [ + 'id' => 'SEDAN', + 'name' => 'Sedan', + ], + [ + 'id' => 'SUV', + 'name' => 'SUV', + ], + [ + 'id' => 'TRUCK', + 'name' => 'Truck', + ] ]; return new ApiResponse(true, '', [ -- 2.43.5 From a4b883b7ea486bc419cd6dabbc31bd735239b62c Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 7 Mar 2024 23:39:57 +0800 Subject: [PATCH 076/119] Fix rider assign MQTT event for new rider app #783 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 1 + src/Service/MQTTClient.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 71f91357..419c27c3 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -2021,6 +2021,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface // NOTE: for resq2 app $mclientv2->sendEvent($obj, $payload); + $mclientv2->sendRiderEvent($obj, $payload); $fcmclient->sendJoEvent($obj, "jo_fcm_title_driver_assigned", "jo_fcm_body_driver_assigned"); } diff --git a/src/Service/MQTTClient.php b/src/Service/MQTTClient.php index 00229f5f..f1f3f2b3 100644 --- a/src/Service/MQTTClient.php +++ b/src/Service/MQTTClient.php @@ -89,6 +89,6 @@ class MQTTClient */ // NOTE: this is for the new rider app - $this->publish('rider/' . $rider->getID(), json_encode($payload)); + $this->publish('rider/' . $rider->getID() . '/delivery', json_encode($payload)); } } -- 2.43.5 From d603934d933ee755a802770f0c53d22f2332e57b Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 7 Mar 2024 23:41:21 +0800 Subject: [PATCH 077/119] Update the correct MQTT client with latest changes #783 --- src/Service/MQTTClient.php | 2 +- src/Service/MQTTClientApiv2.php | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Service/MQTTClient.php b/src/Service/MQTTClient.php index f1f3f2b3..00229f5f 100644 --- a/src/Service/MQTTClient.php +++ b/src/Service/MQTTClient.php @@ -89,6 +89,6 @@ class MQTTClient */ // NOTE: this is for the new rider app - $this->publish('rider/' . $rider->getID() . '/delivery', json_encode($payload)); + $this->publish('rider/' . $rider->getID(), json_encode($payload)); } } diff --git a/src/Service/MQTTClientApiv2.php b/src/Service/MQTTClientApiv2.php index 42b85648..f819be53 100644 --- a/src/Service/MQTTClientApiv2.php +++ b/src/Service/MQTTClientApiv2.php @@ -68,4 +68,31 @@ class MQTTClientApiv2 // error_log('sent to ' . $channel); } } + + public function sendRiderEvent(JobOrder $job_order, $payload) + { + // check if a rider is available + $rider = $job_order->getRider(); + if ($rider == null) + return; + + /* + // NOTE: this is for the old rider app + // check if rider has sessions + $sessions = $rider->getSessions(); + if (count($sessions) == 0) + return; + + // send to every rider session + foreach ($sessions as $sess) + { + $sess_id = $sess->getID(); + $channel = self::RIDER_PREFIX . $sess_id; + $this->publish($channel, json_encode($payload)); + } + */ + + // NOTE: this is for the new rider app + $this->publish('rider/' . $rider->getID() . '/delivery', json_encode($payload)); + } } -- 2.43.5 From 801a274e8c167d295c94e5fa98e632b37f4ab7c2 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Mon, 11 Mar 2024 23:45:05 +0800 Subject: [PATCH 078/119] Disable serial number requirement on rider api to allow old rider app to work for now #783 --- src/Controller/CAPI/RiderAppController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index f5c2a558..3bd5e4e8 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -834,7 +834,8 @@ class RiderAppController extends ApiController if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) { if (empty($serial)) - return new APIResponse(false, 'Missing parameter(s): serial'); + // TODO: serial is required but disabling for now so old rider app works + //return new APIResponse(false, 'Missing parameter(s): serial'); } // set invoice to paid -- 2.43.5 From 175ac927658e3be3dc61111649a319fd5da4f40f Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Mon, 11 Mar 2024 23:50:44 +0800 Subject: [PATCH 079/119] Fix syntax error on rider api controller #783 --- src/Controller/CAPI/RiderAppController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 3bd5e4e8..e23d2350 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -833,9 +833,10 @@ class RiderAppController extends ApiController $serial = $req->request->get('serial', ''); if ($jo->getServiceType() == ServiceType::BATTERY_REPLACEMENT_NEW) { + /* if (empty($serial)) - // TODO: serial is required but disabling for now so old rider app works - //return new APIResponse(false, 'Missing parameter(s): serial'); + return new APIResponse(false, 'Missing parameter(s): serial'); + */ } // set invoice to paid -- 2.43.5 From 9f4c16b1492f82dc35ae6d811ec68800b68cecbc Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 12 Mar 2024 16:34:21 +0800 Subject: [PATCH 080/119] Add debug code for insurance api #783 --- src/Service/InsuranceConnector.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Service/InsuranceConnector.php b/src/Service/InsuranceConnector.php index b56415c0..0b732f65 100644 --- a/src/Service/InsuranceConnector.php +++ b/src/Service/InsuranceConnector.php @@ -111,6 +111,8 @@ class InsuranceConnector error_log("Insurance API Error: " . $error['message']); error_log(Psr7\Message::toString($e->getRequest())); error_log($e->getResponse()->getBody()->getContents()); + error_log("Insurance Creds: " . $this->username . ", " . $this->password); + error_log("Insurance Hash: " . $this->generateHash()); if ($e->hasResponse()) { $error['response'] = Psr7\Message::toString($e->getResponse()); -- 2.43.5 From 47dcd92474c55b8eb9ce2b737b9ebfbd71985cd9 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Wed, 13 Mar 2024 07:09:56 +0800 Subject: [PATCH 081/119] Refactor insurance, paymongo connector logging logic #783 --- src/Controller/InsuranceController.php | 18 +++++---------- src/Controller/PayMongoController.php | 17 +++++--------- src/Service/InsuranceConnector.php | 32 ++++++++++++++++++++++---- src/Service/PayMongoConnector.php | 32 +++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/Controller/InsuranceController.php b/src/Controller/InsuranceController.php index 97744d27..cf3f9967 100644 --- a/src/Controller/InsuranceController.php +++ b/src/Controller/InsuranceController.php @@ -4,6 +4,7 @@ namespace App\Controller; use App\Ramcar\InsuranceApplicationStatus; use App\Service\FCMSender; +use App\Service\InsuranceConnector; use App\Entity\InsuranceApplication; use Doctrine\ORM\EntityManagerInterface; @@ -15,11 +16,13 @@ use DateTime; class InsuranceController extends Controller { + protected $ic; protected $em; protected $fcmclient; - public function __construct(EntityManagerInterface $em, FCMSender $fcmclient) + public function __construct(InsuranceConnector $ic, EntityManagerInterface $em, FCMSender $fcmclient) { + $this->ic = $ic; $this->em = $em; $this->fcmclient = $fcmclient; } @@ -28,17 +31,8 @@ class InsuranceController extends Controller { $payload = $req->request->all(); - // DEBUG - @file_put_contents(__DIR__ . '/../../var/log/insurance.log', print_r($payload, true) . "\r\n----------------------------------------\r\n\r\n", FILE_APPEND); - error_log(print_r($payload, true)); - - /* - return $this->json([ - 'success' => true, - ]); - */ - - // END DEBUG + // log this callback + $this->ic->log('CALLBACK', "[]", json_encode($payload), 'callback'); // if no transaction code given, silently fail if (empty($payload['transaction_code'])) { diff --git a/src/Controller/PayMongoController.php b/src/Controller/PayMongoController.php index 02f75928..21cd864c 100644 --- a/src/Controller/PayMongoController.php +++ b/src/Controller/PayMongoController.php @@ -4,6 +4,7 @@ namespace App\Controller; use App\Entity\GatewayTransaction; use App\Ramcar\TransactionStatus; +use App\Service\PayMongoConnector; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\Request; @@ -12,10 +13,12 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller; class PayMongoController extends Controller { + protected $pm; protected $em; - public function __construct(EntityManagerInterface $em) + public function __construct(PayMongoConnector $pm, EntityManagerInterface $em) { + $this->pm = $pm; $this->em = $em; } @@ -23,16 +26,8 @@ class PayMongoController extends Controller { $payload = json_decode($req->getContent(), true); - // DEBUG - @file_put_contents(__DIR__ . '/../../var/log/paymongo.log', print_r($payload, true) . "\r\n----------------------------------------\r\n\r\n", FILE_APPEND); - - /* - return $this->json([ - 'success' => true, - ]); - */ - - // END DEBUG + // log this callback + $this->pm->log('CALLBACK', "[]", $req->getContent(), 'callback'); // if no event type given, silently fail if (empty($payload['data'])) { diff --git a/src/Service/InsuranceConnector.php b/src/Service/InsuranceConnector.php index 0b732f65..9ad10847 100644 --- a/src/Service/InsuranceConnector.php +++ b/src/Service/InsuranceConnector.php @@ -91,7 +91,7 @@ class InsuranceConnector return base64_encode($this->username . ":" . $this->password); } - protected function doRequest($url, $method, $body = []) + protected function doRequest($url, $method, $request_body = []) { $client = new Client(); $headers = [ @@ -102,7 +102,7 @@ class InsuranceConnector try { $response = $client->request($method, $this->base_url . '/' . $url, [ - 'json' => $body, + 'json' => $request_body, 'headers' => $headers, ]); } catch (RequestException $e) { @@ -114,6 +114,9 @@ class InsuranceConnector error_log("Insurance Creds: " . $this->username . ", " . $this->password); error_log("Insurance Hash: " . $this->generateHash()); + // log this error + $this->log($url, Psr7\Message::toString($e->getRequest()), Psr7\Message::toString($e->getResponse()), 'error'); + if ($e->hasResponse()) { $error['response'] = Psr7\Message::toString($e->getResponse()); } @@ -124,11 +127,32 @@ class InsuranceConnector ]; } - error_log(print_r(json_decode($response->getBody(), true), true)); + $result_body = $response->getBody(); + + // log response + $this->log($url, json_encode($request_body), $result_body); return [ 'success' => true, - 'response' => json_decode($response->getBody(), true) + 'response' => json_decode($result_body, true), ]; } + + // TODO: make this more elegant + public function log($title, $request_body = "[]", $result_body = "[]", $type = 'api') + { + $filename = '/../../var/log/insurance_' . $type . '.log'; + $date = date("Y-m-d H:i:s"); + + // build log entry + $entry = implode("\r\n", [ + $date, + $title, + "REQUEST:\r\n" . $request_body, + "RESPONSE:\r\n" . $result_body, + "\r\n----------------------------------------\r\n\r\n", + ]); + + @file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND); + } } diff --git a/src/Service/PayMongoConnector.php b/src/Service/PayMongoConnector.php index ad2750a2..c34a94e7 100644 --- a/src/Service/PayMongoConnector.php +++ b/src/Service/PayMongoConnector.php @@ -79,7 +79,7 @@ class PayMongoConnector return base64_encode($this->secret_key); } - protected function doRequest($url, $method, $body = []) + protected function doRequest($url, $method, $request_body = []) { $client = new Client(); $headers = [ @@ -90,14 +90,14 @@ class PayMongoConnector try { $response = $client->request($method, $this->base_url . '/' . $url, [ - 'json' => $body, + 'json' => $request_body, 'headers' => $headers, ]); } catch (RequestException $e) { $error = ['message' => $e->getMessage()]; ob_start(); - var_dump($body); + //var_dump($request_body); $varres = ob_get_clean(); error_log($varres); @@ -107,6 +107,9 @@ class PayMongoConnector error_log("PayMongo API Error: " . $error['message']); error_log(Psr7\Message::toString($e->getRequest())); + // log this error + $this->log($url, Psr7\Message::toString($e->getRequest()), Psr7\Message::toString($e->getResponse()), 'error'); + if ($e->hasResponse()) { $error['response'] = Psr7\Message::toString($e->getResponse()); } @@ -117,9 +120,32 @@ class PayMongoConnector ]; } + $result_body = $response->getBody(); + + // log response + $this->log($url, json_encode($request_body), $result_body); + return [ 'success' => true, 'response' => json_decode($response->getBody(), true) ]; } + + // TODO: make this more elegant + public function log($title, $request_body = "[]", $result_body = "[]", $type = 'api') + { + $filename = '/../../var/log/paymongo_' . $type . '.log'; + $date = date("Y-m-d H:i:s"); + + // build log entry + $entry = implode("\r\n", [ + $date, + $title, + "REQUEST:\r\n" . $request_body, + "RESPONSE:\r\n" . $result_body, + "\r\n----------------------------------------\r\n\r\n", + ]); + + @file_put_contents(__DIR__ . $filename, $entry, FILE_APPEND); + } } -- 2.43.5 From 69218aecf4a65e6a07c9c5cfcb4e8365fc4016e9 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Wed, 13 Mar 2024 14:33:29 +0800 Subject: [PATCH 082/119] Update insurance application paid call to use external transaction id #783 --- src/EntityListener/GatewayTransactionListener.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EntityListener/GatewayTransactionListener.php b/src/EntityListener/GatewayTransactionListener.php index 745fc5f9..c9007aaf 100644 --- a/src/EntityListener/GatewayTransactionListener.php +++ b/src/EntityListener/GatewayTransactionListener.php @@ -66,7 +66,7 @@ class GatewayTransactionListener } // flag on api as paid - $result = $this->ic->tagApplicationPaid($obj->getID()); + $result = $this->ic->tagApplicationPaid($obj->getExtTransactionId()); if (!$result['success'] || $result['response']['transaction_code'] !== 'GR004') { error_log("INSURANCE MARK AS PAID FAILED FOR " . $obj->getID() . ": " . $result['error']['message']); } -- 2.43.5 From a59aa0f66deaf1510173b6028cf0824f7e89a49e Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Thu, 14 Mar 2024 13:40:37 +0800 Subject: [PATCH 083/119] Make insurance body types a namevalue class #783 --- .../CustomerAppAPI/InsuranceController.php | 26 ++++++++----------- src/Ramcar/InsuranceBodyType.php | 18 +++++++++++++ 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 src/Ramcar/InsuranceBodyType.php diff --git a/src/Controller/CustomerAppAPI/InsuranceController.php b/src/Controller/CustomerAppAPI/InsuranceController.php index 9d302549..271ebdb8 100644 --- a/src/Controller/CustomerAppAPI/InsuranceController.php +++ b/src/Controller/CustomerAppAPI/InsuranceController.php @@ -18,6 +18,7 @@ use App\Ramcar\InsuranceApplicationStatus; use App\Ramcar\InsuranceMVType; use App\Ramcar\InsuranceClientType; use App\Ramcar\TransactionStatus; +use App\Ramcar\InsuranceBodyType; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use DateTime; @@ -316,21 +317,16 @@ class InsuranceController extends ApiController return new ApiResponse(false, $validity['error']); } - // TODO: if this changes often, make an entity and make it manageable on CRM - $body_types = [ - [ - 'id' => 'SEDAN', - 'name' => 'Sedan', - ], - [ - 'id' => 'SUV', - 'name' => 'SUV', - ], - [ - 'id' => 'TRUCK', - 'name' => 'Truck', - ] - ]; + $bt_collection = InsuranceBodyType::getCollection(); + $body_types = []; + + // NOTE: formatting it this way to match how insurance third party API returns their own stuff, so it's all handled one way on the app + foreach ($bt_collection as $bt_key => $bt_name) { + $body_types[] = [ + 'id' => $bt_key, + 'name' => $bt_name, + ]; + } return new ApiResponse(true, '', [ 'body_types' => $body_types, diff --git a/src/Ramcar/InsuranceBodyType.php b/src/Ramcar/InsuranceBodyType.php new file mode 100644 index 00000000..2abffcdc --- /dev/null +++ b/src/Ramcar/InsuranceBodyType.php @@ -0,0 +1,18 @@ + 'Sedan', + 'SUV' => 'SUV', + 'TRUCK' => 'Truck', + 'MOTORCYCLE' => 'Motorcycle', + ]; +} -- 2.43.5 From bff89a68172dddb101750354495b60a81d4bdc65 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Fri, 15 Mar 2024 16:24:09 +0800 Subject: [PATCH 084/119] Add regional pricing support to job order updates on rider app #783 --- src/Controller/CAPI/RiderAppController.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index e23d2350..ad99e56c 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1204,7 +1204,7 @@ class RiderAppController extends ApiController ]); } - public function updateJobOrder(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic) + public function updateJobOrder(Request $req, EntityManagerInterface $em, InvoiceGeneratorInterface $ic, PriceTierManager $pt_manager) { $items = json_decode(file_get_contents('php://input'), true); @@ -1301,7 +1301,7 @@ class RiderAppController extends ApiController // need to get the existing invoice items using jo id and invoice id $existing_ii = $this->getInvoiceItems($em, $jo); - $this->generateUpdatedInvoice($em, $ic, $jo, $existing_ii, $ti_items, $promo); + $this->generateUpdatedInvoice($em, $ic, $jo, $existing_ii, $ti_items, $promo, $pt_manager); $data = []; return new APIResponse(true, 'Job order updated.', $data); @@ -1453,8 +1453,7 @@ class RiderAppController extends ApiController return new APIResponse(true, 'Job order service changed.', $data); } - protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, JobOrder $jo, - $existing_ii, $trade_in_items, $promo) + protected function generateUpdatedInvoice(EntityManagerInterface $em, InvoiceGeneratorInterface $ic, JobOrder $jo, $existing_ii, $trade_in_items, $promo, PriceTierManager $pt_manager) { // get the service type $stype = $jo->getServiceType(); @@ -1488,6 +1487,10 @@ class RiderAppController extends ApiController ->setHasCoolant($flag_coolant) ->setIsTaxable(); + // set price tier + $pt_id = $pt_manager->getPriceTier($jo->getCoordinates()); + $icrit->setPriceTier($pt_id); + // at this point, all information should be valid // assuming JO information is already valid since this // is in the system already -- 2.43.5 From 9152370300fd1fe4af02dd625cce35c05851f5a2 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 19 Mar 2024 15:22:34 +0800 Subject: [PATCH 085/119] Add checks to prevent JO progression if cancelled #793 --- src/Controller/CAPI/RiderAppController.php | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index ad99e56c..487133a6 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -411,6 +411,9 @@ class RiderAppController extends ApiController if (!empty($msg)) return new APIResponse(false, $msg); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center // set jo status to in transit @@ -461,6 +464,9 @@ class RiderAppController extends ApiController // TODO: this is a workaround for requeue, because rider app gets stuck in accept / decline screen return new APIResponse(true, $msg); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // requeue it, instead of cancelling it $jo->requeue(); @@ -519,6 +525,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB); @@ -559,6 +568,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_PRE_JO); @@ -599,6 +611,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_PRE_JO); @@ -639,6 +654,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_START); @@ -680,6 +698,9 @@ class RiderAppController extends ApiController // set jo status to in progress $jo->setStatus(JOStatus::IN_PROGRESS); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE); @@ -738,6 +759,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB); @@ -828,6 +852,9 @@ class RiderAppController extends ApiController if (!empty($msg)) return new APIResponse(false, $msg); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // need to check if service type is battery sales // if so, serial is a required parameter $serial = $req->request->get('serial', ''); @@ -973,6 +1000,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_POST_JO); @@ -1014,6 +1044,9 @@ class RiderAppController extends ApiController // get rider's current job order $jo = $rider->getCurrentJobOrder(); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_POST_JO); @@ -1217,9 +1250,22 @@ class RiderAppController extends ApiController if (empty($jo_id) || $jo_id == null) return new APIResponse(false, 'Missing parameter(s): jo_id'); + // get capi user + $capi_user = $this->getUser(); + if ($capi_user == null) + return new APIResponse(false, 'User not found.'); + + // get rider id from capi user metadata + $rider = $this->getRiderFromCAPI($capi_user, $em); + if ($rider == null) + return new APIResponse(false, 'No rider found.'); + // get the job order $jo = $em->getRepository(JobOrder::class)->find($jo_id); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // check if we have trade in items $ti_items = []; if (isset($items['trade_in_items'])) @@ -1328,6 +1374,9 @@ class RiderAppController extends ApiController if (!empty($msg)) return new APIResponse(false, $msg); + // check if JO can be modified first + $this->allowJOProgress($jo, $rider); + // check service type $stype_id = $req->request->get('stype_id'); if (!ServiceType::validate($stype_id)) @@ -1690,6 +1739,24 @@ class RiderAppController extends ApiController return $msg; } + protected function allowJOProgress($rider, JobOrder $jo) + { + // TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working. + switch ($jo->getStatus()) + { + case JOStatus::CANCELLED: + // if this is the rider's current JO, set to null + if ($rider->getCurrentJobOrder() === $jo) { + $rider->setCurrentJobOrder(); + } + + return new APIResponse(false, 'Job order can no longer be modified.'); + break; + default: + return true; + } + } + protected function debugRequest(Request $req) { $all = $req->request->all(); -- 2.43.5 From ca513355fe74970e377e02de9c058e3560a0a869 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 19 Mar 2024 15:25:32 +0800 Subject: [PATCH 086/119] Switch parameters of allowJOProgress to fix error #793 --- src/Controller/CAPI/RiderAppController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 487133a6..e54ed55c 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -1739,7 +1739,7 @@ class RiderAppController extends ApiController return $msg; } - protected function allowJOProgress($rider, JobOrder $jo) + protected function allowJOProgress(JobOrder $jo, $rider) { // TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working. switch ($jo->getStatus()) -- 2.43.5 From 1a6af003996d0344dd4d6d22bb688a089ca33cb1 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 19 Mar 2024 16:35:51 +0800 Subject: [PATCH 087/119] Rename JO progression check method #793 --- src/Controller/CAPI/RiderAppController.php | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index e54ed55c..0141617f 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -412,7 +412,7 @@ class RiderAppController extends ApiController return new APIResponse(false, $msg); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // TODO: refactor this into a jo handler class, so we don't have to repeat for control center @@ -465,7 +465,7 @@ class RiderAppController extends ApiController return new APIResponse(true, $msg); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // requeue it, instead of cancelling it $jo->requeue(); @@ -526,7 +526,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB); @@ -569,7 +569,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_PRE_JO); @@ -612,7 +612,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_PRE_JO); @@ -655,7 +655,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_START); @@ -699,7 +699,7 @@ class RiderAppController extends ApiController $jo->setStatus(JOStatus::IN_PROGRESS); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE); @@ -760,7 +760,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB); @@ -853,7 +853,7 @@ class RiderAppController extends ApiController return new APIResponse(false, $msg); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // need to check if service type is battery sales // if so, serial is a required parameter @@ -1001,7 +1001,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_ARRIVE_HUB_POST_JO); @@ -1045,7 +1045,7 @@ class RiderAppController extends ApiController $jo = $rider->getCurrentJobOrder(); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // set delivery status $jo->setDeliveryStatus(DeliveryStatus::RIDER_DEPART_HUB_POST_JO); @@ -1264,7 +1264,7 @@ class RiderAppController extends ApiController $jo = $em->getRepository(JobOrder::class)->find($jo_id); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // check if we have trade in items $ti_items = []; @@ -1375,7 +1375,7 @@ class RiderAppController extends ApiController return new APIResponse(false, $msg); // check if JO can be modified first - $this->allowJOProgress($jo, $rider); + $this->checkJOProgressionAllowed($jo, $rider); // check service type $stype_id = $req->request->get('stype_id'); @@ -1739,7 +1739,7 @@ class RiderAppController extends ApiController return $msg; } - protected function allowJOProgress(JobOrder $jo, $rider) + protected function checkJOProgressionAllowed(JobOrder $jo, $rider) { // TODO: add more statuses to block if needed, hence. this is a failsafe in case MQTT is not working. switch ($jo->getStatus()) -- 2.43.5 From c4e03f861de0fffecad5ed0f3c2df3a2fa8b2611 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 19 Mar 2024 17:33:13 +0800 Subject: [PATCH 088/119] Exclude cancelled JOs on rider app API #783 --- src/Controller/CAPI/RiderAppController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 0141617f..694ffdd0 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -289,8 +289,9 @@ class RiderAppController extends ApiController // do we have a job order? // $jo = $rider->getActiveJobOrder(); + // NOTE: we do not include job orders that have been cancelled $jo = $rider->getCurrentJobOrder(); - if ($jo == null) + if ($jo == null || $jo->getStatus() == JOStatus::CANCELLED) { $data = [ 'job_order' => null -- 2.43.5 From 07b459e7a3810d6ab3e5f02433a3bc5104ca1669 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Tue, 19 Mar 2024 19:16:34 +0800 Subject: [PATCH 089/119] Add pycache and test insurance banner to gitignore #783 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index c99c0c14..2e46e65c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ *.swp /public/warranty_uploads/* .vscode +*__pycache__ +/public/assets/images/insurance-premiums.png \ No newline at end of file -- 2.43.5 From 5af3a3cb5ed3d59cdf5ee9a97cae2d982856b38b Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Sat, 23 Mar 2024 04:01:16 +0800 Subject: [PATCH 090/119] Add check for if serial is present before registering warranty #783 --- src/Controller/CAPI/RiderAppController.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index 694ffdd0..a4b50099 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -953,7 +953,11 @@ class RiderAppController extends ApiController // for riders, use rider id $user_id = $rider->getID(); $source = WarrantySource::RAPI; - $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class, $user_id, $source, $jo->getCustomer(), $jo->getCustomerVehicle()->getVehicle()); + + // create warranty if serial is set + if (!empty($serial)) { + $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class, $user_id, $source, $jo->getCustomer(), $jo->getCustomerVehicle()->getVehicle()); + } } // send mqtt event (fulfilled) -- 2.43.5 From 25e0931f6fe52e9c0b35c7d37646e4b5319ad68b Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Sat, 23 Mar 2024 04:03:00 +0800 Subject: [PATCH 091/119] Revert warranty serial check for now #783 --- src/Controller/CAPI/RiderAppController.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Controller/CAPI/RiderAppController.php b/src/Controller/CAPI/RiderAppController.php index a4b50099..694ffdd0 100644 --- a/src/Controller/CAPI/RiderAppController.php +++ b/src/Controller/CAPI/RiderAppController.php @@ -953,11 +953,7 @@ class RiderAppController extends ApiController // for riders, use rider id $user_id = $rider->getID(); $source = WarrantySource::RAPI; - - // create warranty if serial is set - if (!empty($serial)) { - $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class, $user_id, $source, $jo->getCustomer(), $jo->getCustomerVehicle()->getVehicle()); - } + $wh->createWarranty($serial, $plate_number, $first_name, $last_name, $mobile_number, $batt_list, $date_purchase, $warranty_class, $user_id, $source, $jo->getCustomer(), $jo->getCustomerVehicle()->getVehicle()); } // send mqtt event (fulfilled) -- 2.43.5 From 7b6838a89af5d5d9a33ca65f36ac9db11c867079 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 7 Sep 2023 16:29:27 +0800 Subject: [PATCH 092/119] Add command to archive job order data. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 344 ++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 src/Command/GetJobOrderArchiveDataCommand.php diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php new file mode 100644 index 00000000..ec5266e6 --- /dev/null +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -0,0 +1,344 @@ +em = $em; + $this->project_dir = $kernel->getProjectDir(); + $this->filesystem = $filesystem; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('joborder:archive') + ->setDescription('Get job order data to archive.') + ->setHelp('Get job order data to archive.') + ->addArgument('cutoff_date', InputArgument::REQUIRED, 'cutoff_date') + ->addArgument('period', InputArgument::REQUIRED, 'period'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // get table to back up + $period = $input->getArgument('period'); + $cutoff_date = $input->getArgument('cutoff_date'); + + $em = $this->em; + + $db = $em->getConnection(); + + // create the archive table + $archive_table_name = $this->createArchiveTable($cutoff_date, $period); + + // sql query to retrieve the rows or entries for backup + $query_sql = 'SELECT id, + customer_id, + cvehicle_id, + rider_id, + date_create, + date_schedule, + date_fulfill, + coordinates, + flag_advance, + service_type, + source, + date_cancel, + status, + delivery_instructions, + delivery_address, + create_user_id, + assign_user_id, + date_assign, + warranty_class, + process_user_id, + hub_id, + cancel_reason, + ref_jo_id, + tier1_notes, + tier2_notes, + mode_of_payment, + or_name, + landmark, + promo_detail, + or_num, + trade_in_type, + flag_rider_rating, + flag_coolant, + facilitated_hub_id, + facilitated_type, + coord_long, + coord_lat, + priority, + meta, + status_autoassign, + first_name, + last_name, + plate_number, + phone_mobile, + no_trade_in_reason, + will_wait, + reason_not_waiting, + not_waiting_notes, + delivery_status, + emergency_type_id, + ownership_type_id, + cust_location_id, + source_of_awareness, + remarks, + initial_concern, + initial_concern_notes, + gender, + caller_classification, + inventory_count + FROM job_order + WHERE DATE_CREATE < DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR)'; + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); + + $results = $query_stmt->executeQuery(); + + $backup_data = []; + + while ($row = $results->fetchAssociative()) + { + $backup_data[] = $this->createBackupData($row); + } + + // create the load file for the backup data + $this->createLoadDataFileForBackupData($backup_data); + + return 0; + } + + protected function createArchiveTable($str_date, $period) + { + // form the archive table name _archive_ + $modifier = '-' . $period. 'year'; + + // convert the date string into DateTime + $date = new DateTime($str_date); + $year = $date->modify($modifier)->format('Y'); + + $archive_table_name = 'job_order_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `customer_id` int(11) DEFAULT NULL, + `cvehicle_id` int(11) DEFAULT NULL, + `rider_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_schedule` datetime NOT NULL, + `date_fulfill` datetime DEFAULT NULL, + `coordinates` point NOT NULL COMMENT \'(DC2Type:point)\', + `flag_advance` tinyint(1) NOT NULL, + `service_type` varchar(25) COLLATE utf8_unicode_ci NOT NULL, + `source` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `date_cancel` datetime DEFAULT NULL, + `status` varchar(15) COLLATE utf8_unicode_ci NOT NULL, + `delivery_instructions` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `delivery_address` longtext COLLATE utf8_unicode_ci NOT NULL, + `create_user_id` int(11) DEFAULT NULL, + `assign_user_id` int(11) DEFAULT NULL, + `date_assign` datetime DEFAULT NULL, + `warranty_class` varchar(25) COLLATE utf8_unicode_ci NOT NULL, + `process_user_id` int(11) DEFAULT NULL, + `hub_id` int(11) DEFAULT NULL, + `cancel_reason` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL, + `ref_jo_id` int(11) DEFAULT NULL, + `tier1_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `tier2_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `mode_of_payment` varchar(50) COLLATE utf8_unicode_ci NOT NULL, + `or_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `landmark` longtext COLLATE utf8_unicode_ci NOT NULL, + `promo_detail` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `or_num` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `trade_in_type` varchar(25) COLLATE utf8_unicode_ci DEFAULT NULL, + `flag_rider_rating` tinyint(1) DEFAULT NULL, + `flag_coolant` tinyint(1) NOT NULL, + `facilitated_hub_id` int(11) DEFAULT NULL, + `facilitated_type` varchar(8) COLLATE utf8_unicode_ci DEFAULT NULL, + `coord_long` decimal(11,8) NOT NULL, + `coord_lat` decimal(11,8) NOT NULL, + `priority` int(11) NOT NULL DEFAULT 0, + `meta` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + `status_autoassign` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL, + `first_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `last_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `plate_number` varchar(100) COLLATE utf8_unicode_ci NOT NULL, + `phone_mobile` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `no_trade_in_reason` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `will_wait` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `reason_not_waiting` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `not_waiting_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `delivery_status` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL, + `emergency_type_id` int(11) DEFAULT NULL, + `ownership_type_id` int(11) DEFAULT NULL, + `cust_location_id` int(11) DEFAULT NULL, + `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `initial_concern` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `initial_concern_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `gender` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `caller_classification` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + + return $archive_table_name; + } + + protected function createBackupData($row) + { + // get job order data + // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, + // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, + // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, + // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + + $id = $row['id']; + $cust_id = $row['customer_id']; + $cv_id = $row['cvehicle_id']; + + $rider_id = '\N'; + if ($row['rider_id'] != NULL) + $rider_id = $row]'rider_id']; + + $date_create = $row['date_create']; + $date_schedule = $row['date_schedule']; + + $date_fulfill = '\N'; + if ($row['date_fulfill'] != NULL) + $date_fulfill = $row['date_schedule']; + + $coordinates = $row['coordinates']; + $flag_advance = $row['flag_advance']; + $service_type = $row['service_type']; + $source = $row['source']; + + $date_cancel = '\N'; + if ($row['date_cancel'] != NULL) + $date_cancel = $row['date_cancel']; + + $status = $row['status']; + $del_instructions = $row['delivery_instructions']; + $del_address = $row['delivery_address']; + + $create_user_id = '\N'; + if ($row['create_user_id'] != NULL) + $create_user_id = $row['create_user_id']; + + $assign_user_id = '\N'; + if ($row['assign_user_id'] != NULL) + $assign_user_id = $row['assign_user_id']; + + $date_assign = '\N'; + if ($row['date_assign'] != NULL) + $date_assign = $row['date_assign']; + + $warr_class = $row['warranty_class']; + + $process_user_id = '\N'; + if ($row['process_user_id'] != NULL) + $process_user_id = $row['process_user_id']; + + $hub_id = '\N'; + if ($row['hub_id'] != NULL) + $hub_id = $row['hub_id']; + + $cancel_reason = '\N'; + if ($row['cancel_reason'] != NULL) + $cancel_reason = $row['cancel_reason']; + + $ref_jo_id = '\N'; + if ($row['ref_jo_id'] != NULL) + $ref_jo_id = $row['ref_jo_id']; + + $tier1_notes = $row['tier1_notes']; + $tier2_notes = $row['tier2_notes']; + $mode_of_payment = $row['mode_of_payment']; + $or_name = $row['or_name']; + $landmark = $row['landmark']; + $promo_details = $row['promo_detail']; + + $or_num = '\N'; + if ($row['or_num'] != NULL) + $or_num = $row['or_num']; + + $trade_in_type = '\N'; + if ($row['trade_in_type'] != NULL) + $trade_in_type = $row['trade_in_type']; + + $flag_rider_rating = '\N'; + if ($row['flag_rider_rating'] != NULL) + $flag_rider_rating = $row['flag_rider_rating']; + + $flag_coolant = $row['flag_coolant']; + + $fac_hub_id = '\N'; + if ($row['facilitated_hub_id'] != NULL) + $fac_hub_id = $row['facilitated_hub_id']; + + $fac_type = '\N'; + if ($row['facilitated_type'] != NULL) + $fac_type = $row['facilitated_type']; + + $coord_long = $row['coord_long']; + $coord_lat = $row['coord_lat']; + $priority = $row['priority']; + $meta = $row['meta']; + $status_autoassign = $row['status_autoassign']; + $first_name = $row['first_name']; + $last_name = $row['last_name']; + $plate_number = $row['plate_number']; + $phone_mobile = $row['phone_mobile']; + $no_trade_in_reason = $row[' no_trade_in_reason']; + $will_wait = $row['will_wait']; + $reason_not_waiting = $row['reason_not_waiting']; + $not_waiting_notes = $row['not_waiting_notes']; + $del_status = $row['delivery_status']; + $emergency_type_id = $row['emergency_type_id']; + $owner_type_id = $row['ownership_type_id']; + $cust_location_id = $row['cust_location_id']; + $source_of_awareness = $row['source_of_awareness']; + $remarks = $row['remarks']; + $initial_concern = $row['initial_concern']; + $initial_concern_notes = $row['initial_concern_notes']; + $gender = $row['gender']; + $caller_class = $row['caller_classification']; + $inv_count = $row['inventory_count']; + + // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, + // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, + // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, + // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + } +} -- 2.43.5 From 6382cfda1e62806bdb9e2096a891f2ac7548fe17 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 7 Sep 2023 18:01:13 +0800 Subject: [PATCH 093/119] Add checking for nulls when creating the data for backup. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 89 ++++++++++++++----- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index ec5266e6..704c509f 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -311,34 +311,83 @@ class GetJobOrderArchiveDataCommand extends Command $fac_type = $row['facilitated_type']; $coord_long = $row['coord_long']; - $coord_lat = $row['coord_lat']; $priority = $row['priority']; $meta = $row['meta']; - $status_autoassign = $row['status_autoassign']; + + $status_autoassign = '\N'; + if ($row['status_autoassign'] != NULL) + $status_autoassign = $row['status_autoassign']; + $first_name = $row['first_name']; $last_name = $row['last_name']; $plate_number = $row['plate_number']; $phone_mobile = $row['phone_mobile']; - $no_trade_in_reason = $row[' no_trade_in_reason']; + + $no_trade_in_reason = '\N'; + if ($row['no_trade_in_reason'] != NULL) + $no_trade_in_reason = $row[' no_trade_in_reason']; + $will_wait = $row['will_wait']; - $reason_not_waiting = $row['reason_not_waiting']; - $not_waiting_notes = $row['not_waiting_notes']; - $del_status = $row['delivery_status']; - $emergency_type_id = $row['emergency_type_id']; - $owner_type_id = $row['ownership_type_id']; - $cust_location_id = $row['cust_location_id']; - $source_of_awareness = $row['source_of_awareness']; - $remarks = $row['remarks']; - $initial_concern = $row['initial_concern']; - $initial_concern_notes = $row['initial_concern_notes']; - $gender = $row['gender']; - $caller_class = $row['caller_classification']; + + $reason_not_waiting = '\N'; + if ($row['reason_not_waiting'] != NULL) + $reason_not_waiting = $row['reason_not_waiting']; + + $not_waiting_notes = '\N'; + if ($row['not_waiting_notes'] != NULL) + $not_waiting_notes = $row['not_waiting_notes']; + + $del_status = '\N'; + if ($row['delivery_status'] != NULL) + $del_status = $row['delivery_status']; + + $emergency_type_id = '\N'; + if ($row['emergency_type_id'] != NULL) + $emergency_type_id = $row['emergency_type_id']; + + $owner_type_id = '\N'; + if ($row['ownership_type_id'] != NULL) + $owner_type_id = $row['ownership_type_id']; + + $cust_location_id = '\N'; + if ($row['cust_location_id'] != NULL) + $cust_location_id = $row['cust_location_id']; + + $source_of_awareness = '\N'; + if ($row['source_of_awareness'] != NULL) + $source_of_awareness = $row['source_of_awareness']; + + $remarks = '\N'; + if ($row['remarks'] != NULL) + $remarks = $row['remarks']; + + $initial_concern = '\N'; + if ($row['initial_concern'] != NULL) + $initial_concern = $row['initial_concern']; + + $initial_concern_notes = '\N'; + if ($row['initial_concern_notes'] != NULL) + $initial_concern_notes = $row['initial_concern_notes']; + + $gender = '\N'; + if ($row['gender'] != NULL) + $gender = $row['gender']; + + $caller_class = '\N'; + if ($row['caller_classification'] != NULL) + $caller_class = $row['caller_classification']; + $inv_count = $row['inventory_count']; - // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, - // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, - // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, - // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, - // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id + // create the array for the file + $data = [ + $id, + $cust_id, + // TODO: finish writing to array + ]; + + return $data; } + + // TODO: write the load data file function } -- 2.43.5 From 6ba3ab7186bb4a12c35386d2b7de8bd2bf414619 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 8 Sep 2023 15:27:19 +0800 Subject: [PATCH 094/119] Add loading of data into database. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 115 +++++++++++++++++- 1 file changed, 110 insertions(+), 5 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 704c509f..47c3e174 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -127,7 +127,7 @@ class GetJobOrderArchiveDataCommand extends Command } // create the load file for the backup data - $this->createLoadDataFileForBackupData($backup_data); + $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); return 0; } @@ -229,7 +229,7 @@ class GetJobOrderArchiveDataCommand extends Command $rider_id = '\N'; if ($row['rider_id'] != NULL) - $rider_id = $row]'rider_id']; + $rider_id = $row['rider_id']; $date_create = $row['date_create']; $date_schedule = $row['date_schedule']; @@ -311,6 +311,7 @@ class GetJobOrderArchiveDataCommand extends Command $fac_type = $row['facilitated_type']; $coord_long = $row['coord_long']; + $coord_lat = $row['coord_lat']; $priority = $row['priority']; $meta = $row['meta']; @@ -325,7 +326,7 @@ class GetJobOrderArchiveDataCommand extends Command $no_trade_in_reason = '\N'; if ($row['no_trade_in_reason'] != NULL) - $no_trade_in_reason = $row[' no_trade_in_reason']; + $no_trade_in_reason = $row['no_trade_in_reason']; $will_wait = $row['will_wait']; @@ -383,11 +384,115 @@ class GetJobOrderArchiveDataCommand extends Command $data = [ $id, $cust_id, - // TODO: finish writing to array + $cv_id, + $rider_id, + $date_create, + $date_schedule, + $date_fulfill, + $coordinates, + $flag_advance, + $service_type, + $source, + $date_cancel, + $status, + $del_instructions, + $del_address, + $create_user_id, + $assign_user_id, + $date_assign, + $warr_class, + $process_user_id, + $hub_id, + $cancel_reason, + $ref_jo_id, + $tier1_notes, + $tier2_notes, + $mode_of_payment, + $or_name, + $landmark, + $promo_details, + $or_num, + $trade_in_type, + $flag_rider_rating, + $flag_coolant, + $fac_hub_id, + $fac_type, + $coord_long, + $coord_lat, + $priority, + $meta, + $status_autoassign, + $first_name, + $last_name, + $plate_number, + $phone_mobile, + $no_trade_in_reason, + $will_wait, + $reason_not_waiting, + $not_waiting_notes, + $del_status, + $emergency_type_id, + $owner_type_id, + $cust_location_id, + $source_of_awareness, + $remarks, + $initial_concern, + $initial_concern_notes, + $gender, + $caller_class, + $inv_count ]; return $data; } - // TODO: write the load data file function + protected function createLoadDataFileForBackupData($backup_data, $table_name) + { + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/jo_archive.tab'; + error_log('opening file for jo archive - ' . $file); + + $fp = fopen($file, 'w'); + if ($fp === false) + { + error_log('could not open file for load data infile - ' . $file); + } + else + { + foreach ($backup_data as $key => $data) + { + $line = implode('|', $data) . "\r\n"; + fwrite($fp, $line); + } + } + + fclose($fp); + + $conn = $this->em->getConnection(); + $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count)'); + + $result = $stmt->execute(); + + if (!$result) + error_log('Failed loading data.'); + + // TODO: delete file? + } + } -- 2.43.5 From a74bce2e35c430029d8859c70ff2833fa76ce368 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 8 Sep 2023 17:24:43 +0800 Subject: [PATCH 095/119] Add saving of data to archive table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 47c3e174..7e9f969e 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -126,6 +126,8 @@ class GetJobOrderArchiveDataCommand extends Command $backup_data[] = $this->createBackupData($row); } + error_log('count ' . count($backup_data)); + // create the load file for the backup data $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); @@ -238,7 +240,6 @@ class GetJobOrderArchiveDataCommand extends Command if ($row['date_fulfill'] != NULL) $date_fulfill = $row['date_schedule']; - $coordinates = $row['coordinates']; $flag_advance = $row['flag_advance']; $service_type = $row['service_type']; $source = $row['source']; @@ -248,6 +249,8 @@ class GetJobOrderArchiveDataCommand extends Command $date_cancel = $row['date_cancel']; $status = $row['status']; + + // TODO: might need to clean delivery address and delivery instructions $del_instructions = $row['delivery_instructions']; $del_address = $row['delivery_address']; @@ -312,6 +315,10 @@ class GetJobOrderArchiveDataCommand extends Command $coord_long = $row['coord_long']; $coord_lat = $row['coord_lat']; + + // coordinates needs special handling since it's a spatial column + $coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; + $priority = $row['priority']; $meta = $row['meta']; @@ -471,11 +478,11 @@ class GetJobOrderArchiveDataCommand extends Command fclose($fp); $conn = $this->em->getConnection(); - $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' + $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' FIELDS TERMINATED BY \'|\' LINES TERMINATED BY \'\\r\\n\' (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, coordinates, flag_advance, service_type, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, source, date_cancel, status, delivery_instructions, delivery_address, create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, @@ -485,7 +492,9 @@ class GetJobOrderArchiveDataCommand extends Command first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count)'); + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@coordinates)' + ); $result = $stmt->execute(); -- 2.43.5 From 12edc9915deeabc55b01db5cac22521bae9806ec Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 11 Sep 2023 15:10:08 +0800 Subject: [PATCH 096/119] Fix issues found when saving archive data. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 7e9f969e..4a42849f 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -44,6 +44,8 @@ class GetJobOrderArchiveDataCommand extends Command $period = $input->getArgument('period'); $cutoff_date = $input->getArgument('cutoff_date'); + $cutoff_date_time = $cutoff_date . ' 23:59:59'; + $em = $this->em; $db = $em->getConnection(); @@ -112,7 +114,8 @@ class GetJobOrderArchiveDataCommand extends Command caller_classification, inventory_count FROM job_order - WHERE DATE_CREATE < DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR)'; + WHERE DATE_CREATE <= DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR) + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); @@ -250,9 +253,8 @@ class GetJobOrderArchiveDataCommand extends Command $status = $row['status']; - // TODO: might need to clean delivery address and delivery instructions - $del_instructions = $row['delivery_instructions']; - $del_address = $row['delivery_address']; + $del_instructions = $this->cleanData($row['delivery_instructions']); + $del_address = $this->cleanData($row['delivery_address']); $create_user_id = '\N'; if ($row['create_user_id'] != NULL) @@ -284,11 +286,13 @@ class GetJobOrderArchiveDataCommand extends Command if ($row['ref_jo_id'] != NULL) $ref_jo_id = $row['ref_jo_id']; - $tier1_notes = $row['tier1_notes']; - $tier2_notes = $row['tier2_notes']; + $tier1_notes = $this->cleanData($row['tier1_notes']); + $tier2_notes = $this->cleanData($row['tier2_notes']); + $mode_of_payment = $row['mode_of_payment']; $or_name = $row['or_name']; - $landmark = $row['landmark']; + + $landmark = $this->cleanData($row['landmark']); $promo_details = $row['promo_detail']; $or_num = '\N'; @@ -367,7 +371,7 @@ class GetJobOrderArchiveDataCommand extends Command $remarks = '\N'; if ($row['remarks'] != NULL) - $remarks = $row['remarks']; + $remarks = $this->cleanData(row['remarks']); $initial_concern = '\N'; if ($row['initial_concern'] != NULL) @@ -504,4 +508,15 @@ class GetJobOrderArchiveDataCommand extends Command // TODO: delete file? } + protected function cleanData($text) + { + $clean_text = ''; + + // replace the new lines with whitespace + $clean_text = preg_replace("/[\n\r]/", ' ', $text); + + return $clean_text; + + } + } -- 2.43.5 From f806130561f01cb9faaffbc3d3046ddd49180fac Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 12 Sep 2023 11:35:31 +0800 Subject: [PATCH 097/119] Modify code according to code review. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 229 ++++-------------- 1 file changed, 44 insertions(+), 185 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 4a42849f..2e8e6a41 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -34,91 +34,32 @@ class GetJobOrderArchiveDataCommand extends Command $this->setName('joborder:archive') ->setDescription('Get job order data to archive.') ->setHelp('Get job order data to archive.') - ->addArgument('cutoff_date', InputArgument::REQUIRED, 'cutoff_date') - ->addArgument('period', InputArgument::REQUIRED, 'period'); + ->addArgument('year', InputArgument::REQUIRED, 'year'); } protected function execute(InputInterface $input, OutputInterface $output) { // get table to back up - $period = $input->getArgument('period'); - $cutoff_date = $input->getArgument('cutoff_date'); - - $cutoff_date_time = $cutoff_date . ' 23:59:59'; + $year = $input->getArgument('year'); $em = $this->em; $db = $em->getConnection(); // create the archive table - $archive_table_name = $this->createArchiveTable($cutoff_date, $period); + $archive_table_name = $this->createArchiveTable($year); + // TODO: move the creation of the query_sql to a function or + // set this as a preset or a variable or something and load specific query + // according to what table is to be archived. // sql query to retrieve the rows or entries for backup - $query_sql = 'SELECT id, - customer_id, - cvehicle_id, - rider_id, - date_create, - date_schedule, - date_fulfill, - coordinates, - flag_advance, - service_type, - source, - date_cancel, - status, - delivery_instructions, - delivery_address, - create_user_id, - assign_user_id, - date_assign, - warranty_class, - process_user_id, - hub_id, - cancel_reason, - ref_jo_id, - tier1_notes, - tier2_notes, - mode_of_payment, - or_name, - landmark, - promo_detail, - or_num, - trade_in_type, - flag_rider_rating, - flag_coolant, - facilitated_hub_id, - facilitated_type, - coord_long, - coord_lat, - priority, - meta, - status_autoassign, - first_name, - last_name, - plate_number, - phone_mobile, - no_trade_in_reason, - will_wait, - reason_not_waiting, - not_waiting_notes, - delivery_status, - emergency_type_id, - ownership_type_id, - cust_location_id, - source_of_awareness, - remarks, - initial_concern, - initial_concern_notes, - gender, - caller_classification, - inventory_count + $query_sql = 'SELECT * FROM job_order - WHERE DATE_CREATE <= DATE_SUB(:cutoff_date, INTERVAL ' . $period . ' YEAR) + WHERE YEAR(date_create) = :year ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('cutoff_date', $cutoff_date, PDO::PARAM_STR); + $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $results = $query_stmt->executeQuery(); @@ -137,20 +78,15 @@ class GetJobOrderArchiveDataCommand extends Command return 0; } - protected function createArchiveTable($str_date, $period) + protected function createArchiveTable($year) { // form the archive table name _archive_ - $modifier = '-' . $period. 'year'; - - // convert the date string into DateTime - $date = new DateTime($str_date); - $year = $date->modify($modifier)->format('Y'); - $archive_table_name = 'job_order_archive_' . $year; // create the table if it doesn't exist $db = $this->em->getConnection(); + // TODO: What if table already exists? $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( `id` int(11) NOT NULL, `customer_id` int(11) DEFAULT NULL, @@ -223,7 +159,7 @@ class GetJobOrderArchiveDataCommand extends Command { // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, - // assign_user_id, proces_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, + // assign_user_id, process_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, // flag_rider_rating, facilitated_type, facilitated_hub_id, status_autoassign, reason_not_waiting, // not_waiting_notes, no_trade_in_reason, delivery_status, source_of_awareness, remarks, initial_concern, // initial_concern_notes, gender, caller_classifications, emergency_type_id, ownership_type_id, cust_location_id @@ -232,59 +168,34 @@ class GetJobOrderArchiveDataCommand extends Command $cust_id = $row['customer_id']; $cv_id = $row['cvehicle_id']; - $rider_id = '\N'; - if ($row['rider_id'] != NULL) - $rider_id = $row['rider_id']; + $rider_id = $row['rider_id'] ?? '\N'; $date_create = $row['date_create']; $date_schedule = $row['date_schedule']; - $date_fulfill = '\N'; - if ($row['date_fulfill'] != NULL) - $date_fulfill = $row['date_schedule']; + $date_fulfill = $row['date_fulfill'] ?? '\N'; $flag_advance = $row['flag_advance']; $service_type = $row['service_type']; $source = $row['source']; - $date_cancel = '\N'; - if ($row['date_cancel'] != NULL) - $date_cancel = $row['date_cancel']; + $date_cancel = $row['date_cancel'] ?? '\N'; $status = $row['status']; $del_instructions = $this->cleanData($row['delivery_instructions']); $del_address = $this->cleanData($row['delivery_address']); - $create_user_id = '\N'; - if ($row['create_user_id'] != NULL) - $create_user_id = $row['create_user_id']; - - $assign_user_id = '\N'; - if ($row['assign_user_id'] != NULL) - $assign_user_id = $row['assign_user_id']; - - $date_assign = '\N'; - if ($row['date_assign'] != NULL) - $date_assign = $row['date_assign']; + $create_user_id = $row['create_user_id'] ?? '\N'; + $assign_user_id = $row['assign_user_id'] ?? '\N'; + $date_assign = $row['date_assign'] ?? '\N'; $warr_class = $row['warranty_class']; - $process_user_id = '\N'; - if ($row['process_user_id'] != NULL) - $process_user_id = $row['process_user_id']; - - $hub_id = '\N'; - if ($row['hub_id'] != NULL) - $hub_id = $row['hub_id']; - - $cancel_reason = '\N'; - if ($row['cancel_reason'] != NULL) - $cancel_reason = $row['cancel_reason']; - - $ref_jo_id = '\N'; - if ($row['ref_jo_id'] != NULL) - $ref_jo_id = $row['ref_jo_id']; + $process_user_id = $row['process_user_id'] ?? '\N'; + $hub_id = $row['hub_id'] ?? '\N'; + $cancel_reason = $row['cancel_reason'] ?? '\N'; + $ref_jo_id = $row['ref_jo_id'] ?? '\N'; $tier1_notes = $this->cleanData($row['tier1_notes']); $tier2_notes = $this->cleanData($row['tier2_notes']); @@ -295,99 +206,47 @@ class GetJobOrderArchiveDataCommand extends Command $landmark = $this->cleanData($row['landmark']); $promo_details = $row['promo_detail']; - $or_num = '\N'; - if ($row['or_num'] != NULL) - $or_num = $row['or_num']; - - $trade_in_type = '\N'; - if ($row['trade_in_type'] != NULL) - $trade_in_type = $row['trade_in_type']; - - $flag_rider_rating = '\N'; - if ($row['flag_rider_rating'] != NULL) - $flag_rider_rating = $row['flag_rider_rating']; + $or_num = $row['or_num'] ?? '\N'; + $trade_in_type = $row['trade_in_type'] ?? '\N'; + $flag_rider_rating = $row['flag_rider_rating'] ?? '\N'; $flag_coolant = $row['flag_coolant']; - $fac_hub_id = '\N'; - if ($row['facilitated_hub_id'] != NULL) - $fac_hub_id = $row['facilitated_hub_id']; - - $fac_type = '\N'; - if ($row['facilitated_type'] != NULL) - $fac_type = $row['facilitated_type']; + $fac_hub_id = $row['facilitated_hub_id'] ?? '\N'; + $fac_type = $row['facilitated_type'] ?? '\N'; $coord_long = $row['coord_long']; $coord_lat = $row['coord_lat']; // coordinates needs special handling since it's a spatial column - $coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; + $geo_coordinates = 'POINT(' . $coord_lat . ' ' . $coord_long .')'; $priority = $row['priority']; $meta = $row['meta']; - $status_autoassign = '\N'; - if ($row['status_autoassign'] != NULL) - $status_autoassign = $row['status_autoassign']; + $status_autoassign = $row['status_autoassign'] ?? '\N'; $first_name = $row['first_name']; $last_name = $row['last_name']; $plate_number = $row['plate_number']; $phone_mobile = $row['phone_mobile']; - $no_trade_in_reason = '\N'; - if ($row['no_trade_in_reason'] != NULL) - $no_trade_in_reason = $row['no_trade_in_reason']; + $no_trade_in_reason = $row['no_trade_in_reason'] ?? '\N'; $will_wait = $row['will_wait']; - $reason_not_waiting = '\N'; - if ($row['reason_not_waiting'] != NULL) - $reason_not_waiting = $row['reason_not_waiting']; - - $not_waiting_notes = '\N'; - if ($row['not_waiting_notes'] != NULL) - $not_waiting_notes = $row['not_waiting_notes']; - - $del_status = '\N'; - if ($row['delivery_status'] != NULL) - $del_status = $row['delivery_status']; - - $emergency_type_id = '\N'; - if ($row['emergency_type_id'] != NULL) - $emergency_type_id = $row['emergency_type_id']; - - $owner_type_id = '\N'; - if ($row['ownership_type_id'] != NULL) - $owner_type_id = $row['ownership_type_id']; - - $cust_location_id = '\N'; - if ($row['cust_location_id'] != NULL) - $cust_location_id = $row['cust_location_id']; - - $source_of_awareness = '\N'; - if ($row['source_of_awareness'] != NULL) - $source_of_awareness = $row['source_of_awareness']; - - $remarks = '\N'; - if ($row['remarks'] != NULL) - $remarks = $this->cleanData(row['remarks']); - - $initial_concern = '\N'; - if ($row['initial_concern'] != NULL) - $initial_concern = $row['initial_concern']; - - $initial_concern_notes = '\N'; - if ($row['initial_concern_notes'] != NULL) - $initial_concern_notes = $row['initial_concern_notes']; - - $gender = '\N'; - if ($row['gender'] != NULL) - $gender = $row['gender']; - - $caller_class = '\N'; - if ($row['caller_classification'] != NULL) - $caller_class = $row['caller_classification']; + $reason_not_waiting = $row['reason_not_waiting'] ?? '\N'; + $not_waiting_notes = $this->cleanData($row['not_waiting_notes']) ?? '\N'; + $del_status = $row['delivery_status'] ?? '\N'; + $emergency_type_id = $row['emergency_type_id'] ?? '\N'; + $owner_type_id = $row['ownership_type_id'] ?? '\N'; + $cust_location_id = $row['cust_location_id'] ?? '\N'; + $source_of_awareness = $row['source_of_awareness'] ?? '\N'; + $remarks = $this->cleanData($row['remarks']) ?? '\N'; + $initial_concern = $row['initial_concern'] ?? '\N'; + $initial_concern_notes = $this->cleanData($row['initial_concern_notes']) ?? '\N'; + $gender = $row['gender'] ?? '\N'; + $caller_class = $row['caller_classification'] ?? '\N'; $inv_count = $row['inventory_count']; @@ -400,7 +259,7 @@ class GetJobOrderArchiveDataCommand extends Command $date_create, $date_schedule, $date_fulfill, - $coordinates, + $geo_coordinates, $flag_advance, $service_type, $source, @@ -497,7 +356,7 @@ class GetJobOrderArchiveDataCommand extends Command will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@coordinates)' + SET coordinates=ST_GeomFromText(@geo_coordinates)' ); $result = $stmt->execute(); -- 2.43.5 From e56a5eef44eb417eedfcd2d314a8111a0e4b4210 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 12 Sep 2023 18:18:37 +0800 Subject: [PATCH 098/119] Refactor the retrieval of job order data to include the other associated tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 154 ++++++++++++++++-- 1 file changed, 136 insertions(+), 18 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 2e8e6a41..e1bcabbd 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -42,43 +42,134 @@ class GetJobOrderArchiveDataCommand extends Command // get table to back up $year = $input->getArgument('year'); - $em = $this->em; + // get the data to archive for the following tables: + // (1) job_order + // (2) invoice (has jo foreign key) + // (3) invoice_item (has invoice foreign key) + // (4) ticket (has jo foreign key) + // (5) jo_rejection (has jo foreign key) + // (6) rider_rating (has jo foreign key) - $db = $em->getConnection(); + $jo_backup_data = $this->getJobOrderData($year); - // create the archive table - $archive_table_name = $this->createArchiveTable($year); + // create the archive tables + // TODO: create the other archive tables + $archive_table_name = $this->createJobOrderArchiveTable($year); + + error_log('count ' . count($jo_backup_data)); + + // create the load file for the backup data + // $this->createLoadDataFileForBackupData($jo_backup_data, $archive_table_name); + + return 0; + } + + protected function getJobOrderData($year) + { + $db = $this->em->getConnection(); - // TODO: move the creation of the query_sql to a function or - // set this as a preset or a variable or something and load specific query - // according to what table is to be archived. - // sql query to retrieve the rows or entries for backup $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $results = $query_stmt->executeQuery(); - $backup_data = []; + $jo_data = []; + $jo_event_data = []; + $invoice_data = []; + $ticket_data = []; + $jo_rejection_data = []; + $rider_rating_data = []; while ($row = $results->fetchAssociative()) { - $backup_data[] = $this->createBackupData($row); + $jo_data[] = $this->createJobOrderArchiveData($row); + + // get the data to archive for jo_event, invoice, ticket, jo_rejection, rider_rating + // using the job order id + $id = $row['id']; + + $jo_event_data = $this->getJORelatedData($id, 'jo_event'); + $ticket_data = $this->getJORelatedData($id, 'ticket'); + $jo_rejection_data = $this->getJORelatedData($id, 'jo_rejection'); + $rider_rating_data = $this->getJORelatedData($id, 'rider_rating'); + + // TODO: separate the invoice and invoice item data } - error_log('count ' . count($backup_data)); + $backup_data = [ + 'jo' => $jo_data, + 'jo_event' => $jo_event_data, + 'invoice' => $invoice_data, + 'ticket' => $ticket_data, + 'jo_rejection' => $jo_rejection_data, + 'rider_rating' => $rider_rating_data, + ]; - // create the load file for the backup data - $this->createLoadDataFileForBackupData($backup_data, $archive_table_name); - - return 0; + return $backup_data; } - protected function createArchiveTable($year) + protected function getJORelatedData($id, $table_name) + { + $db = $this->em->getConnection(); + + if (($table_name == 'jo_event') || + ($table_name == 'invoice') || + ($table_name == 'ticket')) + { + $query_sql = 'SELECT * + FROM ' . $table_name . ' WHERE job_order_id = :id'; + } + else + { + $query_sql = 'SELECT * + FROM ' . $table_name . ' WHERE jo_id = :id'; + } + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $id); + + $results = $query_stmt->executeQuery(); + + $jo_related_data = []; + + while ($row = $results->fetchAssociative()) + { + if ($table_name == 'jo_event') + { + // create the jo event archive data + $jo_related_data = $this->createJOEventArchiveData($row); + } + if ($table_name == 'invoice') + { + // get the data to archive for invoice item + // create the invoice archive data + } + if ($table_name == 'ticket') + { + // create the ticket archive data + } + if ($table_name == 'jo_rejection') + { + // create the jo rejection archive data + } + if ($table_name == 'rider_rating') + { + // create the rider rating archive data + } + } + + return $jo_related_data; + } + + // TODO: make this so you just call one function to create all the tables + // pass the year and the table name + // set the create sql as a constant or something + protected function createJobOrderArchiveTable($year) { // form the archive table name _archive_ $archive_table_name = 'job_order_archive_' . $year; @@ -155,7 +246,7 @@ class GetJobOrderArchiveDataCommand extends Command return $archive_table_name; } - protected function createBackupData($row) + protected function createJobOrderArchiveData($row) { // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, @@ -316,6 +407,33 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } + protected function createJOEventArchiveData($row) + { + // fields that can be null: rider_id, create_user_id + $id = $row['id']; + + $create_user_id = $row['create_user_id'] ?? '\N'; + + $job_order_id = $row['job_order_id']; + $date_create = $row['date_create']; + $date_happen = $row['date_happen']; + $type_id = $row['type_id']; + + $rider_id = $row['rider_id'] ?? '\N'; + + $data = [ + $id, + $create_user_id, + $job_order_id, + $date_create, + $date_happen, + $type_id, + $rider_id, + ]; + + return $data; + } + protected function createLoadDataFileForBackupData($backup_data, $table_name) { // cache directory -- 2.43.5 From 9eedab0652a41d0e34ba3131080baef9a2bb53a1 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 13 Sep 2023 17:18:33 +0800 Subject: [PATCH 099/119] Add data files for the related job order tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 190 +++++++++--------- 1 file changed, 96 insertions(+), 94 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e1bcabbd..de602ab5 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -39,7 +39,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { - // get table to back up + // get year to archive $year = $input->getArgument('year'); // get the data to archive for the following tables: @@ -50,70 +50,59 @@ class GetJobOrderArchiveDataCommand extends Command // (5) jo_rejection (has jo foreign key) // (6) rider_rating (has jo foreign key) - $jo_backup_data = $this->getJobOrderData($year); - // create the archive tables // TODO: create the other archive tables $archive_table_name = $this->createJobOrderArchiveTable($year); - - error_log('count ' . count($jo_backup_data)); - - // create the load file for the backup data - // $this->createLoadDataFileForBackupData($jo_backup_data, $archive_table_name); - - return 0; - } - - protected function getJobOrderData($year) - { $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); - $results = $query_stmt->executeQuery(); + $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; - $jo_data = []; - $jo_event_data = []; - $invoice_data = []; - $ticket_data = []; - $jo_rejection_data = []; - $rider_rating_data = []; + $this->getArchiveData($query_stmt, $callback); + + return 0; + } + + protected function getArchiveData($stmt, $callbackJO) + { + $results = $stmt->executeQuery(); + + $related_tables = ['jo_event', 'invoice', 'ticket', 'jo_rejection', 'rider_rating']; + + // delete the related data files + foreach ($related_tables as $tname) + { + $this->deleteDataFiles($tname); + } while ($row = $results->fetchAssociative()) { $jo_data[] = $this->createJobOrderArchiveData($row); - // get the data to archive for jo_event, invoice, ticket, jo_rejection, rider_rating - // using the job order id - $id = $row['id']; + // foreach job order id we got from the first query, we get the JO related + // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating - $jo_event_data = $this->getJORelatedData($id, 'jo_event'); - $ticket_data = $this->getJORelatedData($id, 'ticket'); - $jo_rejection_data = $this->getJORelatedData($id, 'jo_rejection'); - $rider_rating_data = $this->getJORelatedData($id, 'rider_rating'); - - // TODO: separate the invoice and invoice item data + if (is_callable($callbackJO)) + { + foreach ($related_tables as $table_name) + { + call_user_func($callbackJO, $row, $table_name); + } + } } - $backup_data = [ - 'jo' => $jo_data, - 'jo_event' => $jo_event_data, - 'invoice' => $invoice_data, - 'ticket' => $ticket_data, - 'jo_rejection' => $jo_rejection_data, - 'rider_rating' => $rider_rating_data, - ]; + // TODO: load data infile for job order - return $backup_data; } - protected function getJORelatedData($id, $table_name) + protected function getRelatedArchiveData($row, $table_name) { $db = $this->em->getConnection(); @@ -131,39 +120,77 @@ class GetJobOrderArchiveDataCommand extends Command } $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $id); + $query_stmt->bindValue('id', $row['id']); $results = $query_stmt->executeQuery(); - $jo_related_data = []; + $data = []; - while ($row = $results->fetchAssociative()) + while ($q_row = $results->fetchAssociative()) { - if ($table_name == 'jo_event') + $fields = []; + + foreach ($q_row as $key => $value) { - // create the jo event archive data - $jo_related_data = $this->createJOEventArchiveData($row); - } - if ($table_name == 'invoice') - { - // get the data to archive for invoice item - // create the invoice archive data - } - if ($table_name == 'ticket') - { - // create the ticket archive data - } - if ($table_name == 'jo_rejection') - { - // create the jo rejection archive data - } - if ($table_name == 'rider_rating') - { - // create the rider rating archive data + $cleaned_value = $this->cleanData(($value) ?? '\N'); + $fields[] = $cleaned_value; } + + $data[$table_name][$q_row['id']] = $fields; } - return $jo_related_data; + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($data, $table_name); + + if ($file != null) + { + // call load data infile + } + } + + protected function deleteDataFiles($tname) + { + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/' . $tname . '_archive.tab'; + + if (file_exists($file)) + unlink($file); + } + + protected function createDataFileRelatedArchiveData($archive_data, $table_name) + { + if (isset($archive_data[$table_name])) + { + $adata = $archive_data[$table_name]; + + // cache directory + $cache_dir = __DIR__ . '/../../var/cache'; + + $file = $cache_dir . '/' . $table_name . '_archive.tab'; + error_log('opening file for archive - ' . $file); + + $fp = fopen($file, 'a'); + if ($fp === false) + { + error_log('could not open file for load data infile - ' . $file); + } + else + { + foreach ($adata as $key => $data) + { + $line = implode('|', $data) . "\r\n"; + fwrite($fp, $line); + } + } + + fclose($fp); + + return $file; + } + + return null; } // TODO: make this so you just call one function to create all the tables @@ -248,6 +275,8 @@ class GetJobOrderArchiveDataCommand extends Command protected function createJobOrderArchiveData($row) { + // TODO: this could be shrunk further + // get job order data // check for nulls. check the ff fields since these can be null: date_fulfill, date_cancel, date_assign, create_user_id, // assign_user_id, process_user_id, hub_id, rider_id, cancel_reason, ref_jo_id, or_num, trade_in_type, @@ -407,34 +436,7 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - protected function createJOEventArchiveData($row) - { - // fields that can be null: rider_id, create_user_id - $id = $row['id']; - - $create_user_id = $row['create_user_id'] ?? '\N'; - - $job_order_id = $row['job_order_id']; - $date_create = $row['date_create']; - $date_happen = $row['date_happen']; - $type_id = $row['type_id']; - - $rider_id = $row['rider_id'] ?? '\N'; - - $data = [ - $id, - $create_user_id, - $job_order_id, - $date_create, - $date_happen, - $type_id, - $rider_id, - ]; - - return $data; - } - - protected function createLoadDataFileForBackupData($backup_data, $table_name) + protected function createLoadDataFileForArchiveData($archive_data, $table_name) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; @@ -449,7 +451,7 @@ class GetJobOrderArchiveDataCommand extends Command } else { - foreach ($backup_data as $key => $data) + foreach ($archive_data as $key => $data) { $line = implode('|', $data) . "\r\n"; fwrite($fp, $line); -- 2.43.5 From 9c465cae696dc77f01f15ad603310e56db5b57ab Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 15 Sep 2023 18:19:11 +0800 Subject: [PATCH 100/119] Add archiving for invoice item. Add creation of other archive tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 284 ++++++++++++++---- 1 file changed, 229 insertions(+), 55 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index de602ab5..81cd795d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -51,14 +51,19 @@ class GetJobOrderArchiveDataCommand extends Command // (6) rider_rating (has jo foreign key) // create the archive tables - // TODO: create the other archive tables - $archive_table_name = $this->createJobOrderArchiveTable($year); + $this->createJobOrderArchiveTables($year); + $this->createInvoiceArchiveTable($year); + $this->createInvoiceItemArchiveTable($year); + $this->createTicketArchiveTable($year); + $this->createJORejectionArchiveTable($year); + $this->createRiderRatingArchiveTable($year); + $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -82,52 +87,66 @@ class GetJobOrderArchiveDataCommand extends Command $this->deleteDataFiles($tname); } + // special since this is not directly related to JO but to invoice + $this->deleteDataFiles('invoice_item'); + while ($row = $results->fetchAssociative()) { - $jo_data[] = $this->createJobOrderArchiveData($row); + $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); // foreach job order id we got from the first query, we get the JO related // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating if (is_callable($callbackJO)) - { + { foreach ($related_tables as $table_name) { - call_user_func($callbackJO, $row, $table_name); + if (($table_name == 'jo_event') || + ($table_name == 'invoice') || + ($table_name == 'ticket')) + { + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; + } + else + { + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + } + + $db = $this->em->getConnection(); + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $row['id']); + + call_user_func($callbackJO, $row, $query_stmt, $table_name); } } } - // TODO: load data infile for job order - + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($jo_data, 'job_order', 'w'); + + if ($file != null) + { + // call load data infile + } } - protected function getRelatedArchiveData($row, $table_name) + protected function getRelatedArchiveData($row, $query_stmt, $table_name) { - $db = $this->em->getConnection(); - - if (($table_name == 'jo_event') || - ($table_name == 'invoice') || - ($table_name == 'ticket')) - { - $query_sql = 'SELECT * - FROM ' . $table_name . ' WHERE job_order_id = :id'; - } - else - { - $query_sql = 'SELECT * - FROM ' . $table_name . ' WHERE jo_id = :id'; - } - - $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); - $results = $query_stmt->executeQuery(); $data = []; while ($q_row = $results->fetchAssociative()) { + // check if table name is invoice because we need to get + // all invoice items for a specific invoice too + if ($table_name == 'invoice') + { + // get invoice item related data + $this->getInvoiceItemArchiveData($q_row); + } + $fields = []; foreach ($q_row as $key => $value) @@ -140,7 +159,46 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($data, $table_name); + $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + + if ($file != null) + { + // call load data infile + } + } + + protected function getInvoiceItemArchiveData($row) + { + $db = $this->em->getConnection(); + + $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; + + $query_stmt = $db->prepare($query_sql); + $query_stmt->bindValue('id', $row['id']); + + $results = $query_stmt->executeQuery(); + + $ii_data = []; + while ($ii_row = $results->fetchAssociative()) + { + $id = $ii_row['id']; + $invoice_id = $ii_row['invoice_id']; + $title = $ii_row['title']; + $qty = $ii_row['qty']; + $price = $ii_row['price']; + $battery_id = $ii_row['battery_id'] ?? '\N'; + + $ii_data['invoice_item'][$id] = [ + $id, + $invoice_id, + $title, + $qty, + $price, + $battery_id + ]; + } + + $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); if ($file != null) { @@ -159,7 +217,7 @@ class GetJobOrderArchiveDataCommand extends Command unlink($file); } - protected function createDataFileRelatedArchiveData($archive_data, $table_name) + protected function createDataFileRelatedArchiveData($archive_data, $table_name, $option) { if (isset($archive_data[$table_name])) { @@ -171,7 +229,7 @@ class GetJobOrderArchiveDataCommand extends Command $file = $cache_dir . '/' . $table_name . '_archive.tab'; error_log('opening file for archive - ' . $file); - $fp = fopen($file, 'a'); + $fp = fopen($file, $option); if ($fp === false) { error_log('could not open file for load data infile - ' . $file); @@ -193,11 +251,7 @@ class GetJobOrderArchiveDataCommand extends Command return null; } - // TODO: make this so you just call one function to create all the tables - // pass the year and the table name - // set the create sql as a constant or something - protected function createJobOrderArchiveTable($year) - { + protected function createJobOrderArchiveTables($year) { // form the archive table name _archive_ $archive_table_name = 'job_order_archive_' . $year; @@ -269,10 +323,142 @@ class GetJobOrderArchiveDataCommand extends Command $create_stmt = $db->prepare($create_sql); $result = $create_stmt->execute(); - - return $archive_table_name; } + protected function createInvoiceArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'invoice_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_paid` datetime DEFAULT NULL, + `date_cancel` datetime DEFAULT NULL, + `discount` decimal(9,2) NOT NULL, + `trade_in` decimal(9,2) NOT NULL, + `vat` decimal(9,2) NOT NULL, + `vat_exclusive_price` decimal(9,2) NOT NULL, + `total_price` decimal(9,2) NOT NULL, + `status` varchar(40) COLLATE utf8_unicode_ci NOT NULL, + `promo_id` int(11) DEFAULT NULL, + `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createInvoiceItemArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'invoice_item_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `invoice_id` int(11) DEFAULT NULL, + `title` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `qty` smallint(6) NOT NULL, + `price` decimal(9,2) NOT NULL, + `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createTicketArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'ticket_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `customer_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `status` varchar(15) COLLATE utf8_unicode_ci NOT NULL, + `ticket_type` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL, + `other_ticket_type` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `first_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `last_name` varchar(80) COLLATE utf8_unicode_ci NOT NULL, + `contact_num` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL, + `details` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `plate_number` varchar(10) COLLATE utf8_unicode_ci DEFAULT NULL, + `ticket_type_id` int(11) DEFAULT NULL, + `subticket_type_id` int(11) DEFAULT NULL, + `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createJORejectionArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_rejection_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `user_id` int(11) DEFAULT NULL, + `hub_id` int(11) DEFAULT NULL, + `jo_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `reason` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, + `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createRiderRatingArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_rejection_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL, + `rider_id` int(11) DEFAULT NULL, + `customer_id` int(11) DEFAULT NULL, + `jo_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `rating` int(11) NOT NULL, + `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + + protected function createJobOrderArchiveData($row) { // TODO: this could be shrunk further @@ -436,31 +622,19 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - protected function createLoadDataFileForArchiveData($archive_data, $table_name) + // TODO: rewrite this to just load the file + protected function loadDataFileForArchiveData($file, $table_name) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/jo_archive.tab'; + $file = $cache_dir . '/' $table_name . 'archive.tab'; error_log('opening file for jo archive - ' . $file); - $fp = fopen($file, 'w'); - if ($fp === false) - { - error_log('could not open file for load data infile - ' . $file); - } - else - { - foreach ($archive_data as $key => $data) - { - $line = implode('|', $data) . "\r\n"; - fwrite($fp, $line); - } - } - - fclose($fp); - $conn = $this->em->getConnection(); + + // this statement is for job order + // TODO: make for other tables $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' FIELDS TERMINATED BY \'|\' LINES TERMINATED BY \'\\r\\n\' -- 2.43.5 From 29441d82c962ecea25912b680b355f3c42d1fab7 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Mon, 18 Sep 2023 18:10:06 +0800 Subject: [PATCH 101/119] Add loading of data file. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 144 +++++++++++++----- 1 file changed, 109 insertions(+), 35 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 81cd795d..2aa81c42 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -57,25 +57,27 @@ class GetJobOrderArchiveDataCommand extends Command $this->createTicketArchiveTable($year); $this->createJORejectionArchiveTable($year); $this->createRiderRatingArchiveTable($year); + $this->createJOEventArchiveTable($year); $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create'; + ORDER BY date_create + LIMIT 100'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; - $this->getArchiveData($query_stmt, $callback); + $this->getArchiveData($query_stmt, $callback, 'job_order', $year); return 0; } - protected function getArchiveData($stmt, $callbackJO) + protected function getArchiveData($stmt, $callbackJO, $jo_tname, $year) { $results = $stmt->executeQuery(); @@ -117,21 +119,42 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - call_user_func($callbackJO, $row, $query_stmt, $table_name); + call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); } } } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, 'job_order', 'w'); + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); if ($file != null) - { + { + $archive_tname = $jo_tname . '_archive_' . $year; + + // load statement for job order + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@geo_coordinates)'; + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); } } - protected function getRelatedArchiveData($row, $query_stmt, $table_name) + protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) { $results = $query_stmt->executeQuery(); @@ -144,7 +167,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($table_name == 'invoice') { // get invoice item related data - $this->getInvoiceItemArchiveData($q_row); + $this->getInvoiceItemArchiveData($q_row, $year); } $fields = []; @@ -161,13 +184,56 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + // TODO: this needs to move or something because we are writing duplicate rows into the db if ($file != null) { + $archive_tname = $table_name . '_archive_' . $year; + + if ($table_name == 'jo_event') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; + } + if ($table_name == 'jo_rejection') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; + } + if ($table_name == 'invoice') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, + total_price, status, promo_id, used_customer_tag_id)'; + } + if ($table_name == 'rider_rating') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; + } + if ($table_name == 'ticket') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, + contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, + source_of_awareness, remarks, other_description)'; + } + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); } } - protected function getInvoiceItemArchiveData($row) + protected function getInvoiceItemArchiveData($row, $year) { $db = $this->em->getConnection(); @@ -202,6 +268,12 @@ class GetJobOrderArchiveDataCommand extends Command if ($file != null) { + $archive_tname = 'invoice_item_archive' . $year; + + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, invoice_id, title, qty, price, battery_id)'; // call load data infile } } @@ -323,6 +395,8 @@ class GetJobOrderArchiveDataCommand extends Command $create_stmt = $db->prepare($create_sql); $result = $create_stmt->execute(); + + return $archive_table_name; } protected function createInvoiceArchiveTable($year) @@ -438,7 +512,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function createRiderRatingArchiveTable($year) { // form the archive table name _archive_ - $archive_table_name = 'jo_rejection_archive_' . $year; + $archive_table_name = 'rider_rating_archive_' . $year; // create the table if it doesn't exist $db = $this->em->getConnection(); @@ -458,6 +532,29 @@ class GetJobOrderArchiveDataCommand extends Command $result = $create_stmt->execute(); } + protected function createJOEventArchiveTable($year) + { + // form the archive table name _archive_ + $archive_table_name = 'jo_event_archive_' . $year; + + // create the table if it doesn't exist + $db = $this->em->getConnection(); + + // TODO: What if table already exists? + $create_sql = 'CREATE TABLE IF NOT EXISTS `' . $archive_table_name . '` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `create_user_id` int(11) DEFAULT NULL, + `job_order_id` int(11) DEFAULT NULL, + `date_create` datetime NOT NULL, + `date_happen` datetime NOT NULL, + `type_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL, + `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + + $create_stmt = $db->prepare($create_sql); + + $result = $create_stmt->execute(); + } + protected function createJobOrderArchiveData($row) { @@ -622,36 +719,13 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } - // TODO: rewrite this to just load the file - protected function loadDataFileForArchiveData($file, $table_name) + protected function loadDataFileForArchiveData($load_stmt) { - // cache directory - $cache_dir = __DIR__ . '/../../var/cache'; - - $file = $cache_dir . '/' $table_name . 'archive.tab'; - error_log('opening file for jo archive - ' . $file); - $conn = $this->em->getConnection(); // this statement is for job order // TODO: make for other tables - $stmt = $conn->prepare('LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $table_name . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, @coordinates, flag_advance, service_type, - source, date_cancel, status, delivery_instructions, delivery_address, - create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, - hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, - mode_of_payment, or_name, landmark, promo_detail, or_num, - trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, - coord_long, coord_lat, priority, meta, status_autoassign, - first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, - will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, - ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@geo_coordinates)' - ); + $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From 9cfc4132c49bac56d4b7120437c3cc0de9942c6b Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 19 Sep 2023 12:48:14 +0800 Subject: [PATCH 102/119] Fix load file issue. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 76 +++++-------------- 1 file changed, 18 insertions(+), 58 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 2aa81c42..061bddc2 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -92,6 +92,7 @@ class GetJobOrderArchiveDataCommand extends Command // special since this is not directly related to JO but to invoice $this->deleteDataFiles('invoice_item'); + $related_files = []; while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); @@ -119,11 +120,20 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + $files[] = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + + // TODO: need to figure out how to get the filenames + foreach ($files as $key =>$file) + { + $related_files[$key] = $file; + } + } } } + error_log(print_r($related_files, true)); + // write the array into the file $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); @@ -159,6 +169,7 @@ class GetJobOrderArchiveDataCommand extends Command $results = $query_stmt->executeQuery(); $data = []; + $files = []; while ($q_row = $results->fetchAssociative()) { @@ -167,7 +178,9 @@ class GetJobOrderArchiveDataCommand extends Command if ($table_name == 'invoice') { // get invoice item related data - $this->getInvoiceItemArchiveData($q_row, $year); + $ii_file = $this->getInvoiceItemArchiveData($q_row, $year); + + $files['invoice_item'] = $ii_file; } $fields = []; @@ -184,53 +197,9 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); - // TODO: this needs to move or something because we are writing duplicate rows into the db - if ($file != null) - { - $archive_tname = $table_name . '_archive_' . $year; + $files[$table_name] = $file; - if ($table_name == 'jo_event') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; - } - if ($table_name == 'jo_rejection') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; - } - if ($table_name == 'invoice') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, - total_price, status, promo_id, used_customer_tag_id)'; - } - if ($table_name == 'rider_rating') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; - } - if ($table_name == 'ticket') - { - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, - contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, - source_of_awareness, remarks, other_description)'; - } - - // call load data infile - $this->loadDataFileForArchiveData($load_stmt); - } + return $files; } protected function getInvoiceItemArchiveData($row, $year) @@ -266,16 +235,7 @@ class GetJobOrderArchiveDataCommand extends Command $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); - if ($file != null) - { - $archive_tname = 'invoice_item_archive' . $year; - - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, invoice_id, title, qty, price, battery_id)'; - // call load data infile - } + return $file; } protected function deleteDataFiles($tname) -- 2.43.5 From 5834e0a38fa2a74a7fd8aca8cbcc1d0f9020ef5d Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 20 Sep 2023 11:54:05 +0800 Subject: [PATCH 103/119] Add loading of data files. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 119 +++++++++++++----- 1 file changed, 88 insertions(+), 31 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 061bddc2..8115be68 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -65,7 +65,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 100'; + LIMIT 100000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -92,7 +92,7 @@ class GetJobOrderArchiveDataCommand extends Command // special since this is not directly related to JO but to invoice $this->deleteDataFiles('invoice_item'); - $related_files = []; + $archive_files = []; while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); @@ -120,48 +120,27 @@ class GetJobOrderArchiveDataCommand extends Command $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $row['id']); - $files[] = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); + $files = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); - // TODO: need to figure out how to get the filenames foreach ($files as $key =>$file) { - $related_files[$key] = $file; + if ($file != null) + $archive_files[$key] = $file; } - } } } - error_log(print_r($related_files, true)); - // write the array into the file $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); if ($file != null) { - $archive_tname = $jo_tname . '_archive_' . $year; - - // load statement for job order - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' - FIELDS TERMINATED BY \'|\' - LINES TERMINATED BY \'\\r\\n\' - (id, customer_id, cvehicle_id, rider_id, date_create, - date_schedule, date_fulfill, @coordinates, flag_advance, service_type, - source, date_cancel, status, delivery_instructions, delivery_address, - create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, - hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, - mode_of_payment, or_name, landmark, promo_detail, or_num, - trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, - coord_long, coord_lat, priority, meta, status_autoassign, - first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, - will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, - ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, - initial_concern_notes, gender, caller_classification, inventory_count) - SET coordinates=ST_GeomFromText(@geo_coordinates)'; - - // call load data infile - $this->loadDataFileForArchiveData($load_stmt); + $archive_files[$jo_tname] = $file; } + + // error_log(print_r($archive_files, true)); + $this->loadArchiveFiles($archive_files, $year); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -197,7 +176,8 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); - $files[$table_name] = $file; + if ($file != null) + $files[$table_name] = $file; return $files; } @@ -679,6 +659,83 @@ class GetJobOrderArchiveDataCommand extends Command return $data; } + protected function loadArchiveFiles($archive_files, $year) + { + foreach ($archive_files as $tname => $file) + { + $archive_tname = $tname . '_archive_' . $year; + + if ($tname == 'job_order') + { + // load statement for job order + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, customer_id, cvehicle_id, rider_id, date_create, + date_schedule, date_fulfill, @coordinates, flag_advance, service_type, + source, date_cancel, status, delivery_instructions, delivery_address, + create_user_id, assign_user_id, date_assign, warranty_class, process_user_id, + hub_id, cancel_reason, ref_jo_id, tier1_notes, tier2_notes, + mode_of_payment, or_name, landmark, promo_detail, or_num, + trade_in_type, flag_rider_rating, flag_coolant, facilitated_hub_id, facilitated_type, + coord_long, coord_lat, priority, meta, status_autoassign, + first_name, last_name, plate_number, phone_mobile, no_trade_in_reason, + will_wait, reason_not_waiting, not_waiting_notes, delivery_status, emergency_type_id, + ownership_type_id, cust_location_id, source_of_awareness, remarks, initial_concern, + initial_concern_notes, gender, caller_classification, inventory_count) + SET coordinates=ST_GeomFromText(@geo_coordinates)'; + } + if ($tname == 'jo_event') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; + } + if ($tname == 'jo_rejection') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; + } + if ($tname == 'invoice') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, + total_price, status, promo_id, used_customer_tag_id)'; + } + if ($tname == 'rider_rating') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; + } + if ($tname == 'ticket') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, + contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, + source_of_awareness, remarks, other_description)'; + } + if ($tname == 'invoice_item') + { + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + FIELDS TERMINATED BY \'|\' + LINES TERMINATED BY \'\\r\\n\' + (id, invoice_id, title, qty, price, battery_id)'; + } + + // call load data infile + $this->loadDataFileForArchiveData($load_stmt); + } + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); -- 2.43.5 From 1f8f403970adfafc00fe6fee0d69d20121cd2180 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 20 Sep 2023 15:31:46 +0800 Subject: [PATCH 104/119] Improve performance. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 8115be68..c1f24cc6 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -61,11 +61,12 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); + // TODO: improve performance. out of memory exception $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create - LIMIT 100000'; + ORDER BY date_create + LIMIT 150000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -93,13 +94,22 @@ class GetJobOrderArchiveDataCommand extends Command $this->deleteDataFiles('invoice_item'); $archive_files = []; + + $jo_id_list = []; + while ($row = $results->fetchAssociative()) { $jo_data['job_order'][$row['id']] = $this->createJobOrderArchiveData($row); + // add jo id to jo_id_list + $jo_id_list[] = $row['id']; + } + + // get all related data for job order + foreach ($jo_id_list as $jo_id) + { // foreach job order id we got from the first query, we get the JO related // data for that id from jo_event, invoice, ticket, jo_rejection, rider_rating - if (is_callable($callbackJO)) { foreach ($related_tables as $table_name) @@ -118,7 +128,7 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); + $query_stmt->bindValue('id', $jo_id); $files = call_user_func($callbackJO, $row, $query_stmt, $table_name, $year); @@ -149,6 +159,7 @@ class GetJobOrderArchiveDataCommand extends Command $data = []; $files = []; + $invoice_id_list = []; while ($q_row = $results->fetchAssociative()) { @@ -156,10 +167,8 @@ class GetJobOrderArchiveDataCommand extends Command // all invoice items for a specific invoice too if ($table_name == 'invoice') { - // get invoice item related data - $ii_file = $this->getInvoiceItemArchiveData($q_row, $year); - - $files['invoice_item'] = $ii_file; + // add invoice id to list + $invoice_id_list[] = $q_row['id']; } $fields = []; @@ -173,6 +182,14 @@ class GetJobOrderArchiveDataCommand extends Command $data[$table_name][$q_row['id']] = $fields; } + // get the invoice items for archiving + foreach ($invoice_id_list as $i_id) + { + $ii_file = $this->getInvoiceItemArchiveData($i_id, $year); + + $files['invoice_item'] = $ii_file; + } + // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); @@ -182,14 +199,14 @@ class GetJobOrderArchiveDataCommand extends Command return $files; } - protected function getInvoiceItemArchiveData($row, $year) + protected function getInvoiceItemArchiveData($id, $year) { $db = $this->em->getConnection(); $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; $query_stmt = $db->prepare($query_sql); - $query_stmt->bindValue('id', $row['id']); + $query_stmt->bindValue('id', $id); $results = $query_stmt->executeQuery(); -- 2.43.5 From b33257711efcca3186886ba9ac05631a1920eeff Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 22 Sep 2023 14:37:54 +0800 Subject: [PATCH 105/119] Set limit to jo query results. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index c1f24cc6..7303b79a 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -66,7 +66,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 150000'; + LIMIT 125000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); -- 2.43.5 From b2b39b72e1448f2e028f1b7c7a6abdd0f160e934 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 26 Sep 2023 13:03:47 +0800 Subject: [PATCH 106/119] Add retrieval of ids for deletion. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 7303b79a..d6ba4582 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -66,7 +66,7 @@ class GetJobOrderArchiveDataCommand extends Command FROM job_order WHERE YEAR(date_create) = :year ORDER BY date_create - LIMIT 125000'; + LIMIT 100000'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); @@ -151,6 +151,14 @@ class GetJobOrderArchiveDataCommand extends Command // error_log(print_r($archive_files, true)); $this->loadArchiveFiles($archive_files, $year); + + // need to get the list of invoice ids for deletion for invoice items + $invoice_id_list = $this->getInvoiceIds($jo_id_list); + + error_log(print_r($invoice_id_list, true)); + + // at this point, all the job order and related data have been archived into the database + $this->deleteData($jo_id_list, $invoice_id_list); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -256,7 +264,7 @@ class GetJobOrderArchiveDataCommand extends Command $cache_dir = __DIR__ . '/../../var/cache'; $file = $cache_dir . '/' . $table_name . '_archive.tab'; - error_log('opening file for archive - ' . $file); + // error_log('opening file for archive - ' . $file); $fp = fopen($file, $option); if ($fp === false) @@ -753,6 +761,39 @@ class GetJobOrderArchiveDataCommand extends Command } } + protected function deleteData($jo_id_list, $invoice_id_list) + { + $db = $this->em->getConnection(); + + // delete the invoice items first + } + + protected function getInvoiceIds($jo_id_list) + { + $invoice_id_list = []; + + $db = $this->em->getConnection(); + + $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; + + $query_stmt = $db->prepare($query_sql); + + foreach ($jo_id_list as $jo_id) + { + // need to get the invoice ids for the invoice items to delete + $query_stmt->bindValue('id', $jo_id); + + $results = $query_stmt->executeQuery(); + + while ($row = $results->fetchAssociative()) + { + $invoice_id_list[] = $row['id']; + } + } + + return $invoice_id_list; + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); -- 2.43.5 From 22985cde5140a1b32caa5709b8ca4d673feefe04 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 26 Sep 2023 16:28:40 +0800 Subject: [PATCH 107/119] Add deletion. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index d6ba4582..cc0fab18 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -39,6 +39,10 @@ class GetJobOrderArchiveDataCommand extends Command protected function execute(InputInterface $input, OutputInterface $output) { + $current_datetime = new DateTime('now'); + + error_log('Archive start time ' . $current_datetime->format('Y-m-d H:i')); + // get year to archive $year = $input->getArgument('year'); @@ -61,20 +65,26 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); - // TODO: improve performance. out of memory exception + // set the pdo connection to use unbuffered query so we don't run out of memory + // when processing the job order related tables + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + $query_sql = 'SELECT * FROM job_order WHERE YEAR(date_create) = :year - ORDER BY date_create - LIMIT 100000'; + ORDER BY date_create'; $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('year', $year, PDO::PARAM_STR); - $callback = ['App\Command\GetJobOrderArchiveDataCommand', 'getRelatedArchiveData']; + $callback = [$this, 'getRelatedArchiveData']; $this->getArchiveData($query_stmt, $callback, 'job_order', $year); + $current_datetime = new DateTime('now'); + + error_log('Archive end time ' . $current_datetime->format('Y-m-d H:i')); + return 0; } @@ -87,11 +97,11 @@ class GetJobOrderArchiveDataCommand extends Command // delete the related data files foreach ($related_tables as $tname) { - $this->deleteDataFiles($tname); + $this->deleteDataFiles($tname, $year); } // special since this is not directly related to JO but to invoice - $this->deleteDataFiles('invoice_item'); + $this->deleteDataFiles('invoice_item', $year); $archive_files = []; @@ -114,18 +124,21 @@ class GetJobOrderArchiveDataCommand extends Command { foreach ($related_tables as $table_name) { - if (($table_name == 'jo_event') || - ($table_name == 'invoice') || - ($table_name == 'ticket')) - { - $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; - } - else - { - $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + switch ($table_name) { + case 'jo_event': + case 'invoice': + case 'ticket': + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE job_order_id = :id'; + break; + case 'jo_rejection': + case 'rider_rating': + $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + default: + break; } $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_stmt = $db->prepare($query_sql); $query_stmt->bindValue('id', $jo_id); @@ -142,7 +155,7 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, 'w'); + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); if ($file != null) { @@ -155,7 +168,7 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - error_log(print_r($invoice_id_list, true)); + // error_log(print_r($invoice_id_list, true)); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list); @@ -199,7 +212,7 @@ class GetJobOrderArchiveDataCommand extends Command } // write the array into the file - $file = $this->createDataFileRelatedArchiveData($data, $table_name, 'a'); + $file = $this->createDataFileRelatedArchiveData($data, $table_name, $year, 'a'); if ($file != null) $files[$table_name] = $file; @@ -210,6 +223,7 @@ class GetJobOrderArchiveDataCommand extends Command protected function getInvoiceItemArchiveData($id, $year) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_sql = 'SELECT * FROM invoice_item WHERE invoice_id = :id'; @@ -238,23 +252,23 @@ class GetJobOrderArchiveDataCommand extends Command ]; } - $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', 'a'); + $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', $year, 'a'); return $file; } - protected function deleteDataFiles($tname) + protected function deleteDataFiles($tname, $year) { // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/' . $tname . '_archive.tab'; + $file = $cache_dir . '/' . $tname . '_archive_' . $year .'.tab'; if (file_exists($file)) unlink($file); } - protected function createDataFileRelatedArchiveData($archive_data, $table_name, $option) + protected function createDataFileRelatedArchiveData($archive_data, $table_name, $year, $option) { if (isset($archive_data[$table_name])) { @@ -263,7 +277,7 @@ class GetJobOrderArchiveDataCommand extends Command // cache directory $cache_dir = __DIR__ . '/../../var/cache'; - $file = $cache_dir . '/' . $table_name . '_archive.tab'; + $file = $cache_dir . '/' . $table_name . '_archive_'. $year . '.tab'; // error_log('opening file for archive - ' . $file); $fp = fopen($file, $option); @@ -766,6 +780,12 @@ class GetJobOrderArchiveDataCommand extends Command $db = $this->em->getConnection(); // delete the invoice items first + $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; + + $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN ($inv_ids)'; + $ii_stmt = $db->prepare($ii_del_sql); + + $ii_stmt->execute($invoice_id_list); } protected function getInvoiceIds($jo_id_list) -- 2.43.5 From ca09d6fc2e666b3246c35de435f340a7f3700894 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Sep 2023 14:54:36 +0800 Subject: [PATCH 108/119] Fix deletion issues for related tables. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index cc0fab18..3f9d3938 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -133,6 +133,7 @@ class GetJobOrderArchiveDataCommand extends Command case 'jo_rejection': case 'rider_rating': $query_sql = 'SELECT * FROM ' . $table_name . ' WHERE jo_id = :id'; + break; default: break; } @@ -171,7 +172,7 @@ class GetJobOrderArchiveDataCommand extends Command // error_log(print_r($invoice_id_list, true)); // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $invoice_id_list); + $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -775,17 +776,48 @@ class GetJobOrderArchiveDataCommand extends Command } } - protected function deleteData($jo_id_list, $invoice_id_list) + protected function deleteData($jo_id_list, $invoice_id_list, $related_tables) { $db = $this->em->getConnection(); // delete the invoice items first $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; - $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN ($inv_ids)'; + $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN (' . $inv_ids . ')'; $ii_stmt = $db->prepare($ii_del_sql); $ii_stmt->execute($invoice_id_list); + + // delete from invoice, jo_rejection, rider_rating, ticket, and jo_event + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; + + foreach ($related_tables as $table_name) + { + switch ($table_name) { + case 'jo_event': + case 'invoice': + case 'ticket': + $related_del_sql = 'DELETE FROM ' . $table_name . ' WHERE job_order_id IN ('. $jo_ids . ')'; + break; + case 'jo_rejection': + case 'rider_rating': + $related_del_sql = 'DELETE FROM ' . $table_name . ' WHERE jo_id IN (' . $jo_ids. ')'; + break; + default: + break; + } + + $related_stmt = $db->prepare($related_del_sql); + + $related_stmt->execute($jo_id_list); + } + + // TODO: hitting a snag here if JO to be deleted is a reference JO for another JO + // delete from job order last + $jo_del_sql = 'DELETE FROM job_order WHERE id IN (' . $jo_ids . ')'; + $jo_stmt = $db->prepare($jo_del_sql); + + $jo_stmt->execute($jo_id_list); } protected function getInvoiceIds($jo_id_list) -- 2.43.5 From a437a1f74e30a275904530abb7d91270fbfe8be2 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 14:15:41 +0800 Subject: [PATCH 109/119] Add reference_jo_id field to hold the job order id for reference orders. Add a command to decouple reference job order from job order. #762 --- .../SetJobOrderReferenceJOIdCommand.php | 53 +++++++++++++++++++ src/Entity/JobOrder.php | 19 ++++++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/Command/SetJobOrderReferenceJOIdCommand.php diff --git a/src/Command/SetJobOrderReferenceJOIdCommand.php b/src/Command/SetJobOrderReferenceJOIdCommand.php new file mode 100644 index 00000000..20ee236a --- /dev/null +++ b/src/Command/SetJobOrderReferenceJOIdCommand.php @@ -0,0 +1,53 @@ +em = $em; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('joborder:setreferencejoid') + ->setDescription('Set job order reference jo id for existing job orders.') + ->setHelp('Set job order reference jo id for existing job orders. Decoupling job order from reference job order.'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + // get the job orders where ref_jo is not null + $query = $this->em->createQuery('SELECT jo FROM App\Entity\JobOrder jo WHERE jo.ref_jo IS NOT NULL'); + + $jos = $query->getResult(); + + foreach ($jos as $jo) + { + $ref_jo_id = $jo->getReferenceJO()->getID(); + + error_log('Setting reference jo id ' . $ref_jo_id . ' for job order ' . $jo->getID()); + + $jo->setReferenceJOId($ref_jo_id); + + // set the ref_jo to null to decouple ref jo and jo + $jo->setReferenceJO(null); + } + + $this->em->flush(); + + return 0; + } +} diff --git a/src/Entity/JobOrder.php b/src/Entity/JobOrder.php index 885bc295..9229eed9 100644 --- a/src/Entity/JobOrder.php +++ b/src/Entity/JobOrder.php @@ -441,6 +441,12 @@ class JobOrder */ protected $flag_cust_new; + // reference JO id. We are now decoupling job order from itself + /** + * @ORM\Column(type="integer", nullable=true) + */ + protected $reference_jo_id; + public function __construct() { $this->date_create = new DateTime(); @@ -792,7 +798,7 @@ class JobOrder return $this->tickets; } - public function setReferenceJO(JobOrder $ref_jo) + public function setReferenceJO(JobOrder $ref_jo = null) { $this->ref_jo = $ref_jo; return $this; @@ -1256,4 +1262,15 @@ class JobOrder return $this->flag_cust_new; } + public function setReferenceJOId($reference_jo_id) + { + $this->reference_jo_id = $reference_jo_id; + return $this; + } + + public function getReferenceJOId() + { + return $this->reference_jo_id; + } + } -- 2.43.5 From 8ff3fe8d3c4e455052ec6c8ccd028d251377e0ae Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 14:41:49 +0800 Subject: [PATCH 110/119] Modify saving of reference job order for job order. #762 --- src/Service/JobOrderHandler/ResqJobOrderHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Service/JobOrderHandler/ResqJobOrderHandler.php b/src/Service/JobOrderHandler/ResqJobOrderHandler.php index 419c27c3..f5e07aaf 100644 --- a/src/Service/JobOrderHandler/ResqJobOrderHandler.php +++ b/src/Service/JobOrderHandler/ResqJobOrderHandler.php @@ -551,7 +551,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if (empty($ref_jo)) { $error_array['ref_jo'] = 'Invalid reference job order specified.'; } else { - $jo->setReferenceJO($ref_jo); + $jo->setReferenceJOId($ref_jo->getID()); } } @@ -2158,7 +2158,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface if (empty($ref_jo)) { $error_array['ref_jo'] = 'Invalid reference job order specified.'; } else { - $jo->setReferenceJO($ref_jo); + $jo->setReferenceJOId($ref_jo->getID()); } } -- 2.43.5 From d75b94693bd0eef4ce091d0a2ddcc354a131708f Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 16:00:28 +0800 Subject: [PATCH 111/119] Add updating of rider's active and current job orders. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 3f9d3938..563f77d0 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -169,7 +169,13 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // error_log(print_r($invoice_id_list, true)); + // need to get the list of riders whose active_jo_id or current_jo_id is + // set to very old JOs + $rider_id_list = $this->findRiderIDs($jo_id_list); + + // update rider's active_jo_id and current_jo_id to null + // so we can delete the old job orders (foreign key constraint) + $this->updateRiderJobOrders($rider_id_list); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); @@ -812,7 +818,6 @@ class GetJobOrderArchiveDataCommand extends Command $related_stmt->execute($jo_id_list); } - // TODO: hitting a snag here if JO to be deleted is a reference JO for another JO // delete from job order last $jo_del_sql = 'DELETE FROM job_order WHERE id IN (' . $jo_ids . ')'; $jo_stmt = $db->prepare($jo_del_sql); @@ -846,12 +851,51 @@ class GetJobOrderArchiveDataCommand extends Command return $invoice_id_list; } + protected function findRiderIDs($jo_id_list) + { + $rider_id_list = []; + + $db = $this->em->getConnection(); + + $rider_sql = 'SELECT id FROM rider WHERE ((current_jo_id = :jo_id) OR (active_jo_id = :jo_id))'; + $rider_stmt = $db->prepare($rider_sql); + + // find the riders with current_jo_id or active_jo_id are still set to the old JOs + foreach ($jo_id_list as $jo_id) + { + $rider_stmt->bindValue('jo_id', $jo_id); + + $results = $rider_stmt->executeQuery(); + + while ($row = $results->fetchAssociative()) + { + $rider_id_list[] = $row['id']; + } + } + + return $rider_id_list; + } + + protected function updateRiderJobOrders($rider_id_list) + { + $db = $this->em->getConnection(); + + $update_sql = 'UPDATE rider SET current_jo_id = NULL, SET active_jo_id = NULL WHERE id = :id'; + $update_stmt = $db->prepare($update_sql); + + foreach ($rider_id_list as $rider_id) + { + $update_stmt->execute([ + 'id' => $rider_id, + ]); + } + } + protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); // this statement is for job order - // TODO: make for other tables $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From 23ab280df311cdfca0f388e53149f5b424e7d71e Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 18:22:56 +0800 Subject: [PATCH 112/119] Add updating of rider's current and active jo ids to null. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 41 ++++--------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 563f77d0..4fe27fb7 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -169,13 +169,9 @@ class GetJobOrderArchiveDataCommand extends Command // need to get the list of invoice ids for deletion for invoice items $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // need to get the list of riders whose active_jo_id or current_jo_id is - // set to very old JOs - $rider_id_list = $this->findRiderIDs($jo_id_list); - // update rider's active_jo_id and current_jo_id to null // so we can delete the old job orders (foreign key constraint) - $this->updateRiderJobOrders($rider_id_list); + $this->updateRiderJobOrders($jo_id_list); // at this point, all the job order and related data have been archived into the database $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); @@ -830,6 +826,7 @@ class GetJobOrderArchiveDataCommand extends Command $invoice_id_list = []; $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; @@ -851,42 +848,18 @@ class GetJobOrderArchiveDataCommand extends Command return $invoice_id_list; } - protected function findRiderIDs($jo_id_list) - { - $rider_id_list = []; - - $db = $this->em->getConnection(); - - $rider_sql = 'SELECT id FROM rider WHERE ((current_jo_id = :jo_id) OR (active_jo_id = :jo_id))'; - $rider_stmt = $db->prepare($rider_sql); - - // find the riders with current_jo_id or active_jo_id are still set to the old JOs - foreach ($jo_id_list as $jo_id) - { - $rider_stmt->bindValue('jo_id', $jo_id); - - $results = $rider_stmt->executeQuery(); - - while ($row = $results->fetchAssociative()) - { - $rider_id_list[] = $row['id']; - } - } - - return $rider_id_list; - } - - protected function updateRiderJobOrders($rider_id_list) + protected function updateRiderJobOrders($jo_id_list) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $update_sql = 'UPDATE rider SET current_jo_id = NULL, SET active_jo_id = NULL WHERE id = :id'; + $update_sql = 'UPDATE rider SET current_jo_id = NULL, active_jo_id = NULL WHERE (current_jo_id = :id OR active_jo_id = :id)'; $update_stmt = $db->prepare($update_sql); - foreach ($rider_id_list as $rider_id) + foreach ($jo_id_list as $jo_id) { $update_stmt->execute([ - 'id' => $rider_id, + 'id' => $jo_id, ]); } } -- 2.43.5 From b66c809b01ee5c202d26dc3afd4185192cbef9ee Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 19:07:11 +0800 Subject: [PATCH 113/119] Add TODO for updating rider. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 4fe27fb7..e266f6dd 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -850,6 +850,11 @@ class GetJobOrderArchiveDataCommand extends Command protected function updateRiderJobOrders($jo_id_list) { + // TODO: memory exception while updating rider table. + // need to figure out how to make this not run out of memory. + // first draft had us selecting and finding the rider ids. maybe we should bring + // that back with the set attribute? I can't remember if I ran it with that one :( + // so that updating will have a smaller result set. $db = $this->em->getConnection(); $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); -- 2.43.5 From ce39e6612762d0b24172317b8fa1e5b03fbcb493 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Thu, 28 Sep 2023 19:35:10 +0800 Subject: [PATCH 114/119] Modify updating of rider table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e266f6dd..e5ac289d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -850,23 +850,19 @@ class GetJobOrderArchiveDataCommand extends Command protected function updateRiderJobOrders($jo_id_list) { - // TODO: memory exception while updating rider table. - // need to figure out how to make this not run out of memory. - // first draft had us selecting and finding the rider ids. maybe we should bring - // that back with the set attribute? I can't remember if I ran it with that one :( - // so that updating will have a smaller result set. + // TODO: test this $db = $this->em->getConnection(); - $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - $update_sql = 'UPDATE rider SET current_jo_id = NULL, active_jo_id = NULL WHERE (current_jo_id = :id OR active_jo_id = :id)'; - $update_stmt = $db->prepare($update_sql); + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; - foreach ($jo_id_list as $jo_id) - { - $update_stmt->execute([ - 'id' => $jo_id, - ]); - } + $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; + $update_curr_stmt = $db->prepare($update_curr_sql); + + $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; + $udpate_active_stmt = $db->prepare($update_active_sql); + + $update_curr_stmt->execute($jo_id_list); + $update_active_stmt->execute($jo_id_list); } protected function loadDataFileForArchiveData($load_stmt) -- 2.43.5 From 9128768b99666c1c63f128b2d57778df3f738f0e Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Fri, 29 Sep 2023 20:47:13 +0800 Subject: [PATCH 115/119] Fix issues found during testing. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 96 ++++++++++--------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index e5ac289d..1ff9ac6d 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -106,6 +106,7 @@ class GetJobOrderArchiveDataCommand extends Command $archive_files = []; $jo_id_list = []; + $ii_id_list = []; while ($row = $results->fetchAssociative()) { @@ -115,6 +116,24 @@ class GetJobOrderArchiveDataCommand extends Command $jo_id_list[] = $row['id']; } + // write the array into the file + $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); + + if ($file != null) + { + $archive_files[$jo_tname] = $file; + } + + // error_log('jo_data total ' . count($jo_data['job_order'])); + // error_log('jo id list total ' . count($jo_id_list)); + + unset($jo_data); + + // load the job order archive file for job order into the database + $this->loadArchiveFiles($archive_files, $year); + + unset($archive_files[$jo_tname]); + // get all related data for job order foreach ($jo_id_list as $jo_id) { @@ -155,26 +174,16 @@ class GetJobOrderArchiveDataCommand extends Command } } - // write the array into the file - $file = $this->createDataFileRelatedArchiveData($jo_data, $jo_tname, $year, 'w'); - - if ($file != null) - { - $archive_files[$jo_tname] = $file; - } - - // error_log(print_r($archive_files, true)); + // TODO: can we maybe find a way to not load the archive files successively? + // we get the memory exception after loading the data to the last table, jo_rejection. $this->loadArchiveFiles($archive_files, $year); - // need to get the list of invoice ids for deletion for invoice items - $invoice_id_list = $this->getInvoiceIds($jo_id_list); - // update rider's active_jo_id and current_jo_id to null // so we can delete the old job orders (foreign key constraint) $this->updateRiderJobOrders($jo_id_list); // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $invoice_id_list, $related_tables); + $this->deleteData($jo_id_list, $related_tables); } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -207,6 +216,7 @@ class GetJobOrderArchiveDataCommand extends Command } // get the invoice items for archiving + $ii_id_list = []; foreach ($invoice_id_list as $i_id) { $ii_file = $this->getInvoiceItemArchiveData($i_id, $year); @@ -217,6 +227,8 @@ class GetJobOrderArchiveDataCommand extends Command // write the array into the file $file = $this->createDataFileRelatedArchiveData($data, $table_name, $year, 'a'); + unset($data); + if ($file != null) $files[$table_name] = $file; @@ -236,6 +248,7 @@ class GetJobOrderArchiveDataCommand extends Command $results = $query_stmt->executeQuery(); $ii_data = []; + $ii_id_list = []; while ($ii_row = $results->fetchAssociative()) { $id = $ii_row['id']; @@ -253,10 +266,19 @@ class GetJobOrderArchiveDataCommand extends Command $price, $battery_id ]; + + $ii_id_list[] = $id; } $file = $this->createDataFileRelatedArchiveData($ii_data, 'invoice_item', $year, 'a'); + unset($ii_data); + + // special case, delete the invoice items already + // so that we don't have to query for the invoice items to delete + if (count($ii_id_list) > 0) + $this->deleteInvoiceItems($ii_id_list); + return $file; } @@ -778,17 +800,22 @@ class GetJobOrderArchiveDataCommand extends Command } } - protected function deleteData($jo_id_list, $invoice_id_list, $related_tables) + protected function deleteInvoiceItems($ii_id_list) { $db = $this->em->getConnection(); // delete the invoice items first - $inv_ids = str_repeat('?,', count($invoice_id_list) - 1) . '?'; + $ii_ids = str_repeat('?,', count($ii_id_list) - 1) . '?'; - $ii_del_sql = 'DELETE FROM invoice_item WHERE invoice_id IN (' . $inv_ids . ')'; + $ii_del_sql = 'DELETE FROM invoice_item WHERE id IN (' . $ii_ids . ')'; $ii_stmt = $db->prepare($ii_del_sql); - $ii_stmt->execute($invoice_id_list); + $ii_stmt->execute($ii_id_list); + } + + protected function deleteData($jo_id_list, $related_tables) + { + $db = $this->em->getConnection(); // delete from invoice, jo_rejection, rider_rating, ticket, and jo_event $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; @@ -821,36 +848,8 @@ class GetJobOrderArchiveDataCommand extends Command $jo_stmt->execute($jo_id_list); } - protected function getInvoiceIds($jo_id_list) - { - $invoice_id_list = []; - - $db = $this->em->getConnection(); - $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - - $query_sql = 'SELECT id FROM invoice WHERE job_order_id = :id'; - - $query_stmt = $db->prepare($query_sql); - - foreach ($jo_id_list as $jo_id) - { - // need to get the invoice ids for the invoice items to delete - $query_stmt->bindValue('id', $jo_id); - - $results = $query_stmt->executeQuery(); - - while ($row = $results->fetchAssociative()) - { - $invoice_id_list[] = $row['id']; - } - } - - return $invoice_id_list; - } - protected function updateRiderJobOrders($jo_id_list) { - // TODO: test this $db = $this->em->getConnection(); $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; @@ -859,17 +858,20 @@ class GetJobOrderArchiveDataCommand extends Command $update_curr_stmt = $db->prepare($update_curr_sql); $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; - $udpate_active_stmt = $db->prepare($update_active_sql); + $update_active_stmt = $db->prepare($update_active_sql); $update_curr_stmt->execute($jo_id_list); $update_active_stmt->execute($jo_id_list); + + unset($update_curr_stmt); + unset($update_active_stmt); } protected function loadDataFileForArchiveData($load_stmt) { $conn = $this->em->getConnection(); + $conn->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); - // this statement is for job order $stmt = $conn->prepare($load_stmt); $result = $stmt->execute(); -- 2.43.5 From dc363e46cc400deca6558dfa18bd90b8f9898309 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Tue, 3 Oct 2023 22:08:46 +0800 Subject: [PATCH 116/119] Added batch update for rider table. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index 1ff9ac6d..a6540080 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -174,16 +174,23 @@ class GetJobOrderArchiveDataCommand extends Command } } - // TODO: can we maybe find a way to not load the archive files successively? - // we get the memory exception after loading the data to the last table, jo_rejection. $this->loadArchiveFiles($archive_files, $year); - // update rider's active_jo_id and current_jo_id to null - // so we can delete the old job orders (foreign key constraint) - $this->updateRiderJobOrders($jo_id_list); + error_log('Done loading files into database...'); - // at this point, all the job order and related data have been archived into the database - $this->deleteData($jo_id_list, $related_tables); + $jo_id_array = array_chunk($jo_id_list, 10000); + + unset($jo_id_list); + + foreach($jo_id_array as $key => $jo_ids) + { + // update rider's active_jo_id and current_jo_id to null + // so we can delete the old job orders (foreign key constraint) + $this->updateRiderActiveJobOrders($jo_ids); + $this->updateRiderCurrentJobOrders($jo_ids); + + $this->deleteData($jo_ids, $related_tables); + } } protected function getRelatedArchiveData($row, $query_stmt, $table_name, $year) @@ -279,6 +286,8 @@ class GetJobOrderArchiveDataCommand extends Command if (count($ii_id_list) > 0) $this->deleteInvoiceItems($ii_id_list); + unset($ii_id_list); + return $file; } @@ -848,23 +857,38 @@ class GetJobOrderArchiveDataCommand extends Command $jo_stmt->execute($jo_id_list); } - protected function updateRiderJobOrders($jo_id_list) + protected function updateRiderActiveJobOrders($jo_id_list) { $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); + + $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; + + $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; + $update_active_stmt = $db->prepare($update_active_sql); + + error_log('Updating active rider job orders...'); + + $update_active_stmt->execute($jo_id_list); + + unset($update_active_stmt); + } + + protected function updateRiderCurrentJobOrders($jo_id_list) + { + $db = $this->em->getConnection(); + $db->getWrappedConnection()->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); $jo_ids = str_repeat('?,', count($jo_id_list) - 1) . '?'; $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; $update_curr_stmt = $db->prepare($update_curr_sql); - $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; - $update_active_stmt = $db->prepare($update_active_sql); + error_log('Updating current rider job orders...'); $update_curr_stmt->execute($jo_id_list); - $update_active_stmt->execute($jo_id_list); unset($update_curr_stmt); - unset($update_active_stmt); } protected function loadDataFileForArchiveData($load_stmt) -- 2.43.5 From 03709b0d34a3bc45a54e3225d7786a96d3710753 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 4 Oct 2023 10:08:42 +0800 Subject: [PATCH 117/119] Add fix for missing entries when loading file to database. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index a6540080..cd764e56 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -743,6 +743,7 @@ class GetJobOrderArchiveDataCommand extends Command // load statement for job order $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, customer_id, cvehicle_id, rider_id, date_create, date_schedule, date_fulfill, @coordinates, flag_advance, service_type, @@ -762,6 +763,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, create_user_id, job_order_id, date_create, date_happen, type_id, rider_id)'; } @@ -769,6 +771,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, hub_id, jo_id, date_create, reason, remarks, contact_person)'; } @@ -776,6 +779,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, job_order_id, date_create, date_paid, discount, trade_in, vat, vat_exclusive_price, total_price, status, promo_id, used_customer_tag_id)'; @@ -784,6 +788,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, rider_id, customer_id, jo_id, date_create, rating, comment)'; } @@ -791,6 +796,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, user_id, customer_id, date_create, status, ticket_type, other_ticket_type, first_name, last_name, contact_num, details, job_order_id, plate_number, ticket_type_id, subticket_type_id, @@ -800,6 +806,7 @@ class GetJobOrderArchiveDataCommand extends Command { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' FIELDS TERMINATED BY \'|\' + ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' (id, invoice_id, title, qty, price, battery_id)'; } -- 2.43.5 From 1d743abd87beaa0ef46f533447820d83a68ab910 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 4 Oct 2023 13:58:53 +0800 Subject: [PATCH 118/119] Fix saving of the enye character. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index cd764e56..b289cff6 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -403,7 +403,8 @@ class GetJobOrderArchiveDataCommand extends Command `initial_concern_notes` longtext COLLATE utf8_unicode_ci DEFAULT NULL, `gender` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, `caller_classification` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, - `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`))'; + `inventory_count` smallint(6) NOT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -435,7 +436,8 @@ class GetJobOrderArchiveDataCommand extends Command `total_price` decimal(9,2) NOT NULL, `status` varchar(40) COLLATE utf8_unicode_ci NOT NULL, `promo_id` int(11) DEFAULT NULL, - `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `used_customer_tag_id` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -457,7 +459,8 @@ class GetJobOrderArchiveDataCommand extends Command `title` varchar(80) COLLATE utf8_unicode_ci NOT NULL, `qty` smallint(6) NOT NULL, `price` decimal(9,2) NOT NULL, - `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + `battery_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -491,7 +494,8 @@ class GetJobOrderArchiveDataCommand extends Command `subticket_type_id` int(11) DEFAULT NULL, `source_of_awareness` varchar(80) COLLATE utf8_unicode_ci DEFAULT NULL, `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, - `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `other_description` longtext COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -515,7 +519,8 @@ class GetJobOrderArchiveDataCommand extends Command `date_create` datetime NOT NULL, `reason` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `remarks` longtext COLLATE utf8_unicode_ci DEFAULT NULL, - `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`))'; + `contact_person` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -538,7 +543,8 @@ class GetJobOrderArchiveDataCommand extends Command `jo_id` int(11) DEFAULT NULL, `date_create` datetime NOT NULL, `rating` int(11) NOT NULL, - `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`))'; + `comment` longtext COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -561,7 +567,8 @@ class GetJobOrderArchiveDataCommand extends Command `date_create` datetime NOT NULL, `date_happen` datetime NOT NULL, `type_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL, - `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`))'; + `rider_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) + DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci'; $create_stmt = $db->prepare($create_sql); @@ -741,7 +748,8 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'job_order') { // load statement for job order - $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -762,6 +770,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'jo_event') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -770,6 +779,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'jo_rejection') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -778,6 +788,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'invoice') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -787,6 +798,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'rider_rating') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -795,6 +807,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'ticket') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -805,6 +818,7 @@ class GetJobOrderArchiveDataCommand extends Command if ($tname == 'invoice_item') { $load_stmt = 'LOAD DATA LOCAL INFILE \'' . $file . '\' INTO TABLE ' . $archive_tname . ' + CHARACTER SET UTF8 FIELDS TERMINATED BY \'|\' ESCAPED BY \'\b\' LINES TERMINATED BY \'\\r\\n\' @@ -874,7 +888,7 @@ class GetJobOrderArchiveDataCommand extends Command $update_active_sql = 'UPDATE rider SET active_jo_id = NULL WHERE active_jo_id IN (' . $jo_ids . ')'; $update_active_stmt = $db->prepare($update_active_sql); - error_log('Updating active rider job orders...'); + // error_log('Updating active rider job orders...'); $update_active_stmt->execute($jo_id_list); @@ -891,7 +905,7 @@ class GetJobOrderArchiveDataCommand extends Command $update_curr_sql = 'UPDATE rider SET current_jo_id = NULL WHERE current_jo_id IN (' . $jo_ids . ')'; $update_curr_stmt = $db->prepare($update_curr_sql); - error_log('Updating current rider job orders...'); + // error_log('Updating current rider job orders...'); $update_curr_stmt->execute($jo_id_list); -- 2.43.5 From ac361866bb2d0c129284b55ee09a684fbc9bd75a Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 27 Mar 2024 01:07:11 -0400 Subject: [PATCH 119/119] Modify array size for job order. #762 --- src/Command/GetJobOrderArchiveDataCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Command/GetJobOrderArchiveDataCommand.php b/src/Command/GetJobOrderArchiveDataCommand.php index b289cff6..a70c62dc 100644 --- a/src/Command/GetJobOrderArchiveDataCommand.php +++ b/src/Command/GetJobOrderArchiveDataCommand.php @@ -178,7 +178,7 @@ class GetJobOrderArchiveDataCommand extends Command error_log('Done loading files into database...'); - $jo_id_array = array_chunk($jo_id_list, 10000); + $jo_id_array = array_chunk($jo_id_list, 15000); unset($jo_id_list); -- 2.43.5