Compare commits
	
		
			No commits in common. "86647ef04ec7c70ae8f281f62f114f4f1e55222b" and "74ab38ce6b0dc074f0e93cce158320128f245cc7" have entirely different histories. 
		
	
	
		
			86647ef04e
			...
			74ab38ce6b
		
	
		
	| 
						 | 
				
			
			@ -35,7 +35,7 @@
 | 
			
		|||
                    <div class="relative w-full h-60 bg-center bg-gray-100 rounded-xl flex items-center justify-center mx-auto mb-3 overflow-hidden preview-container" id="preview-container">
 | 
			
		||||
                        <div id="default-state">
 | 
			
		||||
                            <div class="upload-icon-container">
 | 
			
		||||
                                <img class="object-cover" src="~/driver/images/trukk.jpg" alt="contoh gambar">
 | 
			
		||||
                                <img src="~/driver/images/trukk.jpg" alt="contoh gambar">
 | 
			
		||||
                                <p class="absolute inset-0 flex items-center justify-center text-white">Contoh Foto</p>
 | 
			
		||||
                                @* <i class="w-8 h-8 text-orange-600" data-lucide="upload-cloud" id="preview-icon"></i> *@
 | 
			
		||||
                            </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
    <link rel="stylesheet" href="@Url.Content("~/driver/css/scanner.css")" asp-append-version="true" />
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<div class="w-full lg:max-w-sm mx-auto bg-white min-h-screen">
 | 
			
		||||
<div class="max-w-sm mx-auto bg-white min-h-screen">
 | 
			
		||||
    <div class="bg-orange-500 text-white px-3 py-4 rounded-b-2xl relative pb-12">
 | 
			
		||||
        <div class="flex items-center justify-between">
 | 
			
		||||
            <a href="@Url.Action("Index", "Home")" class="p-1 hover:bg-white/10 rounded-full transition-colors">
 | 
			
		||||
| 
						 | 
				
			
			@ -180,7 +180,7 @@
 | 
			
		|||
                </div>
 | 
			
		||||
 | 
			
		||||
                <!-- Waktu Masuk dan Keluar -->
 | 
			
		||||
                <div class="grid grid-cols-1 gap-3">
 | 
			
		||||
                <div class="grid grid-cols-2 gap-3">
 | 
			
		||||
                    <div>
 | 
			
		||||
                        <label for="WaktuMasuk" class="block text-sm font-medium text-gray-700 mb-1">Masuk</label>
 | 
			
		||||
                        <input 
 | 
			
		||||
| 
						 | 
				
			
			@ -188,7 +188,7 @@
 | 
			
		|||
                            id="WaktuMasuk" 
 | 
			
		||||
                            name="WaktuMasuk" 
 | 
			
		||||
                            class="mt-1 block w-full rounded-lg border border-orange-300 shadow-sm focus:border-orange-500 focus:ring-2 focus:ring-orange-200 transition-all duration-150 px-4 py-2" 
 | 
			
		||||
                            placeholder="2025-08-04, 08:13:51" 
 | 
			
		||||
                            placeholder="04 Aug 2025, 08:13:51" 
 | 
			
		||||
                        />
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div>
 | 
			
		||||
| 
						 | 
				
			
			@ -198,7 +198,7 @@
 | 
			
		|||
                            id="WaktuKeluar" 
 | 
			
		||||
                            name="WaktuKeluar" 
 | 
			
		||||
                            class="mt-1 block w-full rounded-lg border border-orange-300 shadow-sm focus:border-orange-500 focus:ring-2 focus:ring-orange-200 transition-all duration-150 px-4 py-2" 
 | 
			
		||||
                            placeholder="2025-08-04, 14:35:10" 
 | 
			
		||||
                            placeholder="04 Aug 2025, 14:35:10" 
 | 
			
		||||
                        />
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +253,7 @@
 | 
			
		|||
</div>
 | 
			
		||||
 | 
			
		||||
<register-block dynamic-section="scripts" key="jsSubmitStruk">
 | 
			
		||||
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5.1.1/dist/tesseract.min.js"></script>
 | 
			
		||||
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@4.1.1/dist/tesseract.min.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
    document.addEventListener('DOMContentLoaded', function() {
 | 
			
		||||
        const nomorStrukInput = document.getElementById('NomorStruk');
 | 
			
		||||
| 
						 | 
				
			
			@ -577,35 +577,36 @@
 | 
			
		|||
                let weightNett = '';
 | 
			
		||||
 | 
			
		||||
                const receiptPatterns = [
 | 
			
		||||
                    /(\d{2})_(\d{6,})/gi,                    
 | 
			
		||||
                    /(\d{2})\s+(\d{6,})/gi,             
 | 
			
		||||
                    /(?:no.*struk|nomor.*struk|receipt)[\s.:]*(\d{6,})/gi, 
 | 
			
		||||
                    /(?:^|\s)(\d{6,10})(?:\s|$)/g,         
 | 
			
		||||
                    /(\d{2})\s+(\d{7,})/gi, 
 | 
			
		||||
                    /(\d{2})_(\d{7,})/gi, 
 | 
			
		||||
                    /(?:no.*struk|nomor.*struk|receipt)[\s.:]*(\d{7,})/gi,
 | 
			
		||||
                    /(?:^|\s)(\d{7,10})(?:\s|$)/g, 
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                for (const line of lines) {
 | 
			
		||||
                    console.log(`Processing line for receipt: "${line}"`);
 | 
			
		||||
                    
 | 
			
		||||
                    const monthUnderscoreMatch = line.match(/(\d{2})_(\d{6,})/);
 | 
			
		||||
                    const monthNumberMatch = line.match(/(\d{2})\s+(\d{7,})/);
 | 
			
		||||
                    if (monthNumberMatch && monthNumberMatch[2]) {
 | 
			
		||||
                        receiptNumber = monthNumberMatch[2]; // Take the number after space/underscore
 | 
			
		||||
                        console.log(`Found receipt number: ${receiptNumber} using month-number pattern`);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const monthUnderscoreMatch = line.match(/(\d{2})_(\d{7,})/);
 | 
			
		||||
                    if (monthUnderscoreMatch && monthUnderscoreMatch[2]) {
 | 
			
		||||
                        receiptNumber = monthUnderscoreMatch[2]; 
 | 
			
		||||
                        console.log(`Found receipt number: ${receiptNumber} using month-underscore pattern (removed prefix: ${monthUnderscoreMatch[1]}_)`);
 | 
			
		||||
                        receiptNumber = monthUnderscoreMatch[2]; // Take the number after underscore
 | 
			
		||||
                        console.log(`Found receipt number: ${receiptNumber} using month-underscore pattern`);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const monthSpaceMatch = line.match(/(\d{2})\s+(\d{6,})/);
 | 
			
		||||
                    if (monthSpaceMatch && monthSpaceMatch[2]) {
 | 
			
		||||
                        receiptNumber = monthSpaceMatch[2]; // Take ONLY the number after space
 | 
			
		||||
                        console.log(`Found receipt number: ${receiptNumber} using month-space pattern (removed prefix: ${monthSpaceMatch[1]} )`);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    for (const pattern of receiptPatterns.slice(2)) {
 | 
			
		||||
                    // Other patterns
 | 
			
		||||
                    for (const pattern of receiptPatterns.slice(2)) { // Skip first 2 patterns already handled above
 | 
			
		||||
                        const matches = [...line.matchAll(pattern)];
 | 
			
		||||
                        for (const match of matches) {
 | 
			
		||||
                            if (match[1] && match[1].length >= 6) {
 | 
			
		||||
                            if (match[1] && match[1].length >= 7) {
 | 
			
		||||
                                receiptNumber = match[1];
 | 
			
		||||
                                console.log(`Found receipt number: ${receiptNumber} using context pattern: ${pattern}`);
 | 
			
		||||
                                console.log(`Found receipt number: ${receiptNumber} using pattern: ${pattern}`);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
| 
						 | 
				
			
			@ -667,150 +668,157 @@
 | 
			
		|||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (!truckNumber) {
 | 
			
		||||
                                for (const line of lines) {
 | 
			
		||||
                                    if (line.toLowerCase().includes('no truk')) {
 | 
			
		||||
                                        const match = line.match(/no\s*truk\s*:?\s*(.+)/i);
 | 
			
		||||
                                        if (match && match[1]) {
 | 
			
		||||
                                            truckNumber = match[1].trim();
 | 
			
		||||
                                            console.log(`Found truck number: ${truckNumber} (ambil semua karakter setelah label No Truk)`);
 | 
			
		||||
                    console.log('No truck number found in context lines, trying all lines...');
 | 
			
		||||
                    for (const line of lines) {
 | 
			
		||||
                        console.log(`Scanning line for truck pattern: "${line}"`);
 | 
			
		||||
                        
 | 
			
		||||
                        if (line.match(/[A-Z]\s*\d+\s*[A-Z]{2,3}/i)) {
 | 
			
		||||
                            console.log('Potential truck pattern found:', line);
 | 
			
		||||
                            
 | 
			
		||||
                            for (const pattern of truckPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match) {
 | 
			
		||||
                                    let foundTruck = '';
 | 
			
		||||
                                    
 | 
			
		||||
                                    if (match.length === 4 && match[1] && match[2] && match[3]) {
 | 
			
		||||
                                        foundTruck = `${match[1]} ${match[2]} ${match[3]}`;
 | 
			
		||||
                                    } else if (match[1]) {
 | 
			
		||||
                                        foundTruck = match[1].trim();
 | 
			
		||||
                                    }
 | 
			
		||||
                                    
 | 
			
		||||
                                    if (foundTruck) {
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/([A-Z])(\d+)(\s+[A-Z]{2,3})/g, '$1 $2$3');
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/([A-Z]{1,2})(\d{3,4})([A-Z]{2,3})/g, '$1 $2 $3');
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/\s+/g, ' ').trim();
 | 
			
		||||
                                        
 | 
			
		||||
                                        if (foundTruck.match(/^[A-Z]{1,2}\s+\d{3,4}\s+[A-Z]{2,3}$/)) {
 | 
			
		||||
                                            truckNumber = foundTruck;
 | 
			
		||||
                                            console.log(`Found truck number: "${truckNumber}" using general pattern`);
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                if (!truckNumber) {
 | 
			
		||||
                                    for (const line of lines) {
 | 
			
		||||
                                        const match = line.match(/\bB\s*\d{3,5}\s*[A-Z]{2,4}\b/i);
 | 
			
		||||
                                        if (match && match[0]) {
 | 
			
		||||
                                            truckNumber = match[0].trim();
 | 
			
		||||
                                            console.log(`Fallback truck number: ${truckNumber}`);
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                            }
 | 
			
		||||
                            if (truckNumber) break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (!truckNumber) {
 | 
			
		||||
                    console.log('Still no truck number, trying loose patterns...');
 | 
			
		||||
                    for (const line of lines) {
 | 
			
		||||
                        const looseMatch = line.match(/([A-Z]{1,2})\s*(\d{3,4})\s*([A-Z]{2,3})/i);
 | 
			
		||||
                        if (looseMatch && looseMatch[1] && looseMatch[2] && looseMatch[3]) {
 | 
			
		||||
                            const candidate = `${looseMatch[1].toUpperCase()} ${looseMatch[2]} ${looseMatch[3].toUpperCase()}`;
 | 
			
		||||
                            console.log(`Found potential truck number with loose pattern: "${candidate}"`);
 | 
			
		||||
                            
 | 
			
		||||
                            if (looseMatch[1].length <= 2 && 
 | 
			
		||||
                                looseMatch[2].length >= 3 && looseMatch[2].length <= 4 &&
 | 
			
		||||
                                looseMatch[3].length >= 2 && looseMatch[3].length <= 3) {
 | 
			
		||||
                                truckNumber = candidate;
 | 
			
		||||
                                console.log(`Accepted truck number: "${truckNumber}"`);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Truck detection results:', { truckNumber });
 | 
			
		||||
                
 | 
			
		||||
                console.log('Truck detection result:', truckNumber);
 | 
			
		||||
 | 
			
		||||
                const assignmentPatterns = [
 | 
			
		||||
                    /(?:penugasan|assignment)[\s.:]*([A-Z\s]+?)(?:\n|$)/gi,
 | 
			
		||||
                    /(JAKARTA\s+\w+)/gi, // Specific pattern for Jakarta areas
 | 
			
		||||
                    /(BANDUNG|SURABAYA|MEDAN|SEMARANG|PALEMBANG|MAKASSAR)[\s\w]*/gi,
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                for (const line of lines) {
 | 
			
		||||
                    console.log(`Processing line for assignment: "${line}"`);
 | 
			
		||||
                    
 | 
			
		||||
                    if (line.toLowerCase().includes('penugasan')) {
 | 
			
		||||
                        console.log('Found penugasan line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        const match = line.match(/penugasan\s*:?\s*(.+)/i);
 | 
			
		||||
                        if (match && match[1]) {
 | 
			
		||||
                            assignment = match[1].trim();
 | 
			
		||||
                            console.log(`Found assignment: ${assignment} (ambil semua karakter setelah label Penugasan)`);
 | 
			
		||||
                        const assignmentMatch = line.match(/penugasan\s*:\s*(.+)/i);
 | 
			
		||||
                        if (assignmentMatch && assignmentMatch[1]) {
 | 
			
		||||
                            assignment = assignmentMatch[1].trim();
 | 
			
		||||
                            console.log(`Found assignment: ${assignment}`);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if (line.toUpperCase().includes('JAKARTA') && line.toUpperCase().includes('BARAT')) {
 | 
			
		||||
                        assignment = 'JAKARTA BARAT';
 | 
			
		||||
                        console.log(`Found assignment: ${assignment} from Jakarta Barat line`);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    for (const pattern of assignmentPatterns) {
 | 
			
		||||
                        const match = line.match(pattern);
 | 
			
		||||
                        if (match && match[1]) {
 | 
			
		||||
                            assignment = match[1].trim();
 | 
			
		||||
                            console.log(`Found assignment: ${assignment} using pattern: ${pattern}`);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (assignment) break;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Assignment detection result:', assignment);
 | 
			
		||||
 | 
			
		||||
                // Enhanced time patterns
 | 
			
		||||
                const timePatterns = [
 | 
			
		||||
                    /(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/gi, // 2025-08-02 12:35:34 (highest priority)
 | 
			
		||||
                    /(\d{1,2}\s+\w{3}\s+\d{4},\s*\d{1,2}:\d{2}:\d{2})/gi, // 04 Aug 2025, 08:13:51
 | 
			
		||||
                    /(\d{1,2}\s+\w{3}\s+\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04 Aug 2025 08:13:51
 | 
			
		||||
                    /(\d{1,2}\/\d{1,2}\/\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04/08/2025 08:13:51
 | 
			
		||||
                    /(\d{1,2}-\d{1,2}-\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04-08-2025 08:13:51
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                const convertDateFormat = (dateString) => {
 | 
			
		||||
                    const monthMap = {
 | 
			
		||||
                        'jan': '01', 'january': '01', 'januari': '01',
 | 
			
		||||
                        'feb': '02', 'february': '02', 'februari': '02',
 | 
			
		||||
                        'mar': '03', 'march': '03', 'maret': '03',
 | 
			
		||||
                        'apr': '04', 'april': '04', 'april': '04',
 | 
			
		||||
                        'may': '05', 'may': '05', 'mei': '05',
 | 
			
		||||
                        'jun': '06', 'june': '06', 'juni': '06',
 | 
			
		||||
                        'jul': '07', 'july': '07', 'juli': '07',
 | 
			
		||||
                        'aug': '08', 'august': '08', 'agustus': '08',
 | 
			
		||||
                        'sep': '09', 'september': '09', 'september': '09',
 | 
			
		||||
                        'oct': '10', 'october': '10', 'oktober': '10',
 | 
			
		||||
                        'nov': '11', 'november': '11', 'november': '11',
 | 
			
		||||
                        'dec': '12', 'december': '12', 'desember': '12'
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    const match = dateString.match(/(\d{1,2})\s+(\w{3,})\s+(\d{4}),?\s*(\d{1,2}:\d{2}:\d{2})/i);
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        const day = match[1].padStart(2, '0');
 | 
			
		||||
                        const monthName = match[2].toLowerCase();
 | 
			
		||||
                        const year = match[3];
 | 
			
		||||
                        const time = match[4];
 | 
			
		||||
                        
 | 
			
		||||
                        const month = monthMap[monthName];
 | 
			
		||||
                        if (month) {
 | 
			
		||||
                            return `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    return dateString;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                for (const line of lines) {
 | 
			
		||||
                    console.log(`Processing line for time: "${line}"`);
 | 
			
		||||
                    
 | 
			
		||||
                    // Entry time - look for "Masuk :" pattern
 | 
			
		||||
                    if (line.toLowerCase().includes('masuk') && line.includes(':')) {
 | 
			
		||||
                        console.log('Found masuk line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        const masukMatch = line.match(/masuk\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/i);
 | 
			
		||||
                        if (masukMatch && masukMatch[1]) {
 | 
			
		||||
                            entryTime = masukMatch[1].trim();
 | 
			
		||||
                            console.log(`Found entry time via masuk pattern: ${entryTime} (format: YYYY-MM-DD HH:MM:SS)`);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            for (const pattern of timePatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1]) {
 | 
			
		||||
                                    const rawTime = match[1].trim();
 | 
			
		||||
                                    entryTime = convertDateFormat(rawTime);
 | 
			
		||||
                                    console.log(`Found entry time: ${rawTime} -> converted to: ${entryTime}`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                        for (const pattern of timePatterns) {
 | 
			
		||||
                            const match = line.match(pattern);
 | 
			
		||||
                            if (match && match[1]) {
 | 
			
		||||
                                entryTime = match[1].trim();
 | 
			
		||||
                                console.log(`Found entry time: ${entryTime}`);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        if (!entryTime) {
 | 
			
		||||
                            const masukMatch = line.match(/masuk\s*:\s*(.+)/i);
 | 
			
		||||
                            if (masukMatch && masukMatch[1]) {
 | 
			
		||||
                                const rawTime = masukMatch[1].trim();
 | 
			
		||||
                                entryTime = convertDateFormat(rawTime);
 | 
			
		||||
                                console.log(`Found entry time via masuk pattern: ${rawTime} -> converted to: ${entryTime}`);
 | 
			
		||||
                            }
 | 
			
		||||
                        // Also try to extract after "Masuk : "
 | 
			
		||||
                        const masukMatch = line.match(/masuk\s*:\s*(.+)/i);
 | 
			
		||||
                        if (masukMatch && masukMatch[1] && !entryTime) {
 | 
			
		||||
                            entryTime = masukMatch[1].trim();
 | 
			
		||||
                            console.log(`Found entry time via masuk pattern: ${entryTime}`);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    // Exit time - look for "Keluar :" pattern  
 | 
			
		||||
                    if (line.toLowerCase().includes('keluar') && line.includes(':')) {
 | 
			
		||||
                        console.log('Found keluar line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        const keluarMatch = line.match(/keluar\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/i);
 | 
			
		||||
                        if (keluarMatch && keluarMatch[1]) {
 | 
			
		||||
                            exitTime = keluarMatch[1].trim();
 | 
			
		||||
                            console.log(`Found exit time via keluar pattern: ${exitTime} (format: YYYY-MM-DD HH:MM:SS)`);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            for (const pattern of timePatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1]) {
 | 
			
		||||
                                    const rawTime = match[1].trim();
 | 
			
		||||
                                    exitTime = convertDateFormat(rawTime);
 | 
			
		||||
                                    console.log(`Found exit time: ${rawTime} -> converted to: ${exitTime}`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                        for (const pattern of timePatterns) {
 | 
			
		||||
                            const match = line.match(pattern);
 | 
			
		||||
                            if (match && match[1]) {
 | 
			
		||||
                                exitTime = match[1].trim();
 | 
			
		||||
                                console.log(`Found exit time: ${exitTime}`);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        
 | 
			
		||||
                        if (!exitTime) {
 | 
			
		||||
                            const keluarMatch = line.match(/keluar\s*:\s*(.+)/i);
 | 
			
		||||
                            if (keluarMatch && keluarMatch[1]) {
 | 
			
		||||
                                const rawTime = keluarMatch[1].trim();
 | 
			
		||||
                                exitTime = convertDateFormat(rawTime);
 | 
			
		||||
                                console.log(`Found exit time via keluar pattern: ${rawTime} -> converted to: ${exitTime}`);
 | 
			
		||||
                            }
 | 
			
		||||
                        // Also try to extract after "Keluar : "
 | 
			
		||||
                        const keluarMatch = line.match(/keluar\s*:\s*(.+)/i);
 | 
			
		||||
                        if (keluarMatch && keluarMatch[1] && !exitTime) {
 | 
			
		||||
                            exitTime = keluarMatch[1].trim();
 | 
			
		||||
                            console.log(`Found exit time via keluar pattern: ${exitTime}`);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Time detection results:', { entryTime, exitTime });
 | 
			
		||||
 | 
			
		||||
                // Enhanced weight patterns - more specific for Indonesian receipts
 | 
			
		||||
                const weightPatterns = [
 | 
			
		||||
                    /berat\s+masuk\s*:\s*(\d+)\s*kg/gi, // Berat Masuk : 23280 kg
 | 
			
		||||
                    /berat\s+keluar\s*:\s*(\d+)\s*kg/gi, // Berat Keluar : 13540 kg
 | 
			
		||||
| 
						 | 
				
			
			@ -833,38 +841,41 @@
 | 
			
		|||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightIn = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight in via specific pattern: ${weightIn} (removed kg)`);
 | 
			
		||||
                                weightIn = numbers[1];
 | 
			
		||||
                                console.log(`Found weight in via specific pattern: ${weightIn} kg`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 1000) {
 | 
			
		||||
                                    weightIn = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight in via general pattern: ${weightIn} (removed kg)`);
 | 
			
		||||
                                    weightIn = match[1];
 | 
			
		||||
                                    console.log(`Found weight in via general pattern: ${weightIn} kg`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Berat Keluar - look for exact pattern "Berat Keluar : 13540 kg"
 | 
			
		||||
                    if (lowerLine.includes('berat keluar')) {
 | 
			
		||||
                        console.log('Found berat keluar line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        // Try specific pattern first
 | 
			
		||||
                        const specificMatch = line.match(/berat\s+keluar\s*:\s*(\d+)\s*kg/gi);
 | 
			
		||||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightOut = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight out via specific pattern: ${weightOut} (removed kg)`);
 | 
			
		||||
                                weightOut = numbers[1];
 | 
			
		||||
                                console.log(`Found weight out via specific pattern: ${weightOut} kg`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 1000) {
 | 
			
		||||
                                    weightOut = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight out via general pattern: ${weightOut} (removed kg)`);
 | 
			
		||||
                                    weightOut = match[1];
 | 
			
		||||
                                    console.log(`Found weight out via general pattern: ${weightOut} kg`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -880,16 +891,16 @@
 | 
			
		|||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightNett = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight nett via specific pattern: ${weightNett} (removed kg)`);
 | 
			
		||||
                                weightNett = numbers[1];
 | 
			
		||||
                                console.log(`Found weight nett via specific pattern: ${weightNett} kg`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 100) {
 | 
			
		||||
                                    weightNett = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight nett via general pattern: ${weightNett} (removed kg)`);
 | 
			
		||||
                                    weightNett = match[1];
 | 
			
		||||
                                    console.log(`Found weight nett via general pattern: ${weightNett} kg`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -897,24 +908,6 @@
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Validasi Berat Nett = Berat Masuk - Berat Keluar
 | 
			
		||||
                if (weightIn && weightOut && weightNett) {
 | 
			
		||||
                    const calculatedNett = parseInt(weightIn) - parseInt(weightOut);
 | 
			
		||||
                    const detectedNett = parseInt(weightNett);
 | 
			
		||||
                    
 | 
			
		||||
                    console.log(`Weight validation: ${weightIn} - ${weightOut} = ${calculatedNett}, detected: ${detectedNett}`);
 | 
			
		||||
                    
 | 
			
		||||
                    if (calculatedNett !== detectedNett) {
 | 
			
		||||
                        console.warn(`WARNING: Berat Nett tidak sesuai! Perhitungan: ${calculatedNett}, Terdeteksi: ${detectedNett}`);
 | 
			
		||||
                        // Gunakan hasil perhitungan yang benar
 | 
			
		||||
                        weightNett = calculatedNett.toString();
 | 
			
		||||
                        console.log(`Using calculated weight nett: ${weightNett}`);
 | 
			
		||||
                        
 | 
			
		||||
                        // Alert akan ditampilkan di frontend saat apply data
 | 
			
		||||
                        this.weightValidationError = `Berat Nett tidak sesuai! Perhitungan: ${calculatedNett} kg, Terdeteksi: ${detectedNett} kg. Menggunakan hasil perhitungan.`;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                console.log('Weight detection results:', { weightIn, weightOut, weightNett });
 | 
			
		||||
 | 
			
		||||
                console.log('Final Detected Data before assignment:', {
 | 
			
		||||
| 
						 | 
				
			
			@ -967,15 +960,9 @@
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            applyDetectedDataDirectly() {
 | 
			
		||||
                console.log(`=== APPLYING DATA DIRECTLY TO FORM ===`);
 | 
			
		||||
                console.log('=== APPLYING DATA DIRECTLY TO FORM ===');
 | 
			
		||||
                console.log('Data to apply:', this.detectedData);
 | 
			
		||||
                
 | 
			
		||||
                // Tampilkan alert jika ada error validasi berat nett
 | 
			
		||||
                if (this.weightValidationError) {
 | 
			
		||||
                    alert(this.weightValidationError);
 | 
			
		||||
                    this.weightValidationError = null; // Reset error
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Get input elements by ID directly
 | 
			
		||||
                const nomorStrukInput = document.getElementById('NomorStruk');
 | 
			
		||||
                const nomorPolisiInput = document.getElementById('NomorPolisi');
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
    <link rel="stylesheet" href="@Url.Content("~/driver/css/scanner.css")" asp-append-version="true" />
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
<div class="max-w-sm mx-auto bg-white min-h-screen">
 | 
			
		||||
<div class="w-full lg:max-w-sm mx-auto bg-white min-h-screen">
 | 
			
		||||
    <div class="bg-orange-500 text-white px-3 py-4 rounded-b-2xl relative pb-12">
 | 
			
		||||
        <div class="flex items-center justify-between">
 | 
			
		||||
            <a href="@Url.Action("Index", "Home")" class="p-1 hover:bg-white/10 rounded-full transition-colors">
 | 
			
		||||
| 
						 | 
				
			
			@ -26,25 +26,15 @@
 | 
			
		|||
                </div>
 | 
			
		||||
                <h2 class="text-xl font-bold text-orange-500">Scan Struk Otomatis</h2>
 | 
			
		||||
                <p class="text-sm text-gray-500 text-center">Arahkan kamera ke struk atau upload foto struk untuk membaca data secara otomatis.</p>
 | 
			
		||||
                
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
            <div id="ocr-processing" class="hidden bg-yellow-50 border border-yellow-200 rounded-lg p-3 mb-4">
 | 
			
		||||
            <div id="ocr-processing" class="hidden bg-yellow-50 border border-yellow-200 rounded-lg p-3">
 | 
			
		||||
                <div class="flex items-center">
 | 
			
		||||
                    <div class="loading-spinner-small mr-2"></div>
 | 
			
		||||
                    <span class="text-yellow-800 text-sm">Memproses teks dari struk...</span>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>  
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <div id="scan-success" class="hidden bg-green-50 border border-green-200 rounded-lg p-3 mb-4">
 | 
			
		||||
                <div class="flex items-center">
 | 
			
		||||
                    <i class="w-5 h-5 text-green-600 mr-2" data-lucide="check-circle"></i>
 | 
			
		||||
                    <span class="text-green-800 font-medium">Data struk berhasil diisi otomatis!</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <p class="text-green-700 text-sm mt-1">Scanning dihentikan. Periksa form di bawah dan lengkapi data jika diperlukan.</p>
 | 
			
		||||
                <p class="text-green-700 text-xs mt-1">💡 Untuk scan ulang, "Upload Foto Struk"</p>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <div class="scanner-container mb-4" style="height: 300px;">
 | 
			
		||||
                <div id="scanner-container" class="w-full h-full relative bg-gray-900 rounded-lg overflow-hidden">
 | 
			
		||||
| 
						 | 
				
			
			@ -58,10 +48,10 @@
 | 
			
		|||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="space-y-3 mb-4">
 | 
			
		||||
                @* <button id="start-scanner" type="button" class="w-full bg-orange-500 hover:bg-orange-600 text-white font-medium py-3 px-4 rounded-lg transition-colors btn-scanner">
 | 
			
		||||
                <button id="start-scanner" type="button" class="w-full bg-orange-500 hover:bg-orange-600 text-white font-medium py-3 px-4 rounded-lg transition-colors btn-scanner">
 | 
			
		||||
                    <i class="w-5 h-5 inline mr-2" data-lucide="camera"></i>
 | 
			
		||||
                    Mulai Scan Struk
 | 
			
		||||
                </button> *@
 | 
			
		||||
                </button>
 | 
			
		||||
                
 | 
			
		||||
                <button id="stop-scanner" type="button" class="w-full bg-gray-500 hover:bg-gray-600 text-white font-medium py-3 px-4 rounded-lg transition-colors btn-scanner hidden">
 | 
			
		||||
                    <i class="w-5 h-5 inline mr-2" data-lucide="camera-off"></i>
 | 
			
		||||
| 
						 | 
				
			
			@ -69,11 +59,11 @@
 | 
			
		|||
                </button>
 | 
			
		||||
 | 
			
		||||
               
 | 
			
		||||
                    @* <div class="flex items-center">
 | 
			
		||||
                    <div class="flex items-center">
 | 
			
		||||
                        <div class="flex-1 border-t border-gray-200"></div>
 | 
			
		||||
                        <span class="px-3 text-sm text-gray-500 bg-white">atau</span>
 | 
			
		||||
                        <div class="flex-1 border-t border-gray-200"></div>
 | 
			
		||||
                    </div> *@
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <label for="file-upload" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-medium py-3 px-4 rounded-lg transition-colors cursor-pointer flex items-center justify-center gap-2 upload-label">
 | 
			
		||||
                        <i class="w-5 h-5" data-lucide="upload"></i>
 | 
			
		||||
                        Upload Foto Struk
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +109,17 @@
 | 
			
		|||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
              
 | 
			
		||||
 | 
			
		||||
                <div id="scan-success" class="hidden bg-green-50 border border-green-200 rounded-lg p-3">
 | 
			
		||||
                    <div class="flex items-center">
 | 
			
		||||
                        <i class="w-5 h-5 text-green-600 mr-2" data-lucide="check-circle"></i>
 | 
			
		||||
                        <span class="text-green-800 font-medium">Data struk berhasil diisi otomatis!</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <p class="text-green-700 text-sm mt-1">Scanning dihentikan. Periksa form di bawah dan lengkapi data jika diperlukan.</p>
 | 
			
		||||
                    <p class="text-green-700 text-xs mt-1">💡 Untuk scan ulang, klik "Mulai Scan Struk" atau "Upload Foto Struk"</p>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -252,7 +253,7 @@
 | 
			
		|||
</div>
 | 
			
		||||
 | 
			
		||||
<register-block dynamic-section="scripts" key="jsSubmitStruk">
 | 
			
		||||
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@4.1.1/dist/tesseract.min.js"></script>
 | 
			
		||||
<script src="https://cdn.jsdelivr.net/npm/tesseract.js@5.1.1/dist/tesseract.min.js"></script>
 | 
			
		||||
<script>
 | 
			
		||||
    document.addEventListener('DOMContentLoaded', function() {
 | 
			
		||||
        const nomorStrukInput = document.getElementById('NomorStruk');
 | 
			
		||||
| 
						 | 
				
			
			@ -666,70 +667,28 @@
 | 
			
		|||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (!truckNumber) {
 | 
			
		||||
                    console.log('No truck number found in context lines, trying all lines...');
 | 
			
		||||
                    for (const line of lines) {
 | 
			
		||||
                        console.log(`Scanning line for truck pattern: "${line}"`);
 | 
			
		||||
                        
 | 
			
		||||
                        if (line.match(/[A-Z]\s*\d+\s*[A-Z]{2,3}/i)) {
 | 
			
		||||
                            console.log('Potential truck pattern found:', line);
 | 
			
		||||
                            
 | 
			
		||||
                            for (const pattern of truckPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match) {
 | 
			
		||||
                                    let foundTruck = '';
 | 
			
		||||
                                    
 | 
			
		||||
                                    if (match.length === 4 && match[1] && match[2] && match[3]) {
 | 
			
		||||
                                        foundTruck = `${match[1]} ${match[2]} ${match[3]}`;
 | 
			
		||||
                                    } else if (match[1]) {
 | 
			
		||||
                                        foundTruck = match[1].trim();
 | 
			
		||||
                                    }
 | 
			
		||||
                                    
 | 
			
		||||
                                    if (foundTruck) {
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/([A-Z])(\d+)(\s+[A-Z]{2,3})/g, '$1 $2$3');
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/([A-Z]{1,2})(\d{3,4})([A-Z]{2,3})/g, '$1 $2 $3');
 | 
			
		||||
                                        foundTruck = foundTruck.replace(/\s+/g, ' ').trim();
 | 
			
		||||
                                        
 | 
			
		||||
                                        if (foundTruck.match(/^[A-Z]{1,2}\s+\d{3,4}\s+[A-Z]{2,3}$/)) {
 | 
			
		||||
                                            truckNumber = foundTruck;
 | 
			
		||||
                                            console.log(`Found truck number: "${truckNumber}" using general pattern`);
 | 
			
		||||
                                for (const line of lines) {
 | 
			
		||||
                                    if (line.toLowerCase().includes('no truk')) {
 | 
			
		||||
                                        const match = line.match(/no\s*truk\s*:?\s*(.+)/i);
 | 
			
		||||
                                        if (match && match[1]) {
 | 
			
		||||
                                            truckNumber = match[1].trim();
 | 
			
		||||
                                            console.log(`Found truck number: ${truckNumber} (ambil semua karakter setelah label No Truk)`);
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                if (!truckNumber) {
 | 
			
		||||
                                    for (const line of lines) {
 | 
			
		||||
                                        const match = line.match(/\bB\s*\d{3,5}\s*[A-Z]{2,4}\b/i);
 | 
			
		||||
                                        if (match && match[0]) {
 | 
			
		||||
                                            truckNumber = match[0].trim();
 | 
			
		||||
                                            console.log(`Fallback truck number: ${truckNumber}`);
 | 
			
		||||
                                            break;
 | 
			
		||||
                                        }
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            if (truckNumber) break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if (!truckNumber) {
 | 
			
		||||
                    console.log('Still no truck number, trying loose patterns...');
 | 
			
		||||
                    for (const line of lines) {
 | 
			
		||||
                        const looseMatch = line.match(/([A-Z]{1,2})\s*(\d{3,4})\s*([A-Z]{2,3})/i);
 | 
			
		||||
                        if (looseMatch && looseMatch[1] && looseMatch[2] && looseMatch[3]) {
 | 
			
		||||
                            const candidate = `${looseMatch[1].toUpperCase()} ${looseMatch[2]} ${looseMatch[3].toUpperCase()}`;
 | 
			
		||||
                            console.log(`Found potential truck number with loose pattern: "${candidate}"`);
 | 
			
		||||
                            
 | 
			
		||||
                            if (looseMatch[1].length <= 2 && 
 | 
			
		||||
                                looseMatch[2].length >= 3 && looseMatch[2].length <= 4 &&
 | 
			
		||||
                                looseMatch[3].length >= 2 && looseMatch[3].length <= 3) {
 | 
			
		||||
                                truckNumber = candidate;
 | 
			
		||||
                                console.log(`Accepted truck number: "${truckNumber}"`);
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Truck detection results:', { truckNumber });
 | 
			
		||||
                
 | 
			
		||||
                console.log('Truck detection result:', truckNumber);
 | 
			
		||||
 | 
			
		||||
                const assignmentPatterns = [
 | 
			
		||||
                    /(?:penugasan|assignment)[\s.:]*([A-Z\s]+?)(?:\n|$)/gi,
 | 
			
		||||
                    /(JAKARTA\s+\w+)/gi, // Specific pattern for Jakarta areas
 | 
			
		||||
                    /(BANDUNG|SURABAYA|MEDAN|SEMARANG|PALEMBANG|MAKASSAR)[\s\w]*/gi,
 | 
			
		||||
                ];
 | 
			
		||||
                console.log('Truck detection result:', truckNumber);
 | 
			
		||||
 | 
			
		||||
                for (const line of lines) {
 | 
			
		||||
                    console.log(`Processing line for assignment: "${line}"`);
 | 
			
		||||
| 
						 | 
				
			
			@ -737,168 +696,121 @@
 | 
			
		|||
                    if (line.toLowerCase().includes('penugasan')) {
 | 
			
		||||
                        console.log('Found penugasan line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        const assignmentMatch = line.match(/penugasan\s*:\s*(.+)/i);
 | 
			
		||||
                        if (assignmentMatch && assignmentMatch[1]) {
 | 
			
		||||
                            assignment = assignmentMatch[1].trim();
 | 
			
		||||
                            console.log(`Found assignment: ${assignment}`);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    if (line.toUpperCase().includes('JAKARTA') && line.toUpperCase().includes('BARAT')) {
 | 
			
		||||
                        assignment = 'JAKARTA BARAT';
 | 
			
		||||
                        console.log(`Found assignment: ${assignment} from Jakarta Barat line`);
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    for (const pattern of assignmentPatterns) {
 | 
			
		||||
                        const match = line.match(pattern);
 | 
			
		||||
                        const match = line.match(/penugasan\s*:?\s*(.+)/i);
 | 
			
		||||
                        if (match && match[1]) {
 | 
			
		||||
                            assignment = match[1].trim();
 | 
			
		||||
                            console.log(`Found assignment: ${assignment} using pattern: ${pattern}`);
 | 
			
		||||
                            console.log(`Found assignment: ${assignment} (ambil semua karakter setelah label Penugasan)`);
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    if (assignment) break;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Assignment detection result:', assignment);
 | 
			
		||||
 | 
			
		||||
                // Enhanced time patterns
 | 
			
		||||
                const timePatterns = [
 | 
			
		||||
                    /(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/gi, // 2025-08-02 12:35:34 (highest priority)
 | 
			
		||||
                    /(\d{1,2}\s+\w{3}\s+\d{4},\s*\d{1,2}:\d{2}:\d{2})/gi, // 04 Aug 2025, 08:13:51
 | 
			
		||||
                    /(\d{1,2}\s+\w{3}\s+\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04 Aug 2025 08:13:51
 | 
			
		||||
                    /(\d{1,2}\/\d{1,2}\/\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04/08/2025 08:13:51
 | 
			
		||||
                    /(\d{1,2}-\d{1,2}-\d{4}\s+\d{1,2}:\d{2}:\d{2})/gi, // 04-08-2025 08:13:51
 | 
			
		||||
                    /(\d{4}-\d{1,2}-\d{1,2},\s*\d{1,2}:\d{2}:\d{2})/gi, // 2025-08-04, 08:13:51
 | 
			
		||||
                    /(\d{4}\/\d{1,2}\/\d{1,2}\s+\d{1,2}:\d{2}:\d{2})/gi, // 2025/08/04 08:13:51
 | 
			
		||||
                ];
 | 
			
		||||
 | 
			
		||||
                const convertToStandardFormat = (dateTimeString) => {
 | 
			
		||||
                    if (!dateTimeString) return '';
 | 
			
		||||
                    
 | 
			
		||||
                    console.log('Converting date string:', dateTimeString);
 | 
			
		||||
                    
 | 
			
		||||
                    const monthNamePattern = /(\d{1,2})\s+(\w{3})\s+(\d{4})[,\s]+(\d{1,2}:\d{2}:\d{2})/i;
 | 
			
		||||
                    const monthNameMatch = dateTimeString.match(monthNamePattern);
 | 
			
		||||
                    if (monthNameMatch) {
 | 
			
		||||
                        const day = monthNameMatch[1].padStart(2, '0');
 | 
			
		||||
                        const monthName = monthNameMatch[2].toLowerCase();
 | 
			
		||||
                        const year = monthNameMatch[3];
 | 
			
		||||
                        const time = monthNameMatch[4];
 | 
			
		||||
                const convertDateFormat = (dateString) => {
 | 
			
		||||
                    const monthMap = {
 | 
			
		||||
                        'jan': '01', 'january': '01', 'januari': '01',
 | 
			
		||||
                        'feb': '02', 'february': '02', 'februari': '02',
 | 
			
		||||
                        'mar': '03', 'march': '03', 'maret': '03',
 | 
			
		||||
                        'apr': '04', 'april': '04', 'april': '04',
 | 
			
		||||
                        'may': '05', 'may': '05', 'mei': '05',
 | 
			
		||||
                        'jun': '06', 'june': '06', 'juni': '06',
 | 
			
		||||
                        'jul': '07', 'july': '07', 'juli': '07',
 | 
			
		||||
                        'aug': '08', 'august': '08', 'agustus': '08',
 | 
			
		||||
                        'sep': '09', 'september': '09', 'september': '09',
 | 
			
		||||
                        'oct': '10', 'october': '10', 'oktober': '10',
 | 
			
		||||
                        'nov': '11', 'november': '11', 'november': '11',
 | 
			
		||||
                        'dec': '12', 'december': '12', 'desember': '12'
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    const match = dateString.match(/(\d{1,2})\s+(\w{3,})\s+(\d{4}),?\s*(\d{1,2}:\d{2}:\d{2})/i);
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        const day = match[1].padStart(2, '0');
 | 
			
		||||
                        const monthName = match[2].toLowerCase();
 | 
			
		||||
                        const year = match[3];
 | 
			
		||||
                        const time = match[4];
 | 
			
		||||
                        
 | 
			
		||||
                        const monthMap = {
 | 
			
		||||
                            'jan': '01', 'feb': '02', 'mar': '03', 'apr': '04',
 | 
			
		||||
                            'may': '05', 'jun': '06', 'jul': '07', 'aug': '08',
 | 
			
		||||
                            'sep': '09', 'oct': '10', 'nov': '11', 'dec': '12'
 | 
			
		||||
                        };
 | 
			
		||||
                        
 | 
			
		||||
                        const month = monthMap[monthName] || '01';
 | 
			
		||||
                        const converted = `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        console.log('Converted month name format:', converted);
 | 
			
		||||
                        return converted;
 | 
			
		||||
                        const month = monthMap[monthName];
 | 
			
		||||
                        if (month) {
 | 
			
		||||
                            return `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const ddmmyyyyPattern = /(\d{1,2})\/(\d{1,2})\/(\d{4})\s+(\d{1,2}:\d{2}:\d{2})/;
 | 
			
		||||
                    const ddmmyyyyMatch = dateTimeString.match(ddmmyyyyPattern);
 | 
			
		||||
                    if (ddmmyyyyMatch) {
 | 
			
		||||
                        const day = ddmmyyyyMatch[1].padStart(2, '0');
 | 
			
		||||
                        const month = ddmmyyyyMatch[2].padStart(2, '0');
 | 
			
		||||
                        const year = ddmmyyyyMatch[3];
 | 
			
		||||
                        const time = ddmmyyyyMatch[4];
 | 
			
		||||
                        const converted = `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        console.log('Converted DD/MM/YYYY format:', converted);
 | 
			
		||||
                        return converted;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const ddmmyyyyDashPattern = /(\d{1,2})-(\d{1,2})-(\d{4})\s+(\d{1,2}:\d{2}:\d{2})/;
 | 
			
		||||
                    const ddmmyyyyDashMatch = dateTimeString.match(ddmmyyyyDashPattern);
 | 
			
		||||
                    if (ddmmyyyyDashMatch) {
 | 
			
		||||
                        const day = ddmmyyyyDashMatch[1].padStart(2, '0');
 | 
			
		||||
                        const month = ddmmyyyyDashMatch[2].padStart(2, '0');
 | 
			
		||||
                        const year = ddmmyyyyDashMatch[3];
 | 
			
		||||
                        const time = ddmmyyyyDashMatch[4];
 | 
			
		||||
                        const converted = `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        console.log('Converted DD-MM-YYYY format:', converted);
 | 
			
		||||
                        return converted;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const yyyymmddSlashPattern = /(\d{4})\/(\d{1,2})\/(\d{1,2})\s+(\d{1,2}:\d{2}:\d{2})/;
 | 
			
		||||
                    const yyyymmddSlashMatch = dateTimeString.match(yyyymmddSlashPattern);
 | 
			
		||||
                    if (yyyymmddSlashMatch) {
 | 
			
		||||
                        const year = yyyymmddSlashMatch[1];
 | 
			
		||||
                        const month = yyyymmddSlashMatch[2].padStart(2, '0');
 | 
			
		||||
                        const day = yyyymmddSlashMatch[3].padStart(2, '0');
 | 
			
		||||
                        const time = yyyymmddSlashMatch[4];
 | 
			
		||||
                        const converted = `${year}-${month}-${day}, ${time}`;
 | 
			
		||||
                        console.log('Converted YYYY/MM/DD format:', converted);
 | 
			
		||||
                        return converted;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    const standardPattern = /(\d{4}-\d{1,2}-\d{1,2}),?\s*(\d{1,2}:\d{2}:\d{2})/;
 | 
			
		||||
                    const standardMatch = dateTimeString.match(standardPattern);
 | 
			
		||||
                    if (standardMatch) {
 | 
			
		||||
                        const datePart = standardMatch[1];
 | 
			
		||||
                        const timePart = standardMatch[2];
 | 
			
		||||
                        
 | 
			
		||||
                        const [year, month, day] = datePart.split('-');
 | 
			
		||||
                        const paddedMonth = month.padStart(2, '0');
 | 
			
		||||
                        const paddedDay = day.padStart(2, '0');
 | 
			
		||||
                        
 | 
			
		||||
                        const converted = `${year}-${paddedMonth}-${paddedDay}, ${timePart}`;
 | 
			
		||||
                        console.log('Standardized YYYY-MM-DD format:', converted);
 | 
			
		||||
                        return converted;
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    console.log('No date pattern matched, returning original:', dateTimeString);
 | 
			
		||||
                    return dateTimeString;
 | 
			
		||||
                    return dateString;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                for (const line of lines) {
 | 
			
		||||
                    console.log(`Processing line for time: "${line}"`);
 | 
			
		||||
                    
 | 
			
		||||
                    // Entry time - look for "Masuk :" pattern
 | 
			
		||||
                    if (line.toLowerCase().includes('masuk') && line.includes(':')) {
 | 
			
		||||
                        console.log('Found masuk line:', line);
 | 
			
		||||
                        for (const pattern of timePatterns) {
 | 
			
		||||
                            const match = line.match(pattern);
 | 
			
		||||
                            if (match && match[1]) {
 | 
			
		||||
                                entryTime = convertToStandardFormat(match[1].trim());
 | 
			
		||||
                                console.log(`Found entry time: ${entryTime}`);
 | 
			
		||||
                                break;
 | 
			
		||||
                        
 | 
			
		||||
                        const masukMatch = line.match(/masuk\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/i);
 | 
			
		||||
                        if (masukMatch && masukMatch[1]) {
 | 
			
		||||
                            entryTime = masukMatch[1].trim();
 | 
			
		||||
                            console.log(`Found entry time via masuk pattern: ${entryTime} (format: YYYY-MM-DD HH:MM:SS)`);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            for (const pattern of timePatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1]) {
 | 
			
		||||
                                    const rawTime = match[1].trim();
 | 
			
		||||
                                    entryTime = convertDateFormat(rawTime);
 | 
			
		||||
                                    console.log(`Found entry time: ${rawTime} -> converted to: ${entryTime}`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        // Also try to extract after "Masuk : "
 | 
			
		||||
                        const masukMatch = line.match(/masuk\s*:\s*(.+)/i);
 | 
			
		||||
                        if (masukMatch && masukMatch[1] && !entryTime) {
 | 
			
		||||
                            entryTime = convertToStandardFormat(masukMatch[1].trim());
 | 
			
		||||
                            console.log(`Found entry time via masuk pattern: ${entryTime}`);
 | 
			
		||||
                        
 | 
			
		||||
                        if (!entryTime) {
 | 
			
		||||
                            const masukMatch = line.match(/masuk\s*:\s*(.+)/i);
 | 
			
		||||
                            if (masukMatch && masukMatch[1]) {
 | 
			
		||||
                                const rawTime = masukMatch[1].trim();
 | 
			
		||||
                                entryTime = convertDateFormat(rawTime);
 | 
			
		||||
                                console.log(`Found entry time via masuk pattern: ${rawTime} -> converted to: ${entryTime}`);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    // Exit time - look for "Keluar :" pattern  
 | 
			
		||||
                    if (line.toLowerCase().includes('keluar') && line.includes(':')) {
 | 
			
		||||
                        console.log('Found keluar line:', line);
 | 
			
		||||
                        for (const pattern of timePatterns) {
 | 
			
		||||
                            const match = line.match(pattern);
 | 
			
		||||
                            if (match && match[1]) {
 | 
			
		||||
                                exitTime = convertToStandardFormat(match[1].trim());
 | 
			
		||||
                                console.log(`Found exit time: ${exitTime}`);
 | 
			
		||||
                                break;
 | 
			
		||||
                        
 | 
			
		||||
                        const keluarMatch = line.match(/keluar\s*:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/i);
 | 
			
		||||
                        if (keluarMatch && keluarMatch[1]) {
 | 
			
		||||
                            exitTime = keluarMatch[1].trim();
 | 
			
		||||
                            console.log(`Found exit time via keluar pattern: ${exitTime} (format: YYYY-MM-DD HH:MM:SS)`);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            for (const pattern of timePatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1]) {
 | 
			
		||||
                                    const rawTime = match[1].trim();
 | 
			
		||||
                                    exitTime = convertDateFormat(rawTime);
 | 
			
		||||
                                    console.log(`Found exit time: ${rawTime} -> converted to: ${exitTime}`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        // Also try to extract after "Keluar : "
 | 
			
		||||
                        const keluarMatch = line.match(/keluar\s*:\s*(.+)/i);
 | 
			
		||||
                        if (keluarMatch && keluarMatch[1] && !exitTime) {
 | 
			
		||||
                            exitTime = convertToStandardFormat(keluarMatch[1].trim());
 | 
			
		||||
                            console.log(`Found exit time via keluar pattern: ${exitTime}`);
 | 
			
		||||
                        
 | 
			
		||||
                        if (!exitTime) {
 | 
			
		||||
                            const keluarMatch = line.match(/keluar\s*:\s*(.+)/i);
 | 
			
		||||
                            if (keluarMatch && keluarMatch[1]) {
 | 
			
		||||
                                const rawTime = keluarMatch[1].trim();
 | 
			
		||||
                                exitTime = convertDateFormat(rawTime);
 | 
			
		||||
                                console.log(`Found exit time via keluar pattern: ${rawTime} -> converted to: ${exitTime}`);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                console.log('Time detection results:', { entryTime, exitTime });
 | 
			
		||||
 | 
			
		||||
                // Enhanced weight patterns - more specific for Indonesian receipts
 | 
			
		||||
                const weightPatterns = [
 | 
			
		||||
                    /berat\s+masuk\s*:\s*(\d+)\s*kg/gi, // Berat Masuk : 23280 kg
 | 
			
		||||
                    /berat\s+keluar\s*:\s*(\d+)\s*kg/gi, // Berat Keluar : 13540 kg
 | 
			
		||||
| 
						 | 
				
			
			@ -921,41 +833,38 @@
 | 
			
		|||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightIn = numbers[1];
 | 
			
		||||
                                console.log(`Found weight in via specific pattern: ${weightIn} kg`);
 | 
			
		||||
                                weightIn = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight in via specific pattern: ${weightIn} (removed kg)`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 1000) {
 | 
			
		||||
                                    weightIn = match[1];
 | 
			
		||||
                                    console.log(`Found weight in via general pattern: ${weightIn} kg`);
 | 
			
		||||
                                    weightIn = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight in via general pattern: ${weightIn} (removed kg)`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Berat Keluar - look for exact pattern "Berat Keluar : 13540 kg"
 | 
			
		||||
                    if (lowerLine.includes('berat keluar')) {
 | 
			
		||||
                        console.log('Found berat keluar line:', line);
 | 
			
		||||
                        
 | 
			
		||||
                        // Try specific pattern first
 | 
			
		||||
                        const specificMatch = line.match(/berat\s+keluar\s*:\s*(\d+)\s*kg/gi);
 | 
			
		||||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightOut = numbers[1];
 | 
			
		||||
                                console.log(`Found weight out via specific pattern: ${weightOut} kg`);
 | 
			
		||||
                                weightOut = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight out via specific pattern: ${weightOut} (removed kg)`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 1000) {
 | 
			
		||||
                                    weightOut = match[1];
 | 
			
		||||
                                    console.log(`Found weight out via general pattern: ${weightOut} kg`);
 | 
			
		||||
                                    weightOut = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight out via general pattern: ${weightOut} (removed kg)`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -971,16 +880,16 @@
 | 
			
		|||
                        if (specificMatch) {
 | 
			
		||||
                            const numbers = specificMatch[0].match(/(\d+)/);
 | 
			
		||||
                            if (numbers && numbers[1]) {
 | 
			
		||||
                                weightNett = numbers[1];
 | 
			
		||||
                                console.log(`Found weight nett via specific pattern: ${weightNett} kg`);
 | 
			
		||||
                                weightNett = numbers[1]; // Hanya angka, tanpa "kg"
 | 
			
		||||
                                console.log(`Found weight nett via specific pattern: ${weightNett} (removed kg)`);
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            // Try general patterns
 | 
			
		||||
                            for (const pattern of weightPatterns) {
 | 
			
		||||
                                const match = line.match(pattern);
 | 
			
		||||
                                if (match && match[1] && parseInt(match[1]) > 100) {
 | 
			
		||||
                                    weightNett = match[1];
 | 
			
		||||
                                    console.log(`Found weight nett via general pattern: ${weightNett} kg`);
 | 
			
		||||
                                    weightNett = match[1]; // Hanya angka
 | 
			
		||||
                                    console.log(`Found weight nett via general pattern: ${weightNett} (removed kg)`);
 | 
			
		||||
                                    break;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -988,6 +897,24 @@
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Validasi Berat Nett = Berat Masuk - Berat Keluar
 | 
			
		||||
                if (weightIn && weightOut && weightNett) {
 | 
			
		||||
                    const calculatedNett = parseInt(weightIn) - parseInt(weightOut);
 | 
			
		||||
                    const detectedNett = parseInt(weightNett);
 | 
			
		||||
                    
 | 
			
		||||
                    console.log(`Weight validation: ${weightIn} - ${weightOut} = ${calculatedNett}, detected: ${detectedNett}`);
 | 
			
		||||
                    
 | 
			
		||||
                    if (calculatedNett !== detectedNett) {
 | 
			
		||||
                        console.warn(`WARNING: Berat Nett tidak sesuai! Perhitungan: ${calculatedNett}, Terdeteksi: ${detectedNett}`);
 | 
			
		||||
                        // Gunakan hasil perhitungan yang benar
 | 
			
		||||
                        weightNett = calculatedNett.toString();
 | 
			
		||||
                        console.log(`Using calculated weight nett: ${weightNett}`);
 | 
			
		||||
                        
 | 
			
		||||
                        // Alert akan ditampilkan di frontend saat apply data
 | 
			
		||||
                        this.weightValidationError = `Berat Nett tidak sesuai! Perhitungan: ${calculatedNett} kg, Terdeteksi: ${detectedNett} kg. Menggunakan hasil perhitungan.`;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                console.log('Weight detection results:', { weightIn, weightOut, weightNett });
 | 
			
		||||
 | 
			
		||||
                console.log('Final Detected Data before assignment:', {
 | 
			
		||||
| 
						 | 
				
			
			@ -1040,9 +967,15 @@
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            applyDetectedDataDirectly() {
 | 
			
		||||
                console.log('=== APPLYING DATA DIRECTLY TO FORM ===');
 | 
			
		||||
                console.log(`=== APPLYING DATA DIRECTLY TO FORM ===`);
 | 
			
		||||
                console.log('Data to apply:', this.detectedData);
 | 
			
		||||
                
 | 
			
		||||
                // Tampilkan alert jika ada error validasi berat nett
 | 
			
		||||
                if (this.weightValidationError) {
 | 
			
		||||
                    alert(this.weightValidationError);
 | 
			
		||||
                    this.weightValidationError = null; // Reset error
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                // Get input elements by ID directly
 | 
			
		||||
                const nomorStrukInput = document.getElementById('NomorStruk');
 | 
			
		||||
                const nomorPolisiInput = document.getElementById('NomorPolisi');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue