Assist_Design/docs/integrations/salesforce/apex/SIMInventoryImporter.cls
tema 7139e0489d Enhance Service Pages with New FAQ Sections and Content Updates
- Added new FAQ sections to the TV Services and Public Internet Plans pages, improving user assistance and engagement.
- Updated the Onsite Support page to utilize a dedicated content component for better organization and maintainability.
- Included device compatibility information in the SIM Plans content, enhancing user clarity on service offerings.
- Improved the structure and functionality of FAQ items across various service pages for a more interactive user experience.
2026-01-20 11:43:51 +09:00

272 lines
11 KiB
OpenEdge ABL

/**
* SIMInventoryImporter
* Invocable Apex class for importing Physical SIM inventory from CSV files.
* Used by Screen Flow to allow employees to bulk import physical SIMs.
*
* CSV Format Expected (matching ASI_N6_PASI_*.csv):
* Row,Phone_Number,PT_Number,OEM_ID,Batch_Date,,,,,
* 1,02000002470001,PT0220024700010,PASI,20251229,,,,
*
* Note: No header row expected. All imports are Physical SIM type.
*
* @author Customer Portal Team
* @version 1.1
*/
public with sharing class SIMInventoryImporter {
// Hardcoded values for Physical SIM imports
private static final String SIM_TYPE = 'Physical SIM';
private static final Boolean SKIP_HEADER = false;
/**
* Input wrapper for the invocable method
*/
public class ImportRequest {
@InvocableVariable(label='Content Document IDs' description='IDs from File Upload component' required=true)
public List<String> contentDocumentIds;
}
/**
* Output wrapper for the invocable method
*/
public class ImportResult {
@InvocableVariable(label='Success')
public Boolean success;
@InvocableVariable(label='Records Created')
public Integer recordsCreated;
@InvocableVariable(label='Records Failed')
public Integer recordsFailed;
@InvocableVariable(label='Error Messages')
public String errorMessages;
@InvocableVariable(label='Summary Message')
public String summaryMessage;
}
/**
* Main invocable method called by Flow
*/
@InvocableMethod(label='Import SIM Inventory from CSV'
description='Parses CSV content and creates SIM_Inventory__c records'
category='SIM Management')
public static List<ImportResult> importFromCSV(List<ImportRequest> requests) {
List<ImportResult> results = new List<ImportResult>();
for (ImportRequest request : requests) {
results.add(processCSV(request));
}
return results;
}
/**
* Process a single CSV import request
*/
private static ImportResult processCSV(ImportRequest request) {
ImportResult result = new ImportResult();
result.success = true;
result.recordsCreated = 0;
result.recordsFailed = 0;
result.errorMessages = '';
try {
// Get the first Content Document ID from the list
if (request.contentDocumentIds == null || request.contentDocumentIds.isEmpty()) {
result.success = false;
result.errorMessages = 'No file was uploaded. Please select a CSV file.';
result.summaryMessage = 'Import failed: No file uploaded';
return result;
}
String contentDocumentId = request.contentDocumentIds[0];
// Retrieve file content from ContentVersion
List<ContentVersion> cvList = [
SELECT VersionData
FROM ContentVersion
WHERE ContentDocumentId = :contentDocumentId
AND IsLatest = true
LIMIT 1
];
if (cvList.isEmpty()) {
result.success = false;
result.errorMessages = 'Could not find the uploaded file. Please try again.';
result.summaryMessage = 'Import failed: File not found';
return result;
}
String csvContent = cvList[0].VersionData.toString();
// Parse CSV content
List<String> lines = csvContent.split('\n');
List<SIM_Inventory__c> simsToInsert = new List<SIM_Inventory__c>();
List<String> errors = new List<String>();
// Start from first row (no header row in Physical SIM CSV files)
Integer startIndex = SKIP_HEADER ? 1 : 0;
// Collect existing phone numbers to check for duplicates
Set<String> existingPhoneNumbers = new Set<String>();
for (SIM_Inventory__c existing : [SELECT Phone_Number__c FROM SIM_Inventory__c WHERE Phone_Number__c != null]) {
existingPhoneNumbers.add(existing.Phone_Number__c);
}
Set<String> phoneNumbersInBatch = new Set<String>();
for (Integer i = startIndex; i < lines.size(); i++) {
String line = lines[i].trim();
// Skip empty lines
if (String.isBlank(line)) {
continue;
}
// Remove carriage return if present (Windows line endings)
line = line.replace('\r', '');
try {
// Parse CSV line
List<String> columns = parseCSVLine(line);
// Expected format: Row,Phone_Number,PT_Number,OEM_ID,Batch_Date,,,,,
if (columns.size() < 2) {
errors.add('Row ' + (i + 1) + ': Not enough columns (need at least phone number)');
result.recordsFailed++;
continue;
}
String phoneNumber = columns.size() > 1 ? columns[1].trim() : '';
String ptNumber = columns.size() > 2 ? columns[2].trim() : '';
String oemId = columns.size() > 3 ? columns[3].trim() : '';
String batchDateStr = columns.size() > 4 ? columns[4].trim() : '';
// Validate phone number
if (String.isBlank(phoneNumber)) {
errors.add('Row ' + (i + 1) + ': Phone number is empty');
result.recordsFailed++;
continue;
}
// Check for duplicates in database
if (existingPhoneNumbers.contains(phoneNumber)) {
errors.add('Row ' + (i + 1) + ': Phone number ' + phoneNumber + ' already exists in database');
result.recordsFailed++;
continue;
}
// Check for duplicates within the CSV
if (phoneNumbersInBatch.contains(phoneNumber)) {
errors.add('Row ' + (i + 1) + ': Duplicate phone number ' + phoneNumber + ' in CSV file');
result.recordsFailed++;
continue;
}
// Parse batch date (format: YYYYMMDD)
Date batchDate = null;
if (String.isNotBlank(batchDateStr) && batchDateStr.length() >= 8) {
try {
Integer year = Integer.valueOf(batchDateStr.substring(0, 4));
Integer month = Integer.valueOf(batchDateStr.substring(4, 6));
Integer day = Integer.valueOf(batchDateStr.substring(6, 8));
batchDate = Date.newInstance(year, month, day);
} catch (Exception e) {
// Leave as null if parsing fails - not critical
}
}
// Create SIM_Inventory__c record
SIM_Inventory__c sim = new SIM_Inventory__c();
sim.Phone_Number__c = phoneNumber;
sim.PT_Number__c = ptNumber;
sim.OEM_ID__c = oemId;
sim.Batch_Date__c = batchDate;
sim.Status__c = 'Available';
sim.SIM_Type__c = SIM_TYPE; // Always Physical SIM
sim.Name = phoneNumber; // Use phone number as name for easy identification
simsToInsert.add(sim);
phoneNumbersInBatch.add(phoneNumber);
} catch (Exception e) {
errors.add('Row ' + (i + 1) + ': ' + e.getMessage());
result.recordsFailed++;
}
}
// Insert records with partial success allowed
if (!simsToInsert.isEmpty()) {
Database.SaveResult[] saveResults = Database.insert(simsToInsert, false);
for (Integer i = 0; i < saveResults.size(); i++) {
if (saveResults[i].isSuccess()) {
result.recordsCreated++;
} else {
result.recordsFailed++;
for (Database.Error err : saveResults[i].getErrors()) {
errors.add('Insert error for ' + simsToInsert[i].Phone_Number__c + ': ' + err.getMessage());
}
}
}
}
// Build error message string (limit to first 10 errors for readability)
if (!errors.isEmpty()) {
if (errors.size() <= 10) {
result.errorMessages = String.join(errors, '\n');
} else {
List<String> firstTen = new List<String>();
for (Integer i = 0; i < 10; i++) {
firstTen.add(errors[i]);
}
result.errorMessages = String.join(firstTen, '\n')
+ '\n\n... and ' + (errors.size() - 10) + ' more errors';
}
}
// Build summary message
result.summaryMessage = 'Import completed: ' + result.recordsCreated + ' records created successfully.';
if (result.recordsFailed > 0) {
result.summaryMessage += ' ' + result.recordsFailed + ' records failed.';
result.success = (result.recordsCreated > 0); // Partial success if any records created
}
} catch (Exception e) {
result.success = false;
result.errorMessages = 'Critical error: ' + e.getMessage() + '\n\nStack trace: ' + e.getStackTraceString();
result.summaryMessage = 'Import failed due to an unexpected error.';
}
return result;
}
/**
* Parse a single CSV line, handling quoted fields properly
*/
private static List<String> parseCSVLine(String line) {
List<String> result = new List<String>();
Boolean inQuotes = false;
String currentField = '';
for (Integer i = 0; i < line.length(); i++) {
String c = line.substring(i, i + 1);
if (c == '"') {
inQuotes = !inQuotes;
} else if (c == ',' && !inQuotes) {
result.add(currentField);
currentField = '';
} else {
currentField += c;
}
}
// Add the last field
result.add(currentField);
return result;
}
}