update: scanner submit struk
parent
b5056edfa4
commit
86647ef04e
|
@ -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">
|
||||
|
@ -26,16 +26,26 @@
|
|||
</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">
|
||||
<div id="ocr-processing" class="hidden bg-yellow-50 border border-yellow-200 rounded-lg p-3 mb-4">
|
||||
<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">
|
||||
<div id="loading-scanner" class="absolute inset-0 bg-gray-900 flex items-center justify-center z-10">
|
||||
|
@ -48,10 +58,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>
|
||||
|
@ -59,11 +69,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
|
||||
|
@ -110,17 +120,6 @@
|
|||
</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>
|
||||
|
||||
|
@ -253,7 +252,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');
|
||||
|
@ -667,150 +666,239 @@
|
|||
}
|
||||
|
||||
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)`);
|
||||
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}`);
|
||||
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) 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
|
||||
/(\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 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 convertToStandardFormat = (dateTimeString) => {
|
||||
if (!dateTimeString) return '';
|
||||
|
||||
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];
|
||||
console.log('Converting date string:', dateTimeString);
|
||||
|
||||
const month = monthMap[monthName];
|
||||
if (month) {
|
||||
return `${year}-${month}-${day}, ${time}`;
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
|
||||
return dateString;
|
||||
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;
|
||||
};
|
||||
|
||||
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 = convertToStandardFormat(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 = convertToStandardFormat(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 = convertToStandardFormat(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 = convertToStandardFormat(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 +921,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 +971,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 +988,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 +1040,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">
|
||||
|
@ -180,7 +180,7 @@
|
|||
</div>
|
||||
|
||||
<!-- Waktu Masuk dan Keluar -->
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="grid grid-cols-1 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="04 Aug 2025, 08:13:51"
|
||||
placeholder="2025-08-04, 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="04 Aug 2025, 14:35:10"
|
||||
placeholder="2025-08-04, 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@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');
|
||||
|
@ -577,36 +577,35 @@
|
|||
let weightNett = '';
|
||||
|
||||
const receiptPatterns = [
|
||||
/(\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,
|
||||
/(\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,
|
||||
];
|
||||
|
||||
for (const line of lines) {
|
||||
console.log(`Processing line for receipt: "${line}"`);
|
||||
|
||||
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,})/);
|
||||
const monthUnderscoreMatch = line.match(/(\d{2})_(\d{6,})/);
|
||||
if (monthUnderscoreMatch && monthUnderscoreMatch[2]) {
|
||||
receiptNumber = monthUnderscoreMatch[2]; // Take the number after underscore
|
||||
console.log(`Found receipt number: ${receiptNumber} using month-underscore pattern`);
|
||||
receiptNumber = monthUnderscoreMatch[2];
|
||||
console.log(`Found receipt number: ${receiptNumber} using month-underscore pattern (removed prefix: ${monthUnderscoreMatch[1]}_)`);
|
||||
break;
|
||||
}
|
||||
|
||||
// Other patterns
|
||||
for (const pattern of receiptPatterns.slice(2)) { // Skip first 2 patterns already handled above
|
||||
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)) {
|
||||
const matches = [...line.matchAll(pattern)];
|
||||
for (const match of matches) {
|
||||
if (match[1] && match[1].length >= 7) {
|
||||
if (match[1] && match[1].length >= 6) {
|
||||
receiptNumber = match[1];
|
||||
console.log(`Found receipt number: ${receiptNumber} using pattern: ${pattern}`);
|
||||
console.log(`Found receipt number: ${receiptNumber} using context pattern: ${pattern}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -668,157 +667,150 @@
|
|||
}
|
||||
|
||||
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,
|
||||
];
|
||||
|
||||
for (const line of lines) {
|
||||
console.log(`Processing line for assignment: "${line}"`);
|
||||
|
||||
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
|
||||
];
|
||||
|
||||
for (const line of lines) {
|
||||
console.log(`Processing line for time: "${line}"`);
|
||||
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'
|
||||
};
|
||||
|
||||
// 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 = match[1].trim();
|
||||
console.log(`Found entry time: ${entryTime}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 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}`);
|
||||
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}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = match[1].trim();
|
||||
console.log(`Found exit time: ${exitTime}`);
|
||||
break;
|
||||
return dateString;
|
||||
};
|
||||
|
||||
for (const line of lines) {
|
||||
console.log(`Processing line for time: "${line}"`);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Also try to extract after "Keluar : "
|
||||
const keluarMatch = line.match(/keluar\s*:\s*(.+)/i);
|
||||
if (keluarMatch && keluarMatch[1] && !exitTime) {
|
||||
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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}`);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -841,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;
|
||||
}
|
||||
}
|
||||
|
@ -891,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;
|
||||
}
|
||||
}
|
||||
|
@ -908,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:', {
|
||||
|
@ -960,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