DONE: use acs mykad reader, fix trailing issue, duplicated line

This commit is contained in:
ISMAIL MASSERAN
2026-09-01 14:08:44 +08:00
parent 6e1ce76c50
commit 9fbc77aba8
10 changed files with 375 additions and 294 deletions
+1 -1
View File
@@ -46,5 +46,5 @@ AWS_BUCKET=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
MYKAD_READER_PORT=8085 MYKAD_READER_PORT=17321
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
+5 -5
View File
@@ -3,14 +3,14 @@ APP_ENV=staging
APP_VERSION=v2.2-staging APP_VERSION=v2.2-staging
APP_KEY=base64:O1XZDqK4H6+3GdrODgCaLr2l+OoWvgVhYr0GJ1KizW8= APP_KEY=base64:O1XZDqK4H6+3GdrODgCaLr2l+OoWvgVhYr0GJ1KizW8=
APP_DEBUG=true APP_DEBUG=true
APP_URL=http://172.16.6.200:8091 APP_URL=https://staging.erahn.com.my
HTTP_PORT=8091 HTTP_PORT=8091
MYSQL_PUBLISH_PORT=3309 MYSQL_PUBLISH_PORT=3309
API_URL=http://172.16.6.200:8090 API_URL=https://api-staging.erahn.com.my
API_URL_KOOP=http://172.16.6.200:8090 API_URL_KOOP=https://api-staging.erahn.com.my
API_URL_PKB=http://172.16.6.200:8090 API_URL_PKB=https://api-staging.erahn.com.my
API_ARRAHNBID=http://lelong.test/api/ API_ARRAHNBID=http://lelong.test/api/
LOG_CHANNEL=stack LOG_CHANNEL=stack
@@ -54,5 +54,5 @@ AWS_BUCKET=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
MYKAD_READER_PORT=8085 MYKAD_READER_PORT=17321
MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED MYKAD_READER_ENABLED_CAWANGAN='' # IF NO CAWANGAN STATED, ALL CAWANGAN IS ENABLED
+1 -1
View File
@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
* *
* @var array|string|null * @var array|string|null
*/ */
protected $proxies; protected $proxies = '*';
/** /**
* The headers that should be used to detect proxies. * The headers that should be used to detect proxies.
+3 -1
View File
@@ -23,6 +23,8 @@ class AppServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
// if (strpos((string) config('app.url'), 'https://') === 0) {
\Illuminate\Support\Facades\URL::forceScheme('https');
}
} }
} }
+2 -2
View File
@@ -1,7 +1,7 @@
<?php <?php
$default_port = '8085'; $default_port = '17321';
$getReaderEndpoint = fn($x) => 'http://localhost:' . $x . '/?MYKADJSON'; $getReaderEndpoint = fn($x) => 'http://localhost:' . $x . '/read';
return[ return[
'endpoint' => env('MYKAD_READER_ENDPOINT', $getReaderEndpoint(env('MYKAD_READER_PORT', $default_port))), 'endpoint' => env('MYKAD_READER_ENDPOINT', $getReaderEndpoint(env('MYKAD_READER_PORT', $default_port))),
+3
View File
@@ -9,6 +9,9 @@ server {
client_max_body_size 50M; client_max_body_size 50M;
location / { location / {
# Production Apache public/.htaccess 301-strips trailing slashes.
# Nginx ignores .htaccess, so without this /path/ 404s while /path works.
rewrite ^/(.*)/$ /$1 last;
try_files $uri @php; try_files $uri @php;
} }
+284 -206
View File
@@ -1,131 +1,292 @@
let button_read_mykad = document.getElementById("button_read_mykad"); let button_read_mykad = document.getElementById("button_read_mykad");
let button_close_modal = document.querySelector("#daftar_pelanggan_mykad_reader button.btn.btn-danger"); let button_close_modal = document.querySelector("#daftar_pelanggan_mykad_reader button.btn.btn-danger");
let original_photo_loader = document.querySelector("#photo-mykad").src; let photo_mykad = document.querySelector("#photo-mykad");
let original_photo_loader = photo_mykad ? photo_mykad.src : "";
let showLoader = () => { const MYKAD_READER_TIMEOUT_MS = 45000;
const MYKAD_READER_DEFAULT_ENDPOINT = "http://localhost:17321/read";
let showLoader = () => {
let pageLoader = document.getElementById('page_loader'); let pageLoader = document.getElementById('page_loader');
pageLoader.removeAttribute('class'); if (!pageLoader) {
pageLoader.classList.add('loading');
};
let hideLoader = () => {
let pageLoader = document.getElementById('page_loader');
pageLoader.removeAttribute('class');
};
function handleMyKadReader()
{
showLoader();
WebSocketManager.init("wss://localhost:5963/mykadwebsocket");
WebSocketManager.listReader(callbackDoneGetListCardReader);
}
function callbackDoneGetListCardReader(data, respcode)
{
console.log('done get list card reader');
if(respcode === -1){
console.log({'location': 'callbackDoneGetListCardReader', 'data' : data} );
}
let isDevicesConnected = Object.keys(data).length > 0;
if(! isDevicesConnected){
hideLoader();
Swal.fire({ icon: 'error', title: 'Pembaca MyKad tidak dapat dikesan, sila periksa sambungan', });
return; return;
} }
pageLoader.removeAttribute('class');
pageLoader.classList.add('loading');
};
let slots = data.toString().split(','); let hideLoader = () => {
WebSocketManager.open(doneOpenReaderConnection, slots[0]); let pageLoader = document.getElementById('page_loader');
if (!pageLoader) {
return;
}
pageLoader.removeAttribute('class');
};
function getMyKadReaderEndpoint() {
let endpoint = (typeof mykad_reader_endpoint !== 'undefined' && mykad_reader_endpoint)
? String(mykad_reader_endpoint).trim()
: '';
if (!endpoint || endpoint.includes('MYKADJSON') || endpoint.includes(':8085')) {
return MYKAD_READER_DEFAULT_ENDPOINT;
} }
function doneOpenReaderConnection() return endpoint;
{ }
WebSocketManager.readAllText(callBackAfterReadMykad);
async function parseJsonResponse(response) {
let text = await response.text();
let trimmed = (text || '').trim();
if (!trimmed) {
throw new Error('Pembaca MyKad tidak memulangkan data. Sila cuba lagi.');
} }
function handleMyKadReaderError(sw12AndApiName) if (trimmed.charAt(0) === '<') {
{ throw new Error('Pembaca MyKad memulangkan halaman web, bukan data kad. Sila pastikan perkhidmatan mykad-helper sedang berjalan di localhost:17321.');
hideLoader(); }
let error_handler_dictionary = { try {
'0x80100069' : 'Tiada MyKad dikesan, sila masukkan Mykad untuk dibaca', return JSON.parse(trimmed);
'0x80100066' : 'MyKad mungkin dimasukkan terbalik, sila masukkan dengan betul', } catch (error) {
'default' : sw12AndApiName, throw new Error('Pembaca MyKad memulangkan data yang tidak sah. Sila cuba lagi.');
}
}
function getMyKadNumberWithoutHyphens(nric) {
return String(nric || '').replace(/-/g, '');
}
function titleCase(value) {
return String(value || '')
.toLowerCase()
.split(' ')
.filter(Boolean)
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
function getCodeFromValue(needle, haystack, fallback) {
let normalised = titleCase(needle);
let match = haystack.find(item => item[1].toLowerCase() === normalised.toLowerCase());
return match ? match[0] : fallback;
}
function mapGender(gender) {
let value = String(gender || '').toLowerCase();
if (['male', 'lelaki', 'l', 'm'].includes(value)) {
return 'Lelaki';
}
if (['female', 'perempuan', 'p', 'f'].includes(value)) {
return 'Perempuan';
}
return gender || '';
}
function formatDateOfBirth(dob) {
if (!dob) {
return '';
}
let hyphenated = String(dob).includes('-')
? String(dob)
: String(dob).replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
let [year, month, day] = hyphenated.split('-');
if (!year || !month || !day) {
return dob;
}
return day + '/' + month + '/' + year;
}
function getAgeFromDateOfBirth(dob) {
if (!dob) {
return '';
}
let hyphenated = String(dob).includes('-')
? String(dob)
: String(dob).replace(/(\d{4})(\d{2})(\d{2})/, '$1-$2-$3');
let birthDate = new Date(hyphenated);
if (Number.isNaN(birthDate.getTime())) {
return '';
}
let today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
let monthDiff = today.getMonth() - birthDate.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age -= 1;
}
return age;
}
function getBumiputeraStatus(race) {
const non_bumiputera_ethnicity = ['INDIA', 'CINA', 'INDIAN', 'CHINESE'];
return !non_bumiputera_ethnicity.includes(String(race || '').toUpperCase());
}
function joinAddress(data) {
return [data.address1, data.address2, data.address3]
.map(line => String(line || '').trim())
.filter(Boolean)
.join(', ');
}
function mapReaderErrorCode(rawMessage) {
const error_handler_dictionary = {
'0x80100069': 'Tiada MyKad dikesan, sila masukkan MyKad untuk dibaca',
'0x8010000C': 'Tiada MyKad dikesan, sila masukkan MyKad untuk dibaca',
'0x80100066': 'MyKad mungkin dimasukkan terbalik, sila masukkan dengan betul',
'0x80100067': 'MyKad tidak dapat dikesan. Sila cabut dan masukkan semula kad',
'0x80100016': 'Gagal membaca MyKad. Sila pastikan kad dimasukkan dengan betul dan cuba lagi',
'0x8010002E': 'Pembaca MyKad tidak dapat dikesan, sila periksa sambungan',
'0x80100017': 'Pembaca MyKad tidak dapat dikesan, sila periksa sambungan',
}; };
let error_data = sw12AndApiName.split(" "); let message = String(rawMessage || '');
let codes = message.match(/0x[0-9a-fA-F]+/g) || [];
let matched = codes.reverse().find(code => error_handler_dictionary[code]);
let error_code = error_data.filter(x => x.startsWith('0x')).splice(-1) return matched ? error_handler_dictionary[matched] : (message || null);
}
let error_message = error_handler_dictionary['default']; function getReaderErrorMessage(payload) {
if (!payload) {
let hasDefinedError = error_handler_dictionary.hasOwnProperty(error_code); return 'Pembaca MyKad tidak dapat membaca kad. Sila cuba lagi.';
if(hasDefinedError){
error_message = error_handler_dictionary[error_code];
} }
Swal.fire({ icon: 'error', title: error_message, }); let raw = payload.message || payload.error || payload.detail || '';
return mapReaderErrorCode(raw)
|| 'Pembaca MyKad tidak dapat membaca kad. Sila pastikan MyKad dimasukkan dengan betul.';
}
function getFetchErrorTitle(error) {
if (error && error.name === 'AbortError') {
return 'Masa menunggu pembaca MyKad telah tamat. Sila cuba lagi.';
} }
function callBackAfterReadMykad(data, respcode, sw12AndApiName) return 'Pembaca MyKad tidak dapat dikesan. Sila pastikan perkhidmatan pembaca MyKad sedang berjalan.';
{ }
if(respcode !== 0){
handleMyKadReaderError(sw12AndApiName); function getDisplayError(error) {
return if (!error) {
return getFetchErrorTitle(error);
} }
checkIfMyKadExists(data.IDNum) if (error.name === 'AbortError') {
return getFetchErrorTitle(error);
}
let message = String(error.message || '');
if (!message || message.startsWith('Failed to fetch') || message.includes('NetworkError')) {
return getFetchErrorTitle(error);
}
return message;
}
async function handleMyKadReader() {
showLoader();
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), MYKAD_READER_TIMEOUT_MS);
try {
const response = await fetch(getMyKadReaderEndpoint(), {
method: 'POST',
headers: {
'Accept': 'application/json',
},
signal: controller.signal,
});
const payload = await parseJsonResponse(response);
if (!response.ok) {
throw new Error(getReaderErrorMessage(payload));
}
if (!payload || payload.ok !== true || !payload.data) {
throw new Error(getReaderErrorMessage(payload));
}
await handleMyKadData(payload.data);
} catch (error) {
Swal.fire({
icon: 'error',
title: getDisplayError(error),
});
} finally {
clearTimeout(timeoutId);
hideLoader();
}
}
function handleMyKadData(data) {
return checkIfMyKadExists(data.nric)
.then(response => { .then(response => {
let isResponseArray = Array.isArray(response); let isResponseArray = Array.isArray(response);
resolved_response = isResponseArray ? response.pop() : response; let resolved_response = isResponseArray ? response.pop() : response;
if (resolved_response === 'no-data') { if (!resolved_response || resolved_response === 'no-data') {
populateDaftarPelangganModal(data, handleReadPhoto); populateDaftarPelangganModal(data);
} else { } else {
let input_search_noic = document.getElementById("noic"); let input_search_noic = document.querySelector("form[name='frmsearch'] input[name='noic']");
let form_search_noic = document.querySelector("form[name='frmsearch']"); let form_search_noic = document.querySelector("form[name='frmsearch']");
let getMyKadNumberWithoutHypens = myKadNumber => myKadNumber.replace(/-/g, ''); input_search_noic.value = getMyKadNumberWithoutHyphens(data.nric);
input_search_noic.value = getMyKadNumberWithoutHypens(data.IDNum);
form_search_noic.submit(); form_search_noic.submit();
} }
}) })
.catch(error => { .catch(() => {
Swal.fire({ populateDaftarPelangganModal(data);
icon: 'error',
title: error,
});
}); });
}
hideLoader(); function checkIfMyKadExists(myKadNumber) {
} let myKadNumberWithoutHyphens = getMyKadNumberWithoutHyphens(myKadNumber);
let lookupUrl = new URL(wakil_caricustomer_endpoint, window.location.origin);
lookupUrl.searchParams.set('icno', myKadNumberWithoutHyphens);
function checkIfMyKadExists(myKadNumber) { const csrfToken = document.querySelector('input[name="_token"]');
let myKadNumberWithoutHyphens = myKadNumber.replace(/-/g, '');
const url = wakil_caricustomer_endpoint + '/?icno=' + myKadNumberWithoutHyphens; return fetch(lookupUrl.toString(), {
method: 'GET',
const connectionConfig = {
headers: { headers: {
"Content-Type": "application/json",
"Accept": "application/json", "Accept": "application/json",
"X-Requested-With": "XMLHttpRequest", "X-Requested-With": "XMLHttpRequest",
"X-CSRF-Token": document.querySelector('input[name="_token"]').value "X-CSRF-Token": csrfToken ? csrfToken.value : ""
}, },
credentials: "same-origin", credentials: "same-origin",
}; }).then(async response => {
let text = await response.text();
let trimmed = (text || '').trim();
return fetch(url, connectionConfig) if (!trimmed || trimmed.charAt(0) === '<') {
.then(response => response.json()) return 'no-data';
} }
let populateDaftarPelangganModal = (data, callbackAfterPopulateDaftarPelanggan) => { try {
return JSON.parse(trimmed);
} catch (error) {
return 'no-data';
}
});
}
let populateDaftarPelangganModal = (data) => {
$('#daftar_pelanggan_mykad_reader').modal('show'); $('#daftar_pelanggan_mykad_reader').modal('show');
let modal_form = document.querySelector("#daftar_pelanggan_mykad_reader .modal-body .row.form-group"); let modal_form = document.querySelector("#daftar_pelanggan_mykad_reader .modal-body .row.form-group");
@@ -144,150 +305,67 @@ let original_photo_loader = document.querySelector("#photo-mykad").src;
['L', 'Lain-lain'], ['L', 'Lain-lain'],
]; ];
let getCodeFromValue = (needle, haystack) => {
let title_cased_text = needle.split(' ')
.map(w => w[0].toUpperCase() + w.substring(1).toLowerCase())
.join(' ');
return haystack.filter(x => x[1] == title_cased_text)[0][0];
};
let getMyKadNumberWithoutHypens = (IDNum) => {
return IDNum.replace(/-/g, '');
}
let getFormattedDateOfBirth = (date_of_birth) => {
let date_of_birth_hyphenated = date_of_birth.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3");
const [year, month, day] = date_of_birth_hyphenated.split('-');
return day + '/' + month + '/' + year;
};
let getAgeFromDateOfBirth = (date_of_birth) => {
let date_of_birth_hyphenated = date_of_birth.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3");
const [birth_year, birth_month, birth_day] = date_of_birth_hyphenated.split('-');
let formatBirthMonth = (birth_month) => {
let newbirthMonth = birth_month < 9 ? birth_month[1] : birth_month;
return newbirthMonth;
};
const count_leap_year = countLeapYears(birth_year, formatBirthMonth(birth_month), birth_day) - 1;
const start = new Date(date_of_birth_hyphenated),
end = new Date(),
diff = new Date(end - start),
days = ((diff / 1000 / 60 / 60 / 24) - count_leap_year) / 365;
return parseInt(days);
};
let getBumiputeraStatus = (race) => {
const non_bumiputera_ethnicity = ['INDIA', 'CINA'];
let isBumiputera = !non_bumiputera_ethnicity.includes(race);
return isBumiputera;
};
let disablePointerEventsOnClickableInputs = () => { let disablePointerEventsOnClickableInputs = () => {
modal_form.querySelector("input[name='bumiputera']").style.pointerEvents = 'none'; modal_form.querySelector("input[name='bumiputera']").style.pointerEvents = 'none';
modal_form.querySelector("input[name='warganegara']").style.pointerEvents = 'none'; modal_form.querySelector("input[name='warganegara']").style.pointerEvents = 'none';
modal_form.querySelector("select[name='bangsa']").style.pointerEvents = 'none'; modal_form.querySelector("select[name='bangsa']").style.pointerEvents = 'none';
modal_form.querySelector("select[name='agama']").style.pointerEvents = 'none'; modal_form.querySelector("select[name='agama']").style.pointerEvents = 'none';
} };
let mykad_modal = document.querySelector("#daftar_pelanggan_mykad_reader"); let mykad_modal = document.querySelector("#daftar_pelanggan_mykad_reader");
let photo_container = mykad_modal.querySelector("#photo-mykad-container"); let photo_container = mykad_modal.querySelector("#photo-mykad-container");
modal_form.querySelector("textarea[name='name']").value = data.OrgName;
modal_form.querySelector("input[name='noic']").value = getMyKadNumberWithoutHypens(data.IDNum);
modal_form.querySelector("input[name='tarikh_lahir']").value = getFormattedDateOfBirth(data.BirthDate);
modal_form.querySelector("input[name='negeri_lahir']").value = data.BirthPlace;
modal_form.querySelector("input[name='jantina']").value = data.Gender == 'LELAKI' ? 'Lelaki' : 'Perempuan';
modal_form.querySelector("input[name='warganegara']").checked = data.Citizenship === 'WARGANEGARA' ? true : false;
modal_form.querySelector("input[name='bumiputera']").checked = getBumiputeraStatus(data.Race);
modal_form.querySelector("select[name='agama']").value = getCodeFromValue(data.Religion, religions);
modal_form.querySelector("textarea[name='alamat']").value = [data.Address1, data.Address2, data.Address3].join(", ");
let getPostCode = (postCodeCity) => postCodeCity.replace(/\D/g, '');
modal_form.querySelector("input[name='poskod']").value = getPostCode(data.PostcodeCity);
let getCityName = (postCodeCity) => postCodeCity.replace(/\d/g, '');
modal_form.querySelector("input[name='daerah']").value = getCityName(data.PostcodeCity).trim();
modal_form.querySelector("input[name='negeri']").value = data.State;
modal_form.querySelector("input[name='age']").value = getAgeFromDateOfBirth(data.BirthDate);
modal_form.querySelector("select[name='bangsa']").value = getCodeFromValue(data.Race, races);
calculatePassportAge();
photo_container.classList.remove('d-none');
photo_container.classList.add('d-flex');
$('#daftar_pelanggan_mykad_reader').modal('show');
disablePointerEventsOnClickableInputs();
callbackAfterPopulateDaftarPelanggan();
}
function handleReadPhoto()
{
WebSocketManager.init("wss://localhost:5963/mykadwebsocket");
WebSocketManager.listReader(callbackDoneGetListCardReader2);
}
function callbackDoneGetListCardReader2(data, respcode)
{
if(respcode === -1){
console.log({'location': 'callbackDoneGetListCardReader', 'data' : data} );
}
let slots = data.toString().split(',');
WebSocketManager.open(doneOpenReaderConnection2, slots[0]);
}
function doneOpenReaderConnection2()
{
WebSocketManager.readPhoto(callbackAfterReadPhoto2);
}
function callbackAfterReadPhoto2(data, RespCode, RespSW12AndApiName)
{
let mykad_modal = document.querySelector("#daftar_pelanggan_mykad_reader");
let photo = mykad_modal.querySelector("#photo-mykad"); let photo = mykad_modal.querySelector("#photo-mykad");
let isDataEmpty = data modal_form.querySelector("textarea[name='name']").value = data.name || data.gmpc_name || '';
&& Object.keys(data).length === 0 modal_form.querySelector("input[name='noic']").value = getMyKadNumberWithoutHyphens(data.nric);
&& Object.getPrototypeOf(data) === Object.prototype; modal_form.querySelector("input[name='tarikh_lahir']").value = formatDateOfBirth(data.dob);
modal_form.querySelector("input[name='negeri_lahir']").value = data.birth_place || '';
modal_form.querySelector("input[name='jantina']").value = mapGender(data.gender);
modal_form.querySelector("input[name='warganegara']").checked = String(data.citizenship || '').toUpperCase() === 'WARGANEGARA';
modal_form.querySelector("input[name='bumiputera']").checked = getBumiputeraStatus(data.race);
modal_form.querySelector("select[name='agama']").value = getCodeFromValue(data.religion, religions, '05');
modal_form.querySelector("textarea[name='alamat']").value = joinAddress(data);
modal_form.querySelector("input[name='poskod']").value = data.postcode || '';
modal_form.querySelector("input[name='daerah']").value = data.city || '';
modal_form.querySelector("input[name='negeri']").value = data.state || '';
modal_form.querySelector("input[name='age']").value = data.age != null && data.age !== ''
? data.age
: getAgeFromDateOfBirth(data.dob);
modal_form.querySelector("select[name='bangsa']").value = getCodeFromValue(data.race, races, 'L');
if(isDataEmpty){ if (data.has_photo && data.photo_base64) {
let mime = data.photo_mime || 'image/jpeg';
photo.src = 'data:' + mime + ';base64,' + data.photo_base64;
photo_container.classList.remove('d-none');
photo_container.classList.add('d-flex');
} else {
photo.src = original_photo_loader; photo.src = original_photo_loader;
return; photo_container.classList.add('d-none');
photo_container.classList.remove('d-flex');
} }
photo.src = 'data:image/jpeg;base64, ' + data.Base64Photo; disablePointerEventsOnClickableInputs();
} $(modal_form.querySelector("input[name='poskod']")).trigger('change');
};
let hideMykadPhoto = () => { let hideMykadPhoto = () => {
WebSocketManager.close(() => console.log('Websocket closed'));
let photo = document.getElementById("photo-mykad"); let photo = document.getElementById("photo-mykad");
let photo_container = document.getElementById("photo-mykad-container"); let photo_container = document.getElementById("photo-mykad-container");
if (photo) {
photo.src = original_photo_loader; photo.src = original_photo_loader;
}
if (photo_container) {
photo_container.classList.add('d-none'); photo_container.classList.add('d-none');
photo_container.classList.remove('d-flex'); photo_container.classList.remove('d-flex');
}
}; };
button_read_mykad.addEventListener("click", handleMyKadReader); if (button_read_mykad) {
button_close_modal.addEventListener("click", hideMykadPhoto); button_read_mykad.addEventListener("click", handleMyKadReader);
}
if (button_close_modal) {
button_close_modal.addEventListener("click", hideMykadPhoto);
}
+1 -2
View File
@@ -1277,8 +1277,7 @@
let wakil_caricustomer_endpoint = "{{ route('wakil.caricustomer') }}"; let wakil_caricustomer_endpoint = "{{ route('wakil.caricustomer') }}";
let mykad_reader_driver_endpoint = "{{ route('mykadreader.driver') }}"; let mykad_reader_driver_endpoint = "{{ route('mykadreader.driver') }}";
</script> </script>
<script src="{{ asset('js/iris-mykad-websocket-client-api.js') }}"></script> <script src="{{ asset('js/mykad-reader-customer.js') }}?v=2"></script>
<script src="{{ asset('js/mykad-reader-customer.js') }}"></script>
<script src="{{ asset('js/postcode-concerns.js') }}"></script> <script src="{{ asset('js/postcode-concerns.js') }}"></script>
@endpush @endpush
+1 -2
View File
@@ -1417,8 +1417,7 @@ document.getElementsByName('form-store')[0].addEventListener('keypress', functio
let wakil_caricustomer_endpoint = "{{ route('wakil.caricustomer') }}"; let wakil_caricustomer_endpoint = "{{ route('wakil.caricustomer') }}";
let mykad_reader_driver_endpoint = "{{ route('mykadreader.driver') }}"; let mykad_reader_driver_endpoint = "{{ route('mykadreader.driver') }}";
</script> </script>
<script src="{{ asset('js/iris-mykad-websocket-client-api.js') }}"></script> <script src="{{ asset('js/mykad-reader-customer.js') }}?v=2"></script>
<script src="{{ asset('js/mykad-reader-customer.js') }}"></script>
<script src="{{ asset('js/postcode-concerns.js') }}"></script> <script src="{{ asset('js/postcode-concerns.js') }}"></script>
@endpush @endpush
@@ -634,7 +634,7 @@
<tr> <tr>
<td style="width:10px">(-) Rebat Untung</td> <td style="width:10px">(-) Rebat Untung</td>
<td style="width:10px">: RM <td style="width:10px">: RM
{{ number_format($totalrebate['onepercent'], 2) }} {{ number_format($keuntungan_rebate,2) }}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -644,7 +644,7 @@
<tr> <tr>
<td style="width:10px">(-) Rebat Lain-Lain Caj</td> <td style="width:10px">(-) Rebat Lain-Lain Caj</td>
<td style="width:10px">: RM <td style="width:10px">: RM
{{ number_format($totalrebate['ujrah'], 2) }} </td> {{ number_format($ujrah_rebate, 2) }} </td>
</tr> </tr>
<tr> <tr>
<td style="width:10px">Jumlah Keuntungan + Lain-Lain Caj</td> <td style="width:10px">Jumlah Keuntungan + Lain-Lain Caj</td>
@@ -867,7 +867,7 @@
<tr> <tr>
<td style="width:10px">(-) Rebat Untung</td> <td style="width:10px">(-) Rebat Untung</td>
<td style="width:10px">: RM <td style="width:10px">: RM
{{ number_format($totalrebate['onepercent'], 2) }} {{ number_format($keuntungan_rebate, 2) }}
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -877,7 +877,7 @@
<tr> <tr>
<td style="width:10px">(-) Rebat Lain-Lain Caj</td> <td style="width:10px">(-) Rebat Lain-Lain Caj</td>
<td style="width:10px">: RM <td style="width:10px">: RM
{{ number_format($totalrebate['ujrah'], 2) }} </td> {{ number_format($ujrah_rebate, 2) }} </td>
</tr> </tr>
<tr> <tr>
<td style="width:10px">Jumlah Keuntungan + Lain-Lain Caj</td> <td style="width:10px">Jumlah Keuntungan + Lain-Lain Caj</td>