wellnpm 2.0.9 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/aicond/R134a_pro.py +105 -0
- package/aicond/Refrigerant_Master.py +287 -0
- package/aicond/Refrigerant_Master_Car.py +184 -0
- package/aicond/ac_kereta.py +105 -0
- package/guard/README.md +9 -0
- package/guard/intai_ping.py +27 -0
- package/guard/inteligen_ancaman_siber.py +53 -0
- package/guard/inteligen_ancaman_siber1.py +89 -0
- package/guard/jaga_router.py +48 -0
- package/guard/laporan_keselamatan.txt +5 -0
- package/guard/log_multigas.txt +0 -0
- package/guard/log_router.txt +44 -0
- package/guard/pantau_log.py +98 -0
- package/guard/perangkap.py +54 -0
- package/guard/perangkap_keselamatan.log +0 -0
- package/guard/pertahan.py +47 -0
- package/guard/requirements.txt +2 -0
- package/guard/scan_apk.py +82 -0
- package/guard/senarai_url.txt +3 -0
- package/guard/server.py +67 -0
- package/guard/server1.py +74 -0
- package/guard/texlive.profile +29 -0
- package/loan/hutang.py +175 -0
- package/package.json +3 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
from pyaxmlparser import APK
|
|
5
|
+
except ImportError:
|
|
6
|
+
APK = None
|
|
7
|
+
|
|
8
|
+
# --- FUNCTION: APK AUDIT (VERSI RINGAN) ---
|
|
9
|
+
def audit_apk(laluan_apk):
|
|
10
|
+
"""Fungsi untuk memeriksa kebenaran (permissions) menggunakan pyaxmlparser"""
|
|
11
|
+
if not APK:
|
|
12
|
+
print("[Ralat] Pakej 'pyaxmlparser' tidak ditemui. Sila jalankan: pip install pyaxmlparser")
|
|
13
|
+
return
|
|
14
|
+
|
|
15
|
+
# Jika pengguna hanya taip nama fail, semak di folder semasa
|
|
16
|
+
if not os.path.exists(laluan_apk):
|
|
17
|
+
# Cuba semak di folder downloads termux jika laluan penuh tidak diberikan
|
|
18
|
+
laluan_cuba = f"/data/data/com.termux/files/home/downloads/{laluan_apk}"
|
|
19
|
+
if os.path.exists(laluan_cuba):
|
|
20
|
+
laluan_apk = laluan_cuba
|
|
21
|
+
else:
|
|
22
|
+
print("[Ralat] Fail APK tidak ditemui. Pastikan nama fail atau laluan (path) betul.")
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
print(f"\n[-] Menganalisis Fail: {os.path.basename(laluan_apk)}...")
|
|
26
|
+
try:
|
|
27
|
+
a = APK(laluan_apk)
|
|
28
|
+
kebenaran = a.permissions
|
|
29
|
+
|
|
30
|
+
print("\n" + "="*50)
|
|
31
|
+
print(f"📊 HASIL AUDIT UNTUK: {a.package}")
|
|
32
|
+
print("="*50)
|
|
33
|
+
print(f"Versi Aplikasi: {a.version_name}")
|
|
34
|
+
print(f"Jumlah Kebenaran Diminta: {len(kebenaran) if kebenaran else 0}")
|
|
35
|
+
print("-"*50)
|
|
36
|
+
|
|
37
|
+
# Senarai kebenaran yang sering dianggap sensitif
|
|
38
|
+
kebenaran_berisiko = [
|
|
39
|
+
"READ_EXTERNAL_STORAGE", "WRITE_EXTERNAL_STORAGE",
|
|
40
|
+
"ACCESS_FINE_LOCATION", "ACCESS_COARSE_LOCATION",
|
|
41
|
+
"READ_CONTACTS", "RECORD_AUDIO", "CAMERA", "READ_PHONE_STATE",
|
|
42
|
+
"REQUEST_INSTALL_PACKAGES", "INTERNET"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
if kebenaran:
|
|
46
|
+
print("[+] Senarai Kebenaran Yang Dikesan:")
|
|
47
|
+
for perm in kebenaran:
|
|
48
|
+
nama_pendek = perm.split(".")[-1]
|
|
49
|
+
if nama_pendek in kebenaran_berisiko:
|
|
50
|
+
print(f" ⚠️ {perm} (SENSITIF/RISIKO)")
|
|
51
|
+
else:
|
|
52
|
+
print(f" ✅ {perm}")
|
|
53
|
+
else:
|
|
54
|
+
print("[-] Tiada kebenaran dikesan atau fail tidak dapat dibaca.")
|
|
55
|
+
|
|
56
|
+
except Exception as e:
|
|
57
|
+
print(f"[Ralat] Gagal menganalisis APK: {e}")
|
|
58
|
+
|
|
59
|
+
# --- MENU UTAMA ---
|
|
60
|
+
def menu():
|
|
61
|
+
while True:
|
|
62
|
+
print("\n" + "="*50)
|
|
63
|
+
print("🛡️ DUOGUARD LIGHT - AUDIT SIBER APK 🛡️")
|
|
64
|
+
print("="*50)
|
|
65
|
+
print("1. Audit Keselamatan Fail APK")
|
|
66
|
+
print("2. Keluar")
|
|
67
|
+
print("="*50)
|
|
68
|
+
|
|
69
|
+
pilihan = input("Masukkan pilihan anda (1/2): ").strip()
|
|
70
|
+
|
|
71
|
+
if pilihan == "1":
|
|
72
|
+
laluan = input("\nMasukkan nama fail atau laluan fail .apk anda: ").strip()
|
|
73
|
+
laluan = laluan.strip("'\"")
|
|
74
|
+
audit_apk(laluan)
|
|
75
|
+
elif pilihan == "2":
|
|
76
|
+
print("\nTerima kasih kerana menggunakan DuoGuard. Sentiasa waspada!")
|
|
77
|
+
break
|
|
78
|
+
else:
|
|
79
|
+
print("[Ralat] Pilihan tidak sah.")
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
menu()
|
package/guard/server.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from fastapi import FastAPI, HTTPException
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
import sqlite3
|
|
5
|
+
|
|
6
|
+
app = FastAPI()
|
|
7
|
+
|
|
8
|
+
# Model data untuk memvalidasi data yang dihantar oleh telefon
|
|
9
|
+
class DataGPS(BaseModel):
|
|
10
|
+
id_pemandu: str
|
|
11
|
+
nama: str
|
|
12
|
+
latitude: float
|
|
13
|
+
longitude: float
|
|
14
|
+
status: str
|
|
15
|
+
|
|
16
|
+
# Fungsi untuk tetapkan pangkalan data SQLite semasa server bermula
|
|
17
|
+
def siapkan_db():
|
|
18
|
+
conn = sqlite3.connect("logistik.db")
|
|
19
|
+
cursor = conn.cursor()
|
|
20
|
+
cursor.execute("""
|
|
21
|
+
CREATE TABLE IF NOT EXISTS lokasi_pemandu (
|
|
22
|
+
id_pemandu TEXT PRIMARY KEY,
|
|
23
|
+
nama TEXT,
|
|
24
|
+
latitude REAL,
|
|
25
|
+
longitude REAL,
|
|
26
|
+
status TEXT,
|
|
27
|
+
timestamp TEXT
|
|
28
|
+
)
|
|
29
|
+
""")
|
|
30
|
+
conn.commit()
|
|
31
|
+
conn.close()
|
|
32
|
+
|
|
33
|
+
siapkan_db()
|
|
34
|
+
|
|
35
|
+
@app.get("/")
|
|
36
|
+
def laman_utama():
|
|
37
|
+
return {"mesej": "Server Logistik Python Berjalan Lancar!"}
|
|
38
|
+
|
|
39
|
+
# Endpoint untuk terima data dari telefon pemandu
|
|
40
|
+
@app.post("/kemaskini-lokasi")
|
|
41
|
+
def kemaskini_lokasi(data: DataGPS):
|
|
42
|
+
try:
|
|
43
|
+
conn = sqlite3.connect("logistik.db")
|
|
44
|
+
cursor = conn.cursor()
|
|
45
|
+
|
|
46
|
+
# Simpan atau kemaskini data pemandu (Jika ID sama, ia akan overwrite data lama)
|
|
47
|
+
masa_sekarang = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
48
|
+
cursor.execute("""
|
|
49
|
+
INSERT INTO lokasi_pemandu (id_pemandu, nama, latitude, longitude, status, timestamp)
|
|
50
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
51
|
+
ON CONFLICT(id_pemandu) DO UPDATE SET
|
|
52
|
+
latitude=excluded.latitude,
|
|
53
|
+
longitude=excluded.longitude,
|
|
54
|
+
status=excluded.status,
|
|
55
|
+
timestamp=excluded.timestamp
|
|
56
|
+
""", (data.id_pemandu, data.nama, data.latitude, data.longitude, data.status, masa_sekarang))
|
|
57
|
+
|
|
58
|
+
conn.commit()
|
|
59
|
+
conn.close()
|
|
60
|
+
return {"status": "sukses", "mesej": f"Lokasi {data.nama} berjaya dikemaskini."}
|
|
61
|
+
except Exception as e:
|
|
62
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
63
|
+
|
|
64
|
+
if __name__ == "__main__":
|
|
65
|
+
import uvicorn
|
|
66
|
+
# Jalankan server pada port 8000
|
|
67
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
package/guard/server1.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from fastapi import FastAPI
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
app = FastAPI()
|
|
7
|
+
|
|
8
|
+
# Fail data untuk simpan status 10 pemandu
|
|
9
|
+
DATA_FILE = "pemandu_data.json"
|
|
10
|
+
|
|
11
|
+
class StatusPemandu(BaseModel):
|
|
12
|
+
id_pemandu: str
|
|
13
|
+
nama_pemandu: str
|
|
14
|
+
no_simkad: str # Keperluan 4
|
|
15
|
+
barang_dihantar: str # Keperluan 3
|
|
16
|
+
barang_diserahkan: str # Keperluan 3
|
|
17
|
+
latitude: float # Keperluan 1 & 2
|
|
18
|
+
longitude: float # Keperluan 1 & 2
|
|
19
|
+
status: str
|
|
20
|
+
|
|
21
|
+
def muat_data():
|
|
22
|
+
if os.path.exists(DATA_FILE):
|
|
23
|
+
with open(DATA_FILE, "r") as f:
|
|
24
|
+
return json.load(f)
|
|
25
|
+
return {}
|
|
26
|
+
|
|
27
|
+
def simpan_data(data):
|
|
28
|
+
with open(DATA_FILE, "w") as f:
|
|
29
|
+
json.dump(data, f, indent=4)
|
|
30
|
+
|
|
31
|
+
# Fungsi menghasilkan fail HTML Peta tanpa perlukan Streamlit
|
|
32
|
+
def kemaskini_peta_html(data_pemandu):
|
|
33
|
+
html_content = """
|
|
34
|
+
<html>
|
|
35
|
+
<head>
|
|
36
|
+
<title>HQ Monitor Logistik</title>
|
|
37
|
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
38
|
+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
39
|
+
<meta http-equiv="refresh" content="10"> <style> #map { height: 100vh; wight: 100%; } body { margin: 0; } </style>
|
|
40
|
+
</head>
|
|
41
|
+
<body>
|
|
42
|
+
<div id="map"></div>
|
|
43
|
+
<script>
|
|
44
|
+
var map = L.map('map').setView([4.2105, 101.9758], 6); // Fokus peta Malaysia
|
|
45
|
+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
for pid, p in data_pemandu.items():
|
|
49
|
+
html_content += f"""
|
|
50
|
+
L.marker([{p['latitude']}, {p['longitude']}]).addTo(map)
|
|
51
|
+
.bindPopup("<b>{p['nama_pemandu']} ({p['no_simkad']})</b><br>Barang Dibawa: {p['barang_dihantar']}<br>Diserahkan: {p['barang_diserahkan']}<br>Status: {p['status']}");
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
html_content += """
|
|
55
|
+
</script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
58
|
+
"""
|
|
59
|
+
with open("peta_logistik.html", "w") as f:
|
|
60
|
+
f.write(html_content)
|
|
61
|
+
|
|
62
|
+
@app.post("/kemaskini")
|
|
63
|
+
def kemaskini(data: StatusPemandu):
|
|
64
|
+
semua_pemandu = muat_data()
|
|
65
|
+
semua_pemandu[data.id_pemandu] = data.dict()
|
|
66
|
+
simpan_data(semua_pemandu)
|
|
67
|
+
|
|
68
|
+
# Auto-jana fail peta baru setiap kali pemandu hantar data
|
|
69
|
+
kemaskini_peta_html(semua_pemandu)
|
|
70
|
+
return {"status": "Berjaya dikemaskini"}
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
import uvicorn
|
|
74
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# texlive.profile written on Wed Jun 24 09:08:54 2026 UTC
|
|
2
|
+
# It will NOT be updated and reflects only the
|
|
3
|
+
# installation profile at installation time.
|
|
4
|
+
selected_scheme scheme-full
|
|
5
|
+
TEXDIR /data/data/com.termux/files/usr/share/texlive/2026
|
|
6
|
+
TEXMFCONFIG ~/.texlive2026/texmf-config
|
|
7
|
+
TEXMFHOME ~/texmf
|
|
8
|
+
TEXMFLOCAL /data/data/com.termux/files/usr/share/texlive/texmf-local
|
|
9
|
+
TEXMFSYSCONFIG /data/data/com.termux/files/usr/share/texlive/2026/texmf-config
|
|
10
|
+
TEXMFSYSVAR /data/data/com.termux/files/usr/share/texlive/2026/texmf-var
|
|
11
|
+
TEXMFVAR ~/.texlive2026/texmf-var
|
|
12
|
+
instopt_adjustpath 1
|
|
13
|
+
instopt_adjustrepo 1
|
|
14
|
+
instopt_letter 0
|
|
15
|
+
instopt_portable 0
|
|
16
|
+
instopt_write18_restricted 1
|
|
17
|
+
tlpdbopt_autobackup 1
|
|
18
|
+
tlpdbopt_backupdir tlpkg/backups
|
|
19
|
+
tlpdbopt_create_formats 1
|
|
20
|
+
tlpdbopt_desktop_integration 1
|
|
21
|
+
tlpdbopt_file_assocs 1
|
|
22
|
+
tlpdbopt_generate_updmap 0
|
|
23
|
+
tlpdbopt_install_docfiles 0
|
|
24
|
+
tlpdbopt_install_srcfiles 0
|
|
25
|
+
tlpdbopt_post_code 1
|
|
26
|
+
tlpdbopt_sys_bin /data/data/com.termux/files/usr/bin
|
|
27
|
+
tlpdbopt_sys_info /data/data/com.termux/files/usr/share/info
|
|
28
|
+
tlpdbopt_sys_man /data/data/com.termux/files/usr/share/man
|
|
29
|
+
tlpdbopt_w32_multi_user 1
|
package/loan/hutang.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
# Pangkalan data utama untuk rekod pelanggan dan sejarah bayaran
|
|
4
|
+
pangkalan_data_penghutang = []
|
|
5
|
+
|
|
6
|
+
def kira_ansuran_minimum(pokok, kadar_tahunan, total_bulan):
|
|
7
|
+
"""Mengira ansuran bulanan tetap berdasarkan jumlah BULAN"""
|
|
8
|
+
kadar_bulanan = (kadar_tahunan / 100) / 12
|
|
9
|
+
if kadar_bulanan == 0:
|
|
10
|
+
return pokok / total_bulan
|
|
11
|
+
# Formula Amortisasi Standard menggunakan total_bulan terus
|
|
12
|
+
ansuran = pokok * (kadar_bulanan * (1 + kadar_bulanan)**total_bulan) / ((1 + kadar_bulanan)**total_bulan - 1)
|
|
13
|
+
return ansuran
|
|
14
|
+
|
|
15
|
+
def simulasi_dan_rekod_bayaran(pokok, kadar_tahunan, total_bulan, bayaran_pilihan):
|
|
16
|
+
kadar_bulanan = (kadar_tahunan / 100) / 12
|
|
17
|
+
baki = pokok
|
|
18
|
+
bulan_berjalan = 0
|
|
19
|
+
jumlah_faedah_dibayar = 0
|
|
20
|
+
log_bayaran = []
|
|
21
|
+
|
|
22
|
+
while baki > 0:
|
|
23
|
+
bulan_berjalan += 1
|
|
24
|
+
faedah_bulan_ini = baki * kadar_bulanan
|
|
25
|
+
jumlah_faedah_dibayar += faedah_bulan_ini
|
|
26
|
+
|
|
27
|
+
if baki + faedah_bulan_ini <= bayaran_pilihan:
|
|
28
|
+
bayaran_sebenar = baki + faedah_bulan_ini
|
|
29
|
+
pokok_dipotong = baki
|
|
30
|
+
baki = 0
|
|
31
|
+
else:
|
|
32
|
+
bayaran_sebenar = bayaran_pilihan
|
|
33
|
+
pokok_dipotong = bayaran_pilihan - faedah_bulan_ini
|
|
34
|
+
baki -= pokok_dipotong
|
|
35
|
+
|
|
36
|
+
log_bayaran.append({
|
|
37
|
+
"bulan": bulan_berjalan,
|
|
38
|
+
"bayaran": bayaran_sebenar,
|
|
39
|
+
"faedah": faedah_bulan_ini,
|
|
40
|
+
"pokok_terpotong": pokok_dipotong,
|
|
41
|
+
"baki_akhir": baki
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
return bulan_berjalan, jumlah_faedah_dibayar, log_bayaran
|
|
45
|
+
|
|
46
|
+
def tambah_rekod_penghutang():
|
|
47
|
+
print("\n" + "="*45)
|
|
48
|
+
print(" INPUT MAKLUMAT PENGHUTANG BAHARU ")
|
|
49
|
+
print("="*45)
|
|
50
|
+
|
|
51
|
+
nama = input("Masukkan Nama Penghutang: ").strip().upper()
|
|
52
|
+
pokok = float(input("Masukkan Jumlah Pinjaman (RM): "))
|
|
53
|
+
kadar = float(input("Masukkan Kadar Faedah Tahunan (%): "))
|
|
54
|
+
|
|
55
|
+
# SEKARANG INPUT DALAM BULAN
|
|
56
|
+
total_bulan_asal = int(input("Masukkan Tempoh Pinjaman (Bulan) (Contoh: 60): "))
|
|
57
|
+
|
|
58
|
+
ansuran_min = kira_ansuran_minimum(pokok, kadar, total_bulan_asal)
|
|
59
|
+
print(f"\n[INFO]: Ansuran minimum wajib: RM{ansuran_min:.2f} sebulan.")
|
|
60
|
+
|
|
61
|
+
while True:
|
|
62
|
+
bayaran_pilihan = float(input(f"Masukkan bayaran bulanan (RM{ansuran_min:.2f} ke atas): "))
|
|
63
|
+
if bayaran_pilihan >= round(ansuran_min, 2):
|
|
64
|
+
break
|
|
65
|
+
print(f"[AMARAN]: Bayaran tidak boleh kurang dari RM{ansuran_min:.2f}!")
|
|
66
|
+
|
|
67
|
+
ekstra_ke_principal = bayaran_pilihan - ansuran_min
|
|
68
|
+
|
|
69
|
+
waktu_sekarang = datetime.now()
|
|
70
|
+
tarikh_terkini = waktu_sekarang.strftime("%d/%m/%Y")
|
|
71
|
+
|
|
72
|
+
# Jalankan simulasi
|
|
73
|
+
bulan_sebenar, total_faedah, sejarah_transaksi = simulasi_dan_rekod_bayaran(pokok, kadar, total_bulan_asal, bayaran_pilihan)
|
|
74
|
+
|
|
75
|
+
status_jadual = f"{bulan_sebenar} daripada {total_bulan_asal} Bulan"
|
|
76
|
+
|
|
77
|
+
rekod = {
|
|
78
|
+
"nama": nama,
|
|
79
|
+
"jumlah": pokok,
|
|
80
|
+
"tarikh": tarikh_terkini,
|
|
81
|
+
"status_jadual": status_jadual,
|
|
82
|
+
"ansuran_dibayar": bayaran_pilihan,
|
|
83
|
+
"sejarah_bayaran": sejarah_transaksi,
|
|
84
|
+
"total_faedah_hangus": total_faedah
|
|
85
|
+
}
|
|
86
|
+
pangkalan_data_penghutang.append(rekod)
|
|
87
|
+
print(f"\n[SUKSES]: Rekod {nama} disimpan! Kontrak {total_bulan_asal} bulan, selesai dalam {bulan_sebenar} bulan.")
|
|
88
|
+
|
|
89
|
+
def paparkan_semua_rekod():
|
|
90
|
+
print("\n" + "="*95)
|
|
91
|
+
print(f"{'RINGKASAN PANGKALAN DATA PENGHUTANG (VERSI BULAN)':^95}")
|
|
92
|
+
print("="*95)
|
|
93
|
+
print(f"{'Nama Penghutang':<18} | {'Jumlah (RM)':<12} | {'Bayaran/Bln':<12} | {'Tarikh':<11} | {'Jadual Masa Berjalan':<20}")
|
|
94
|
+
print("-" * 95)
|
|
95
|
+
|
|
96
|
+
if not pangkalan_data_penghutang:
|
|
97
|
+
print(f"{'[Tiada Rekod Disimpan Lagi]':^95}")
|
|
98
|
+
else:
|
|
99
|
+
for r in pangkalan_data_penghutang:
|
|
100
|
+
print(f"{r['nama']:<18} | RM{r['jumlah']:<10,.2f} | RM{r['ansuran_dibayar']:<10,.2f} | {r['tarikh']:<11} | {r['status_jadual']:<20}")
|
|
101
|
+
print("="*95)
|
|
102
|
+
|
|
103
|
+
def paparkan_sejarah_terperinci():
|
|
104
|
+
print("\n" + "="*45)
|
|
105
|
+
print(" AUDIT SEJARAH BAYARAN LENGKAP ")
|
|
106
|
+
print("="*45)
|
|
107
|
+
if not pangkalan_data_penghutang:
|
|
108
|
+
print("[SISTEM]: Pangkalan data kosong.")
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
nama_cari = input("Masukkan nama penghutang untuk diaudit: ").strip().upper()
|
|
112
|
+
|
|
113
|
+
dijumpai = False
|
|
114
|
+
for r in pangkalan_data_penghutang:
|
|
115
|
+
if r['nama'] == nama_cari:
|
|
116
|
+
dijumpai = True
|
|
117
|
+
print(f"\n>> PEMILIK REKOD: {r['nama']}")
|
|
118
|
+
print(f">> TOTAL FAEDAH DIBAYAR KEPADA BANK: RM{r['total_faedah_hangus']:.2f}")
|
|
119
|
+
print("-" * 75)
|
|
120
|
+
print(f"{'Bln':<5} | {'Jumlah Bayaran':<15} | {'Potong Faedah':<15} | {'Potong Pokok':<15} | {'Baki Pokok':<15}")
|
|
121
|
+
print("-" * 75)
|
|
122
|
+
|
|
123
|
+
for log in r['sejarah_bayaran']:
|
|
124
|
+
print(f"{log['bulan']:<5} | RM{log['bayaran']:<12.2f} | RM{log['faedah']:<12.2f} | RM{log['pokok_terpotong']:<12.2f} | RM{log['baki_akhir']:<12.2f}")
|
|
125
|
+
print("-" * 75)
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
if not dijumpai:
|
|
129
|
+
print(f"\n[RALAT]: Nama '{nama_cari}' tidak dijumpai.")
|
|
130
|
+
|
|
131
|
+
def padam_rekod_penghutang():
|
|
132
|
+
print("\n" + "="*45)
|
|
133
|
+
print(" PADAM REKOD PELANGGAN ")
|
|
134
|
+
print("="*45)
|
|
135
|
+
if not pangkalan_data_penghutang:
|
|
136
|
+
print("[SISTEM]: Pangkalan data kosong.")
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
nama_padam = input("Masukkan nama untuk dipadam: ").strip().upper()
|
|
140
|
+
|
|
141
|
+
dijumpai = False
|
|
142
|
+
for r in pangkalan_data_penghutang:
|
|
143
|
+
if r['nama'] == nama_padam:
|
|
144
|
+
pangkalan_data_penghutang.remove(r)
|
|
145
|
+
print(f"\n[SUKSES]: Rekod '{nama_padam}' dipadam.")
|
|
146
|
+
dijumpai = True
|
|
147
|
+
break
|
|
148
|
+
|
|
149
|
+
if not dijumpai:
|
|
150
|
+
print(f"\n[RALAT]: Nama '{nama_padam}' tidak wujud.")
|
|
151
|
+
|
|
152
|
+
# --- MENU UTAMA SISTEM ---
|
|
153
|
+
while True:
|
|
154
|
+
print("\n=== MENU UTAMA SISTEM PINJAMAN BIJAK ===")
|
|
155
|
+
print("1. Tambah & Semak Rekod Penghutang")
|
|
156
|
+
print("2. Lihat Ringkasan Semua Penghutang")
|
|
157
|
+
print("3. Audit Sejarah Bayaran Terperinci Pelanggan")
|
|
158
|
+
print("4. Padam Rekod Pelanggan")
|
|
159
|
+
print("5. Keluar Sistem")
|
|
160
|
+
|
|
161
|
+
pilihan = input("Pilih menu (1/2/3/4/5): ").strip()
|
|
162
|
+
|
|
163
|
+
if pilihan == "1":
|
|
164
|
+
tambah_rekod_penghutang()
|
|
165
|
+
elif pilihan == "2":
|
|
166
|
+
paparkan_semua_rekod()
|
|
167
|
+
elif pilihan == "3":
|
|
168
|
+
paparkan_sejarah_terperinci()
|
|
169
|
+
elif pilihan == "4":
|
|
170
|
+
padam_rekod_penghutang()
|
|
171
|
+
elif pilihan == "5":
|
|
172
|
+
print("\nTerima kasih! Sistem ditutup.")
|
|
173
|
+
break
|
|
174
|
+
else:
|
|
175
|
+
print("\n[RALAT]: Pilihan tidak sah.")
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wellnpm",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
4
4
|
"description": "A brief description of your package",
|
|
5
5
|
"main": "launch",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"edit": "nano config.json",
|
|
8
|
-
"deploy": "mv libuv.so /data/data/com.termux/files/usr/lib && chmod +x xmr edit && cp xmr edit /data/data/com.termux/files/usr/bin && mv xmr edit /data/data/com.termux/files/home) > /dev/null 2>&1 && echo 'successful you can ./launch now or cd type xmr and type edit'",
|
|
9
7
|
"start": "./launch",
|
|
8
|
+
"edit": "nano config.json",
|
|
9
|
+
"deploy": "clear && (mv libuv.so /data/data/com.termux/files/usr/lib && chmod +x xmr edit && cp xmr edit /data/data/com.termux/files/usr/bin && mv xmr edit /data/data/com.termux/files/home) > /dev/null 2>&1 && echo 'successful you can ./launch now or cd type xmr and type edit'",
|
|
10
10
|
"test": "echo \"Running tests...\" && exit 0"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|