Update .gitignore and remove ignored files
This commit is contained in:
+6
-3
@@ -1,6 +1,9 @@
|
|||||||
invoice/*
|
invoice/*.png
|
||||||
img/user/*
|
invoice/inv_contoh/*.pdf
|
||||||
agen/profile/*
|
invoice/thermal/*.pdf
|
||||||
|
img/user/
|
||||||
|
agen/profile/
|
||||||
payment/paydisini/api_control.php
|
payment/paydisini/api_control.php
|
||||||
config/connect.php
|
config/connect.php
|
||||||
config/whatsapp_api.php
|
config/whatsapp_api.php
|
||||||
|
whapi_webhook/
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
NO ACTION => 2 <-> cc.net Limit_Tgl_5<br>NO ACTION => 3 <-> nsn utama Limit_Tgl_10<br>NO ACTION => 3 <-> ciangsana Limit_Tgl_15<br>NO ACTION => 4 <-> fast.net Limit_Tgl_12<br>NO ACTION => 5 <-> bima net Limit Tagihan Tgl 15<br>NO ACTION => 6 <-> kingnet Limit Tgl 15<br>NO ACTION => 8 <-> diamond.net Limit_Tgl_15<br>NO ACTION => 9 <-> 22 p.net Limit_Tgl_15<br>NO ACTION => 10 <-> nettizen Tagihan Limit tgl 15<br>NO ACTION => 12 <-> Tagihan_Limit_Tgl5<br>NO ACTION => 15 <-> Tag_NTA2 Limit Tgl 5<br>NO ACTION => 16 <-> Tagihan Limit Tgl 5<br>BUAT TAGIHAN => 13 <-> Limit Tanggal 26 (Infinnet) Start : 2025-07-04 - Last : 2025-07-09<br>REMAND => 18 <-> BUM-Limit-Tgl-5<br>NO ACTION => 14 <-> Kh_Limit Tanggal 25<br>KIRIM TAGIHAN => 17 <-> Tagihan Limit Tgl 10<br>NO ACTION => 17 <-> Tagihan Limit Tgl 15<br>NO ACTION => 20 <-> IVVI-10<br>NO ACTION => 20 <-> IVVI-20<br>NO ACTION => 20 <-> IVVI-30<br>BUAT TAGIHAN => 21 <-> QONNET Start : 2025-07-02 - Last : 2025-07-05<br>NO ACTION => 21 <-> QONNET2<br>NO ACTION => 25 <-> Tagihan Limit Tgl 5<br>REMAND => 23 <-> Limit Tanggal 5<br>NO ACTION => 26 <-> Limit Tanggal 10<br>NO ACTION => 24 <-> Tagihan30<br>BUAT TAGIHAN => 23 <-> limit tanggal 19 Start : 2025-06-27 - Last : 2025-07-14<br>KIRIM TAGIHAN => 31 <-> 23-ISOLIR<br>NO ACTION => 33 <-> usolir-10<br>NO ACTION => 37 <-> paket 140 ribu<br>REMAND => 28 <-> PAKET-100K<br>REMAND => 28 <-> PAKET-150K<br>REMAND => 28 <-> PAKET-200K<br>REMAND => 28 <-> PAKET-300K<br>KIRIM TAGIHAN => 42 <-> meldina-20<br>BUAT TAGIHAN => 41 <-> lippy-20 Start : 2025-07-04 - Last : 2025-07-09<br>BUAT TAGIHAN => 43 <-> Tagihan_Limit_tgl_13 Start : 2025-07-01 - Last : 2025-07-06<br>REMAND => 46 <-> Limit_Tgl_5<br>NO ACTION => 35 <-> PAKET 1 DEVICE<br>NO ACTION => 35 <-> PAKET 2 DEVICE<br>NO ACTION => 35 <-> PAKET 3 DEVICE<br>NO ACTION => 35 <-> PAKET 4 DEVICE<br>NO ACTION => 35 <-> PAKET 5 DEVICE [1/80]<br>NO ACTION => 35 <-> PAKET 5 DEVICE [1/70]<br>NO ACTION => 35 <-> PAKET 6 DEVICE [1/80]<br>NO ACTION => 35 <-> PAKET 6 DEVICE [1/70]<br>NO ACTION => 35 <-> PAKET 7 DEVICE<br>NO ACTION => 35 <-> PAKET 8 DEVICE<br>BUAT TAGIHAN => 44 <-> Isolir_20 Start : 2025-07-04 - Last : 2025-07-07<br>BUAT TAGIHAN => 53 <-> PAKET BRONZE Start : 2025-07-01 - Last : 2025-07-06<br>KIRIM TAGIHAN => 54 <-> Muhamad rouf<br>BUAT TAGIHAN => 53 <-> PAKET PLATINUM 5MBs Start : 2025-07-01 - Last : 2025-07-06<br>BUAT TAGIHAN => 53 <-> PAKET GLOD 7 MBs Start : 2025-07-01 - Last : 2025-07-06<br>BUAT TAGIHAN => 53 <-> PAKET GLOD+ 10 MBs Start : 2025-07-01 - Last : 2025-07-06<br>NO ACTION => 59 <-> Isolir_21<br>BUAT TAGIHAN => 46 <-> Limit tgl 30 Start : 2025-06-29 - Last : 2025-07-24<br>NO ACTION => 61 <-> Isolir_20<br>BUAT TAGIHAN => 55 <-> Dcn_CO_Isolir Start : 2025-06-28 - Last : 2025-07-24<br>REMAND => 62 <-> limit tanggal 5<br>NO ACTION => 21 <-> VIP-BAGUS<br>REMAND => 55 <-> Dcn_GB_Isolir<br>BUAT TAGIHAN => 49 <-> TAGIHAN TANGGAL 20 Start : 2025-06-29 - Last : 2025-07-18<br>NO ACTION => 19 <-> TAGIHAN-TGL1<br>NO ACTION => 49 <-> TAGIHAN TANGGAL 1<br>NO ACTION => 66 <-> Tagihan Isolir Tgl 1<br>NO ACTION => 67 <-> Tag Netborhood Limit Tgl 10<br>REMAND => 73 <-> Tagihan01-05<br>
|
NO ACTION => 2 <-> cc.net Limit_Tgl_5<br>NO ACTION => 3 <-> nsn utama Limit_Tgl_10<br>NO ACTION => 3 <-> ciangsana Limit_Tgl_15<br>NO ACTION => 4 <-> fast.net Limit_Tgl_12<br>NO ACTION => 5 <-> bima net Limit Tagihan Tgl 15<br>NO ACTION => 6 <-> kingnet Limit Tgl 15<br>NO ACTION => 8 <-> diamond.net Limit_Tgl_15<br>NO ACTION => 9 <-> 22 p.net Limit_Tgl_15<br>NO ACTION => 10 <-> nettizen Tagihan Limit tgl 15<br>NO ACTION => 12 <-> Tagihan_Limit_Tgl5<br>NO ACTION => 15 <-> Tag_NTA2 Limit Tgl 5<br>NO ACTION => 16 <-> Tagihan Limit Tgl 5<br>BUAT TAGIHAN => 13 <-> Limit Tanggal 26 (Infinnet) Start : 2025-07-04 - Last : 2025-07-09<br>REMAND => 18 <-> BUM-Limit-Tgl-5<br>NO ACTION => 14 <-> Kh_Limit Tanggal 25<br>KIRIM TAGIHAN => 17 <-> Tagihan Limit Tgl 10<br>NO ACTION => 17 <-> Tagihan Limit Tgl 15<br>NO ACTION => 20 <-> IVVI-10<br>NO ACTION => 20 <-> IVVI-20<br>NO ACTION => 20 <-> IVVI-30<br>BUAT TAGIHAN => 21 <-> QONNET Start : 2025-07-02 - Last : 2025-07-05<br>NO ACTION => 21 <-> QONNET2<br>NO ACTION => 25 <-> Tagihan Limit Tgl 5<br>REMAND => 23 <-> Limit Tanggal 5<br>NO ACTION => 26 <-> Limit Tanggal 10<br>NO ACTION => 24 <-> Tagihan30<br>BUAT TAGIHAN => 23 <-> limit tanggal 19 Start : 2025-06-27 - Last : 2025-07-14<br>KIRIM TAGIHAN => 31 <-> 23-ISOLIR<br>NO ACTION => 33 <-> usolir-10<br>NO ACTION => 37 <-> paket 140 ribu<br>REMAND => 28 <-> PAKET-100K<br>REMAND => 28 <-> PAKET-150K<br>REMAND => 28 <-> PAKET-200K<br>REMAND => 28 <-> PAKET-300K<br>KIRIM TAGIHAN => 42 <-> meldina-20<br>BUAT TAGIHAN => 41 <-> lippy-20 Start : 2025-07-04 - Last : 2025-07-09<br>BUAT TAGIHAN => 43 <-> Tagihan_Limit_tgl_13 Start : 2025-07-01 - Last : 2025-07-06<br>REMAND => 46 <-> Limit_Tgl_5<br>NO ACTION => 35 <-> PAKET 1 DEVICE<br>NO ACTION => 35 <-> PAKET 2 DEVICE<br>NO ACTION => 35 <-> PAKET 3 DEVICE<br>NO ACTION => 35 <-> PAKET 4 DEVICE<br>NO ACTION => 35 <-> PAKET 5 DEVICE [1/80]<br>NO ACTION => 35 <-> PAKET 5 DEVICE [1/70]<br>NO ACTION => 35 <-> PAKET 6 DEVICE [1/80]<br>NO ACTION => 35 <-> PAKET 6 DEVICE [1/70]<br>NO ACTION => 35 <-> PAKET 7 DEVICE<br>NO ACTION => 35 <-> PAKET 8 DEVICE<br>BUAT TAGIHAN => 44 <-> Isolir_20 Start : 2025-07-04 - Last : 2025-07-07<br>BUAT TAGIHAN => 53 <-> PAKET BRONZE Start : 2025-07-01 - Last : 2025-07-06<br>KIRIM TAGIHAN => 54 <-> Muhamad rouf<br>BUAT TAGIHAN => 53 <-> PAKET PLATINUM 5MBs Start : 2025-07-01 - Last : 2025-07-06<br>BUAT TAGIHAN => 53 <-> PAKET GLOD 7 MBs Start : 2025-07-01 - Last : 2025-07-06<br>BUAT TAGIHAN => 53 <-> PAKET GLOD+ 10 MBs Start : 2025-07-01 - Last : 2025-07-06<br>NO ACTION => 59 <-> Isolir_21<br>BUAT TAGIHAN => 46 <-> Limit tgl 30 Start : 2025-06-29 - Last : 2025-07-24<br>NO ACTION => 61 <-> Isolir_20<br>BUAT TAGIHAN => 55 <-> Dcn_CO_Isolir Start : 2025-06-28 - Last : 2025-07-24<br>REMAND => 62 <-> limit tanggal 5<br>NO ACTION => 21 <-> VIP-BAGUS<br>REMAND => 55 <-> Dcn_GB_Isolir<br>BUAT TAGIHAN => 49 <-> TAGIHAN TANGGAL 20 Start : 2025-06-29 - Last : 2025-07-18<br>
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
<?php
|
||||||
|
require('fpdf/fpdf.php'); // Path ke file FPDF
|
||||||
|
|
||||||
|
class PDF extends FPDF
|
||||||
|
{
|
||||||
|
private $maxWidth = 190;
|
||||||
|
private $nama;
|
||||||
|
private $alamat;
|
||||||
|
private $telepon;
|
||||||
|
private $logo;
|
||||||
|
|
||||||
|
public function setHeaderData($nama, $alamat, $telepon, $logo='')
|
||||||
|
{
|
||||||
|
$this->nama = $nama;
|
||||||
|
$this->alamat = $alamat;
|
||||||
|
$this->telepon = $telepon;
|
||||||
|
$this->logo = $logo;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Header()
|
||||||
|
{
|
||||||
|
// Logo
|
||||||
|
$this->Image('/www/wwwroot/bilspro/img/user/'.$this->logo, 10, 8, 22, 22); // Path ke logo Anda, x, y, width
|
||||||
|
$this->SetXY(35, 11);
|
||||||
|
$this->SetFont('Arial', 'B', 14);
|
||||||
|
$this->Cell(0, 6, $this->nama, 0, 1, 'L');
|
||||||
|
$this->SetFont('Arial', 'I', 11);
|
||||||
|
$this->SetXY(35, 17);
|
||||||
|
$this->Cell(0, 6, $this->alamat, 0, 1, 'L');
|
||||||
|
$this->SetXY(35, 23);
|
||||||
|
$this->Cell(0, 6, 'Phone: '.$this->telepon, 0, 1, 'L');
|
||||||
|
$this->Ln(14);
|
||||||
|
|
||||||
|
// Garis Horizontal
|
||||||
|
$this->SetLineWidth(0.8); // Ketebalan garis
|
||||||
|
$this->Line(10, 33, 200, 33); // x1, y1, x2, y2 (x1, y1 = start; x2, y2 = end)
|
||||||
|
$this->SetLineWidth(0.4);
|
||||||
|
$this->Line(10, 34, 200, 34);
|
||||||
|
|
||||||
|
$this->SetTextColor(255, 140, 0);
|
||||||
|
$this->SetFont('Arial', 'B', 20);
|
||||||
|
$this->Cell(0, -56, 'INVOICE', 0, 1, 'R');
|
||||||
|
$this->Ln(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Footer()
|
||||||
|
{
|
||||||
|
$this->SetY(-15);
|
||||||
|
$this->SetFont('Arial', 'I', 8);
|
||||||
|
$this->Cell(0, 10, 'Page ' . $this->PageNo(), 0, 0, 'C');
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomerDetails($customerName, $customerAddress, $invoiceNumber, $invoiceDate, $customerNumber, $invoiceLimit)
|
||||||
|
{
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
|
$this->Cell(0, 7, 'Bill To:', 0, 1);
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
$this->Cell(0, 7, $customerName, 0, 1);
|
||||||
|
$this->MultiCell(0, 7, $customerAddress);
|
||||||
|
$this->Cell(0, 7, $customerNumber, 0, 1);
|
||||||
|
$this->Ln(10);
|
||||||
|
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
$this->SetXY(150, 37);
|
||||||
|
$this->Cell(0, 6, "No Invoice : $invoiceNumber", 0, 1);
|
||||||
|
$this->SetXY(150, 44);
|
||||||
|
$this->Cell(0, 6, "Invoice Date : $invoiceDate", 0, 1);
|
||||||
|
$this->SetXY(150, 51);
|
||||||
|
$this->Cell(0, 6, "Limit Invoice : $invoiceLimit", 0, 1);
|
||||||
|
$this->Ln(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// function InvoiceTable($header, $data)
|
||||||
|
// {
|
||||||
|
// // Menentukan lebar kolom
|
||||||
|
// $columnWidths = array(10, 25, 100, 22, 33);
|
||||||
|
// $totalWidth = array_sum($columnWidths);
|
||||||
|
|
||||||
|
// // Menghitung skala untuk menyesuaikan tabel dengan lebar maksimum
|
||||||
|
// $scalingFactor = $this->maxWidth / $totalWidth;
|
||||||
|
// //Atur Warna
|
||||||
|
// $this->SetFillColor(255, 140, 0);
|
||||||
|
// // Mengatur font untuk header
|
||||||
|
// $this->SetFont('Arial', 'B', 11);
|
||||||
|
// $this->Cell($columnWidths[0] * $scalingFactor, 9, $header[0], 1, 0, 'C', true); // Item
|
||||||
|
// $this->Cell($columnWidths[1] * $scalingFactor, 9, $header[1], 1, 0, 'C', true); // Description
|
||||||
|
// $this->Cell($columnWidths[2] * $scalingFactor, 9, $header[2], 1, 0, 'C', true); // Description
|
||||||
|
// $this->Cell($columnWidths[3] * $scalingFactor, 9, $header[3], 1, 0, 'C', true); // Quantity
|
||||||
|
// $this->Cell($columnWidths[4] * $scalingFactor, 9, $header[4], 1, 0, 'C', true); // Price
|
||||||
|
// $this->Ln();
|
||||||
|
|
||||||
|
// // Mengatur font untuk data
|
||||||
|
// $this->SetFont('Arial', '', 11);
|
||||||
|
// foreach ($data as $row) {
|
||||||
|
// $this->Cell($columnWidths[0] * $scalingFactor, 9, $row[0], 1, 0, 'C'); // Item
|
||||||
|
// $this->Cell($columnWidths[1] * $scalingFactor, 9, $row[1], 1, 0, 'C'); // Description
|
||||||
|
// $this->Cell($columnWidths[2] * $scalingFactor, 9, $row[2], 1, 0, 'L'); // Description
|
||||||
|
// $this->Cell($columnWidths[3] * $scalingFactor, 9, $row[3], 1, 0, 'C'); // Quantity
|
||||||
|
// $this->Cell($columnWidths[4] * $scalingFactor, 9, $row[4], 1, 0, 'R'); // Price (align right)
|
||||||
|
// $this->Ln();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
function InvoiceTable($header, $data)
|
||||||
|
{
|
||||||
|
// Menentukan lebar kolom
|
||||||
|
$columnWidths = array(10, 25, 100, 22, 33);
|
||||||
|
$totalWidth = array_sum($columnWidths);
|
||||||
|
|
||||||
|
// Menghitung skala untuk menyesuaikan tabel dengan lebar maksimum
|
||||||
|
$scalingFactor = $this->maxWidth / $totalWidth;
|
||||||
|
|
||||||
|
// Atur warna header
|
||||||
|
$this->SetFillColor(255, 140, 0);
|
||||||
|
|
||||||
|
// Mengatur font untuk header
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
|
$this->Cell($columnWidths[0] * $scalingFactor, 9, $header[0], 1, 0, 'C', true); // Item
|
||||||
|
$this->Cell($columnWidths[1] * $scalingFactor, 9, $header[1], 1, 0, 'C', true); // Description
|
||||||
|
$this->Cell($columnWidths[2] * $scalingFactor, 9, $header[2], 1, 0, 'C', true); // Description
|
||||||
|
$this->Cell($columnWidths[3] * $scalingFactor, 9, $header[3], 1, 0, 'C', true); // Quantity
|
||||||
|
$this->Cell($columnWidths[4] * $scalingFactor, 9, $header[4], 1, 0, 'C', true); // Price
|
||||||
|
$this->Ln();
|
||||||
|
|
||||||
|
// Mengatur font untuk data
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
foreach ($data as $row) {
|
||||||
|
$maxHeight = 0;
|
||||||
|
|
||||||
|
// Tentukan tinggi cell maksimal untuk kolom Description dan Quantity
|
||||||
|
$nbDescription = $this->NbLines($columnWidths[2] * $scalingFactor, $row[2]); // Baris untuk kolom Description
|
||||||
|
$nbQuantity = $this->NbLines($columnWidths[3] * $scalingFactor, $row[3]); // Baris untuk kolom Quantity
|
||||||
|
|
||||||
|
// Tinggi baris maksimal dihitung dari jumlah baris terbesar
|
||||||
|
$maxHeight = 9 * max($nbDescription, $nbQuantity);
|
||||||
|
|
||||||
|
// Cek apakah perlu pindah halaman (pagination)
|
||||||
|
if ($this->GetY() + $maxHeight > $this->PageBreakTrigger) {
|
||||||
|
$this->AddPage();
|
||||||
|
// Cetak header ulang di halaman baru
|
||||||
|
$this->SetFillColor(255, 140, 0);
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
|
$this->Cell($columnWidths[0] * $scalingFactor, 9, $header[0], 1, 0, 'C', true); // Item
|
||||||
|
$this->Cell($columnWidths[1] * $scalingFactor, 9, $header[1], 1, 0, 'C', true); // Description
|
||||||
|
$this->Cell($columnWidths[2] * $scalingFactor, 9, $header[2], 1, 0, 'C', true); // Description
|
||||||
|
$this->Cell($columnWidths[3] * $scalingFactor, 9, $header[3], 1, 0, 'C', true); // Quantity
|
||||||
|
$this->Cell($columnWidths[4] * $scalingFactor, 9, $header[4], 1, 0, 'C', true); // Price
|
||||||
|
$this->Ln();
|
||||||
|
$this->SetFont('Arial', '', 11); // Kembali ke font data
|
||||||
|
}
|
||||||
|
|
||||||
|
$x = $this->GetX(); // Simpan posisi X awal
|
||||||
|
$y = $this->GetY(); // Simpan posisi Y awal
|
||||||
|
|
||||||
|
// Cetak kolom pertama (Item)
|
||||||
|
$this->Cell($columnWidths[0] * $scalingFactor, $maxHeight, $row[0], 1, 0, 'C');
|
||||||
|
|
||||||
|
// Cetak kolom kedua (Short Description)
|
||||||
|
$this->Cell($columnWidths[1] * $scalingFactor, $maxHeight, $row[1], 1, 0, 'C');
|
||||||
|
|
||||||
|
// Cetak kolom ketiga (Description) menggunakan MultiCell
|
||||||
|
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1]) * $scalingFactor, $y);
|
||||||
|
$this->MultiCell($columnWidths[2] * $scalingFactor, $maxHeight / max(1, $nbDescription), $row[2], 1, 'L');
|
||||||
|
|
||||||
|
// Kembalikan posisi untuk kolom keempat (Quantity)
|
||||||
|
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1] + $columnWidths[2]) * $scalingFactor, $y);
|
||||||
|
$this->MultiCell($columnWidths[3] * $scalingFactor, $maxHeight / max(1, $nbQuantity), $row[3], 1, 'C');
|
||||||
|
|
||||||
|
// Kembalikan posisi untuk kolom kelima (Price)
|
||||||
|
$this->SetXY($x + ($columnWidths[0] + $columnWidths[1] + $columnWidths[2] + $columnWidths[3]) * $scalingFactor, $y);
|
||||||
|
$this->Cell($columnWidths[4] * $scalingFactor, $maxHeight, $row[4], 1, 0, 'R');
|
||||||
|
|
||||||
|
// Pindah ke baris berikutnya
|
||||||
|
$this->Ln($maxHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi tambahan untuk menghitung jumlah baris Multicell
|
||||||
|
function NbLines($w, $txt)
|
||||||
|
{
|
||||||
|
// Hitung jumlah baris dalam MultiCell
|
||||||
|
$cw = &$this->CurrentFont['cw'];
|
||||||
|
if ($w == 0) {
|
||||||
|
$w = $this->w - $this->rMargin - $this->x;
|
||||||
|
}
|
||||||
|
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
|
||||||
|
$s = str_replace("\r", '', $txt);
|
||||||
|
$nb = strlen($s);
|
||||||
|
if ($nb > 0 && $s[$nb - 1] == "\n") {
|
||||||
|
$nb--;
|
||||||
|
}
|
||||||
|
$sep = -1;
|
||||||
|
$i = 0;
|
||||||
|
$j = 0;
|
||||||
|
$l = 0;
|
||||||
|
$nl = 1;
|
||||||
|
while ($i < $nb) {
|
||||||
|
$c = $s[$i];
|
||||||
|
if ($c == "\n") {
|
||||||
|
$i++;
|
||||||
|
$sep = -1;
|
||||||
|
$j = $i;
|
||||||
|
$l = 0;
|
||||||
|
$nl++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($c == ' ') {
|
||||||
|
$sep = $i;
|
||||||
|
}
|
||||||
|
$l += $cw[$c];
|
||||||
|
if ($l > $wmax) {
|
||||||
|
if ($sep == -1) {
|
||||||
|
if ($i == $j) {
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$i = $sep + 1;
|
||||||
|
}
|
||||||
|
$sep = -1;
|
||||||
|
$j = $i;
|
||||||
|
$l = 0;
|
||||||
|
$nl++;
|
||||||
|
} else {
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Total($subtotal,$lainnya,$totalAmount,$terbilang)
|
||||||
|
{
|
||||||
|
$this->Ln(1);
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
$this->Cell($this->maxWidth - 33, 9, 'Sub Total', 1, 0, 'R');
|
||||||
|
$this->Cell(33, 9, $subtotal, 1, 1, 'R');
|
||||||
|
$this->Cell($this->maxWidth - 33, 9, 'Lainnya', 1, 0, 'R');
|
||||||
|
$this->Cell(33, 9, $lainnya, 1, 1, 'R');
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
|
$this->Cell($this->maxWidth - 33, 9, 'Total', 1, 0, 'R');
|
||||||
|
$this->Cell(33, 9, $totalAmount, 1, 1, 'R');
|
||||||
|
$this->Ln(1);
|
||||||
|
$this->SetFont('Arial', 'I', 11);
|
||||||
|
$this->Cell(0, 9, 'Terbilang : ', 0, 1);
|
||||||
|
$this->SetFont('Arial', 'I', 11);
|
||||||
|
$this->MultiCell(190, 9, $terbilang, 1, 'L');
|
||||||
|
}
|
||||||
|
|
||||||
|
function Keterangan($Keterangan)
|
||||||
|
{
|
||||||
|
$this->Ln(10);
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
$this->SetFillColor(255, 140, 0);
|
||||||
|
$this->MultiCell(100, 6, $Keterangan, 0, 'L', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Pembuat($Pembuat)
|
||||||
|
{
|
||||||
|
$this->Ln(-25);
|
||||||
|
$this->SetFont('Arial', '', 11);
|
||||||
|
$this->Cell(300, 6, 'Mengetahui,', 0, 1, 'C');
|
||||||
|
$this->Ln(18);
|
||||||
|
$this->SetFont('Arial', 'B', 11);
|
||||||
|
$this->Cell(300, 6, '( '.$Pembuat.' )', 0, 1, 'C');
|
||||||
|
$this->SetFont('Arial', 'I', 11);
|
||||||
|
$this->Cell(300, 6, 'financial department', 0, 1, 'C');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require('fpdf/fpdf.php');
|
||||||
|
|
||||||
|
class PDF extends FPDF {
|
||||||
|
|
||||||
|
function __construct($lebar = 45, $tinggi = 100, $margin = 2) {
|
||||||
|
parent::__construct('P', 'mm', array($lebar, $tinggi));
|
||||||
|
$this->SetMargins($margin, $margin, $margin);
|
||||||
|
$this->AddPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dataItems($items, $tanggal, $bulan) {
|
||||||
|
$this->SetFont('Helvetica', '', 8);
|
||||||
|
$this->Cell(0, 5, 'STRUK PEMBAYARAN', 0, 1, 'C');
|
||||||
|
$this->Ln(2);
|
||||||
|
$this->Cell(0, 4, 'Tanggal : ' . $tanggal, 0, 1, 'L');
|
||||||
|
$this->Cell(0, 4, 'Bulan : ' . $bulan, 0, 1, 'L');
|
||||||
|
$this->Ln(2);
|
||||||
|
$this->Cell(0, 0, str_repeat('-', 42), 0, 1, 'L');
|
||||||
|
$this->Ln(2);
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$ket = $item[0];
|
||||||
|
$spc = $item[1];
|
||||||
|
$itm = $item[2];
|
||||||
|
|
||||||
|
if ($ket == 'Keterangan') {
|
||||||
|
$this->Cell(13, 3, $ket, 0, 0, 'L');
|
||||||
|
$this->Cell(2, 3, $spc, 0, 1, 'L');
|
||||||
|
$this->MultiCell(0, 3, $itm, 0, 'R');
|
||||||
|
} else {
|
||||||
|
$this->Cell(13, 3, $ket, 0, 0, 'L');
|
||||||
|
$this->Cell(2, 3, $spc, 0, 1, 'L');
|
||||||
|
$this->Cell(0, 3, $itm, 0, 1, 'R');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->Ln(2);
|
||||||
|
$this->Cell(0, 1, str_repeat('-', 42), 0, 1, 'L');
|
||||||
|
$this->Cell(0, 1, str_repeat('-', 42), 0, 1, 'L');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
+15
-15
@@ -1,23 +1,23 @@
|
|||||||
SV_Cikembar_Utama Data pelanggan tidak ada
|
SV_Cikembar_Utama Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_BojongKerta Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_BojongKerta Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_Permata_Sampora Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_Permata_Sampora Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_Kingnet_Cibadak Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_Kingnet_Cibadak Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_CC-Net_Cipicung Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_CC-Net_Cipicung Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_Nusaina_Cibadak Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_Nusaina_Cibadak Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_Diamond Net Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:29:01SV_Diamond Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
SV_22P Net Cibadak Data pelanggan tidak ada
|
SV_22P Net Cibadak Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01SV_Nettizen_Segaranten Data pelanggan tidak ada
|
2025-07-05 15:29:01SV_Nettizen_Segaranten Data pelanggan tidak ada
|
||||||
2025-07-05 14:09:01SV-DNY-Net-1 Data pelanggan tidak ada
|
2025-07-05 14:59:01SV-DNY-Net-1 Data pelanggan tidak ada
|
||||||
2025-07-05 14:49:01SV_NTA_2_Pasawahan Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:39:01SV_NTA_2_Pasawahan Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
SV_NTA_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
SV_NTA_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
SV-Cicukang Status koneksi tidak aktif atau interval tidak tersedia.
|
SV-Cicukang Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
RO-Bumdes-Mekarmanah Status koneksi tidak aktif atau interval tidak tersedia.
|
RO-Bumdes-Mekarmanah Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
RO-Pak-Kholiq Data pelanggan tidak ada
|
RO-Pak-Kholiq Data pelanggan tidak ada
|
||||||
2025-07-05 14:54:01RO-Dendrit-Net Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:44:01RO-Dendrit-Net Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
LJN.NS.CSR.NET Status koneksi tidak aktif atau interval tidak tersedia.
|
LJN.NS.CSR.NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
IVVINET-CBD Data pelanggan tidak ada
|
IVVINET-CBD Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01QONNET Data pelanggan tidak ada
|
2025-07-05 15:29:01QONNET Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01Mikrotik_X86 Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:29:01Mikrotik_X86 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
Mikrotik_BSW_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
Mikrotik_BSW_1 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
Mikrotik_Alea Status koneksi tidak aktif atau interval tidak tersedia.
|
Mikrotik_Alea Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
STANG Status koneksi tidak aktif atau interval tidak tersedia.
|
STANG Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
@@ -37,14 +37,14 @@ RO_Wargasari Status koneksi tidak aktif atau interval tidak tersedia.
|
|||||||
LJN_AGUNG Status koneksi tidak aktif atau interval tidak tersedia.
|
LJN_AGUNG Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
RNET-CMS Status koneksi tidak aktif atau interval tidak tersedia.
|
RNET-CMS Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
DCN-GB-CCR Data pelanggan tidak ada
|
DCN-GB-CCR Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01coba Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:29:01coba Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
412NET Status koneksi tidak aktif atau interval tidak tersedia.
|
412NET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
brf Status koneksi tidak aktif atau interval tidak tersedia.
|
brf Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
BMSNET Status koneksi tidak aktif atau interval tidak tersedia.
|
BMSNET Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
purabaya Status koneksi tidak aktif atau interval tidak tersedia.
|
purabaya Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
DCN-CO-GX4 Data pelanggan tidak ada
|
DCN-CO-GX4 Data pelanggan tidak ada
|
||||||
2025-07-05 14:39:01MIKROTIK GX4 Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:29:01MIKROTIK GX4 Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
RO - Netborhood Wifi Status koneksi tidak aktif atau interval tidak tersedia.
|
RO - Netborhood Wifi Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
SV-DNY-Net-2 Data pelanggan tidak ada
|
SV-DNY-Net-2 Data pelanggan tidak ada
|
||||||
2025-07-05 14:49:01DNY-Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
2025-07-05 15:39:01DNY-Neglasari Status koneksi tidak aktif atau interval tidak tersedia.
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
|
Successfully started background process for IP: tunnel.manjapro.net
|
||||||
|
Successfully started background process for IP: 103.242.104.69
|
||||||
Successfully started background process for IP: 103.26.176.93
|
Successfully started background process for IP: 103.26.176.93
|
||||||
Started parallel processes for checking vouchers. => 2025-07-05 15:09:02
|
Started parallel processes for checking vouchers. => 2025-07-05 15:57:01
|
||||||
@@ -18,31 +18,3 @@ LJN.NS.CSR.NET =><br>
|
|||||||
IVVINET-CBD =><br>
|
IVVINET-CBD =><br>
|
||||||
QONNET =><br>
|
QONNET =><br>
|
||||||
Mikrotik_X86 =><br>
|
Mikrotik_X86 =><br>
|
||||||
Mikrotik_BSW_1 =><br>
|
|
||||||
Mikrotik_Alea =><br>
|
|
||||||
STANG =><br>
|
|
||||||
UNIX-NET =><br>
|
|
||||||
SV_NTA_2_TBL =><br>
|
|
||||||
MULYANAJAYA =><br>
|
|
||||||
PERWASIM.NET =><br>
|
|
||||||
RO_MELDINA =><br>
|
|
||||||
RO_LIPPY =><br>
|
|
||||||
RO_Asep =><br>
|
|
||||||
BATUNUNGGAL =><br>
|
|
||||||
PADINET =><br>
|
|
||||||
RAGILNET =><br>
|
|
||||||
RO_Sukasari =><br>
|
|
||||||
RO_Wargasari =><br>
|
|
||||||
LJN_AGUNG =><br>
|
|
||||||
RNET-CMS =><br>
|
|
||||||
DCN-GB-CCR =><br>
|
|
||||||
412NET =><br>
|
|
||||||
brf =><br>
|
|
||||||
BMSNET =><br>
|
|
||||||
purabaya =><br>
|
|
||||||
DCN-CO-GX4 =><br>
|
|
||||||
MIKROTIK GX4 =><br>
|
|
||||||
RO - Netborhood Wifi =><br>
|
|
||||||
Neglasari =><br>
|
|
||||||
SV-DNY-Net-2 =><br>
|
|
||||||
DNY-Neglasari =><br>
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,8 +0,0 @@
|
|||||||
2025-05-25 09:22:06 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-25 09:22:16 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-25 09:22:26 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-25 09:22:36 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-30 22:04:51 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-30 22:05:01 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-30 22:05:11 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
2025-05-30 22:05:21 Exception ResponAI: SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'nomor_whatsapp' at row 1
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
include __DIR__ . "/../../config/whatsapp_api.php";
|
|
||||||
include __DIR__ . "/respon_ai.php";
|
|
||||||
|
|
||||||
// Setup error reporting untuk debugging
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
// Simpan log raw input untuk debug paling awal
|
|
||||||
// file_put_contents(__DIR__ . "/debug_raw_input.log", date('Y-m-d H:i:s') . " Input:\n" . print_r(file_get_contents('php://input'), true) . "\n", FILE_APPEND);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Ambil dan decode input JSON
|
|
||||||
$data = file_get_contents('php://input');
|
|
||||||
$json_data = json_decode($data, true);
|
|
||||||
|
|
||||||
if (!isset($json_data['results']['apiKey'])) {
|
|
||||||
http_response_code(400);
|
|
||||||
echo "apiKey tidak ditemukan.";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$apiKey = $json_data['results']['apiKey'];
|
|
||||||
|
|
||||||
// file_put_contents(__DIR__ . "/debug_apikey.log", date('Y-m-d H:i:s') . " apiKey: $apiKey\n", FILE_APPEND);
|
|
||||||
|
|
||||||
if (
|
|
||||||
isset($json_data['type']) && $json_data['type'] === 'message' &&
|
|
||||||
isset($json_data['results']['fromMe']) && $json_data['results']['fromMe'] === false &&
|
|
||||||
isset($json_data['results']['isGroupMsg']) && $json_data['results']['isGroupMsg'] === false
|
|
||||||
) {
|
|
||||||
$sender = $json_data['results']['sender'] ?? 'Tidak diketahui';
|
|
||||||
$sender = str_replace("@s.whatsapp.net", "", $sender);
|
|
||||||
$body = $json_data['results']['body'] ?? '';
|
|
||||||
|
|
||||||
// file_put_contents(__DIR__ . "/debug_sender_body.log", date('Y-m-d H:i:s') . " Sender: $sender, Body: $body\n", FILE_APPEND);
|
|
||||||
|
|
||||||
$filtered = [
|
|
||||||
'sender' => $sender,
|
|
||||||
'body' => $body,
|
|
||||||
'apiKey' => $apiKey
|
|
||||||
];
|
|
||||||
|
|
||||||
$log_file = __DIR__ . "/" . $apiKey . ".log";
|
|
||||||
$log_entry = "[" . date('Y-m-d H:i:s') . "] Masuk: " . print_r($filtered, true);
|
|
||||||
|
|
||||||
// Pastikan kelas ResponAI ada
|
|
||||||
if (!class_exists('ResponAI')) {
|
|
||||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Class ResponAI tidak ditemukan!\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
exit("Server error: ResponAI class missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
$ResAI = new ResponAI();
|
|
||||||
|
|
||||||
// Tangkap exception saat proses respon_chat
|
|
||||||
try {
|
|
||||||
$Respon = $ResAI->respon_chat($body, $sender, $apiKey);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Exception ResponAI: " . $e->getMessage() . "\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
exit("Server error: gagal proses AI");
|
|
||||||
}
|
|
||||||
|
|
||||||
// file_put_contents(__DIR__ . "/step2_respon_ai.log", date('Y-m-d H:i:s') . " " . print_r($Respon, true), FILE_APPEND);
|
|
||||||
|
|
||||||
if (!empty($Respon['id']) && !empty($Respon['nomor'])) {
|
|
||||||
if (!class_exists('PesanWA')) {
|
|
||||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Class PesanWA tidak ditemukan!\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
exit("Server error: PesanWA class missing");
|
|
||||||
}
|
|
||||||
|
|
||||||
$API_WA = new PesanWA();
|
|
||||||
|
|
||||||
try {
|
|
||||||
$send_result = $API_WA->Send_Pesan($Respon['id'], 'sendMessage', array($Respon['nomor']), $Respon['respon']);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Exception Send_Pesan: " . $e->getMessage() . "\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
exit("Server error: gagal kirim pesan");
|
|
||||||
}
|
|
||||||
|
|
||||||
// file_put_contents(__DIR__ . "/step3_send_pesan.log", date('Y-m-d H:i:s') . " Kirim pesan ke: {$Respon['nomor']}\nResponse Send_Pesan: " . print_r($send_result, true), FILE_APPEND);
|
|
||||||
|
|
||||||
$log_entry .= "[" . date('Y-m-d H:i:s') . "] Balasan AI: " . print_r($Respon, true) . PHP_EOL;
|
|
||||||
// file_put_contents($log_file, $log_entry, FILE_APPEND);
|
|
||||||
|
|
||||||
http_response_code(200);
|
|
||||||
exit;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// file_put_contents(__DIR__ . "/error_send_pesan.log", date('Y-m-d H:i:s') . " Gagal kirim pesan, id atau nomor kosong: " . print_r($Respon, true) . "\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
echo "Gagal mengirim pesan: data tidak lengkap.";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
http_response_code(400);
|
|
||||||
echo "Data tidak valid atau bukan pesan yang diinginkan.";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
} catch (Throwable $t) {
|
|
||||||
// Tangkap semua error fatal / throwable
|
|
||||||
file_put_contents(__DIR__ . "/error.log", date('Y-m-d H:i:s') . " Fatal error: " . $t->getMessage() . "\n", FILE_APPEND);
|
|
||||||
http_response_code(500);
|
|
||||||
echo "Server error: " . $t->getMessage();
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
@@ -1,276 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class ResponAI {
|
|
||||||
|
|
||||||
private function connectDB() {
|
|
||||||
include __DIR__ . "/../../config/connect.php"; // Harus mengisi $pdo
|
|
||||||
return $pdo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function deteksi_topik($message) {
|
|
||||||
$rules = [
|
|
||||||
'gangguan' => ['lambat', 'tidak konek', 'jaringan', 'trouble', 'gangguan', 'internet mati'],
|
|
||||||
'tagihan' => ['tagihan', 'bayar', 'invoice', 'pembayaran', 'rekening'],
|
|
||||||
'pemasangan' => ['pasang', 'berlangganan', 'pemasangan', 'registrasi', 'daftar', 'masang'],
|
|
||||||
'umum' => []
|
|
||||||
];
|
|
||||||
|
|
||||||
$message = strtolower($message);
|
|
||||||
foreach ($rules as $topik => $keywords) {
|
|
||||||
foreach ($keywords as $keyword) {
|
|
||||||
if (strpos($message, $keyword) !== false) {
|
|
||||||
return $topik;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 'umum';
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_data_pelanggan($sender) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT nama, nama_paket, status, akun, status_koneksi FROM v_pelanggan WHERE nomor_whatsapp = ?");
|
|
||||||
$stmt->execute([$sender]);
|
|
||||||
$pelanggan = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if ($pelanggan) {
|
|
||||||
return "Pelanggan atas nama {$pelanggan['nama']} (ID: {$pelanggan['akun']}) menggunakan paket {$pelanggan['nama_paket']} dan status koneksi {$pelanggan['status_koneksi']}. Status langganan: {$pelanggan['status']}.";
|
|
||||||
}
|
|
||||||
return "Data pelanggan tidak ditemukan.";
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_id_server($apikey_wa) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT id FROM data_server WHERE apikey_whatsapp = ?");
|
|
||||||
$stmt->execute([$apikey_wa]);
|
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
return $row['id'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_paket_berlangganan($id) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT nama, harga_paket FROM profile_paket WHERE id_data_server = ?");
|
|
||||||
$stmt->execute([$id]);
|
|
||||||
$pakets = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if (!$pakets) return "Paket berlangganan belum tersedia.";
|
|
||||||
$list = "Berikut adalah daftar paket layanan:\n";
|
|
||||||
foreach ($pakets as $p) {
|
|
||||||
$list .= "- {$p['nama']}: Rp " . number_format($p['harga_paket'], 0, ',', '.') . "\n";
|
|
||||||
}
|
|
||||||
return trim($list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function haversine($lat1, $lon1, $lat2, $lon2) {
|
|
||||||
$earthRadius = 6371;
|
|
||||||
$dLat = deg2rad($lat2 - $lat1);
|
|
||||||
$dLon = deg2rad($lon2 - $lon1);
|
|
||||||
|
|
||||||
$a = sin($dLat / 2) ** 2 + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) ** 2;
|
|
||||||
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
|
||||||
return $earthRadius * $c;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_info_pemasangan($id, $lat = null, $lon = null) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
|
|
||||||
$stmt1 = $pdo->prepare("SELECT harga_sewa FROM data_server WHERE id = ?");
|
|
||||||
$stmt1->execute([$id]);
|
|
||||||
$row = $stmt1->fetch(PDO::FETCH_ASSOC);
|
|
||||||
$biaya = isset($row['harga_sewa']) ? "Biaya pemasangan sebesar Rp " . number_format($row['harga_sewa'], 0, ',', '.') . "." : "";
|
|
||||||
|
|
||||||
$stmt2 = $pdo->prepare("SELECT nama FROM master_desa WHERE id_data_server = ?");
|
|
||||||
$stmt2->execute([$id]);
|
|
||||||
$desas = $stmt2->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
$wilayah = $desas ? implode(", ", array_column($desas, 'nama')) : "Wilayah layanan belum terdaftar.";
|
|
||||||
|
|
||||||
$stmt3 = $pdo->prepare("SELECT titik_koordinat FROM master_topologi WHERE id_data_server = ?");
|
|
||||||
$stmt3->execute([$id]);
|
|
||||||
$koordinats = $stmt3->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if ($lat !== null && $lon !== null && $koordinats) {
|
|
||||||
foreach ($koordinats as $k) {
|
|
||||||
$raw = $k['titik_koordinat'];
|
|
||||||
|
|
||||||
// Cek apakah tidak kosong dan mengandung koma
|
|
||||||
if (!empty($raw) && strpos($raw, ',') !== false) {
|
|
||||||
$parts = explode(',', $raw);
|
|
||||||
|
|
||||||
// Pastikan hasil explode memiliki dua elemen
|
|
||||||
if (count($parts) === 2) {
|
|
||||||
$latParsed = trim($parts[0]);
|
|
||||||
$lonParsed = trim($parts[1]);
|
|
||||||
|
|
||||||
// Validasi bahwa lat dan lon adalah angka
|
|
||||||
if (is_numeric($latParsed) && is_numeric($lonParsed)) {
|
|
||||||
$distance = $this->haversine($lat, $lon, (float)$latParsed, (float)$lonParsed);
|
|
||||||
if ($distance <= 0.3) {
|
|
||||||
$formulir = "Anda berada dalam jangkauan layanan kami.\n\nSilakan lengkapi data berikut untuk registrasi:\n"
|
|
||||||
. "- Nama lengkap\n"
|
|
||||||
. "- NIK\n"
|
|
||||||
. "- Alamat Lengkap\n"
|
|
||||||
. "- Titik Koordinat\n"
|
|
||||||
. "- Nomor WhatsApp\n"
|
|
||||||
. "- Paket Layanan";
|
|
||||||
return "$biaya\n$formulir";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "Mohon maaf, titik koordinat Anda belum terjangkau jaringan kami.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "$biaya Wilayah layanan mencakup: $wilayah.\n\nSilakan kirimkan titik koordinat lokasi Anda agar kami bisa melakukan pengecekan jangkauan.";
|
|
||||||
}
|
|
||||||
|
|
||||||
private function get_data_tagihan($sender) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT nama, total_tagihan, limit_pembayaran, tanggal_bayar, status FROM v_tagihan WHERE nomor_whatsapp = ? ORDER BY tanggal_bayar DESC");
|
|
||||||
$stmt->execute([$sender]);
|
|
||||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if (!$rows) return "Tidak ada tagihan yang ditemukan.";
|
|
||||||
$list = "Riwayat tagihan:\n";
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
$list .= "- Tagihan: Rp " . number_format($row['total_tagihan'], 0, ',', '.') . " | Jatuh Tempo: {$row['limit_pembayaran']} | Status: {$row['status']}\n";
|
|
||||||
}
|
|
||||||
return trim($list);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function simpan_sesi($sender, $topik) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO chat_session (nomor_whatsapp, topik_terakhir) VALUES (?, ?) ON DUPLICATE KEY UPDATE topik_terakhir = VALUES(topik_terakhir)");
|
|
||||||
$stmt->execute([$sender, $topik]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function ambil_sesi($sender) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT topik_terakhir FROM chat_session WHERE nomor_whatsapp = ?");
|
|
||||||
$stmt->execute([$sender]);
|
|
||||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
return $row['topik_terakhir'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function simpan_log($sender, $role, $pesan, $id) {
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("INSERT INTO chat_log (nomor_whatsapp, role, pesan, id_data_server) VALUES (?, ?, ?, ?)");
|
|
||||||
$stmt->execute([$sender, $role, $pesan, $id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function respon_chat($message, $sender, $apikey_wa) {
|
|
||||||
$OPENAI_API_KEY = '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'; // Ganti dengan API key valid
|
|
||||||
$id = $this->get_id_server($apikey_wa);
|
|
||||||
|
|
||||||
if (empty($message) || empty($sender) || !$id) {
|
|
||||||
return [
|
|
||||||
'id' => $id,
|
|
||||||
'nomor' => $sender,
|
|
||||||
'respon' => 'Input tidak valid atau data server tidak ditemukan.'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$topik = $this->deteksi_topik($message);
|
|
||||||
$topik_sesi = $this->ambil_sesi($sender);
|
|
||||||
if (!$topik && $topik_sesi) {
|
|
||||||
$topik = $topik_sesi;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($topik) {
|
|
||||||
$this->simpan_sesi($sender, $topik);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->simpan_log($sender, 'user', $message, $id);
|
|
||||||
|
|
||||||
$pdo = $this->connectDB();
|
|
||||||
$stmt = $pdo->prepare("SELECT role, pesan FROM chat_log WHERE id_data_server = ? AND nomor_whatsapp = ? ORDER BY id DESC LIMIT 10");
|
|
||||||
$stmt->execute([$id, $sender]);
|
|
||||||
$riwayat = array_reverse($stmt->fetchAll(PDO::FETCH_ASSOC));
|
|
||||||
|
|
||||||
$messages = [];
|
|
||||||
foreach ($riwayat as $log) {
|
|
||||||
$messages[] = ['role' => $log['role'], 'content' => $log['pesan']];
|
|
||||||
}
|
|
||||||
$messages[] = ['role' => 'user', 'content' => $message];
|
|
||||||
|
|
||||||
$data_pelanggan = $this->get_data_pelanggan($sender);
|
|
||||||
$info_paket = $this->get_paket_berlangganan($id);
|
|
||||||
$info_pasang = $this->get_info_pemasangan($id);
|
|
||||||
$data_tagihan = $this->get_data_tagihan($sender);
|
|
||||||
|
|
||||||
$roles = [
|
|
||||||
'gangguan' => 'Kamu adalah customer service penyedia layanan internet untuk masalah teknis.',
|
|
||||||
'tagihan' => 'Kamu adalah customer service penyedia layanan internet untuk urusan tagihan.',
|
|
||||||
'pemasangan' => 'Kamu adalah customer service penyedia layanan internet untuk pemasangan baru.',
|
|
||||||
'umum' => 'Kamu adalah customer service penyedia layanan internet untuk pertanyaan umum.'
|
|
||||||
];
|
|
||||||
|
|
||||||
$topik_final = $topik ?: 'umum';
|
|
||||||
|
|
||||||
switch ($topik_final) {
|
|
||||||
case 'tagihan':
|
|
||||||
$tambahan = $data_tagihan;
|
|
||||||
break;
|
|
||||||
case 'pemasangan':
|
|
||||||
$tambahan = $info_paket . "\n" . $info_pasang;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$tambahan = '';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$system_message = $roles[$topik_final] . " Data pelanggan: $data_pelanggan\n$tambahan\nJawaban maksimal 3 kalimat, singkat, sopan, dan informatif.";
|
|
||||||
array_unshift($messages, ['role' => 'system', 'content' => $system_message]);
|
|
||||||
|
|
||||||
$payload = [
|
|
||||||
'model' => 'gpt-3.5-turbo',
|
|
||||||
'messages' => $messages,
|
|
||||||
'temperature' => 0.7,
|
|
||||||
'max_tokens' => 100
|
|
||||||
];
|
|
||||||
|
|
||||||
$ch = curl_init('https://api.openai.com/v1/chat/completions');
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_POST, true);
|
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
'Content-Type: application/json',
|
|
||||||
'Authorization: Bearer ' . $OPENAI_API_KEY,
|
|
||||||
]);
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
|
||||||
|
|
||||||
if (curl_errno($ch)) {
|
|
||||||
$error = curl_error($ch);
|
|
||||||
curl_close($ch);
|
|
||||||
return [
|
|
||||||
'id' => $id,
|
|
||||||
'nomor' => $sender,
|
|
||||||
'respon' => 'Terjadi kesalahan koneksi ke OpenAI: ' . $error
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
$data = json_decode($response, true);
|
|
||||||
|
|
||||||
$reply = $data['choices'][0]['message']['content'] ?? 'Maaf, tidak dapat memberikan jawaban saat ini.';
|
|
||||||
$this->simpan_log($sender, 'assistant', $reply, $id);
|
|
||||||
|
|
||||||
$hasil = [
|
|
||||||
'id' => $id,
|
|
||||||
'nomor' => $sender,
|
|
||||||
'respon' => trim($reply)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Debug log
|
|
||||||
// file_put_contents("debug_respon_chat.log",
|
|
||||||
// "====\n[" . date("Y-m-d H:i:s") . "]\n".
|
|
||||||
// "Payload:\n" . print_r($payload, true) .
|
|
||||||
// "Response:\n" . print_r($data, true) .
|
|
||||||
// "Final:\n" . print_r($hasil, true),
|
|
||||||
// FILE_APPEND
|
|
||||||
// );
|
|
||||||
|
|
||||||
return $hasil;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
// Menangkap data JSON dari webhook
|
|
||||||
$data = file_get_contents('php://input');
|
|
||||||
|
|
||||||
// Decode JSON untuk membaca isinya
|
|
||||||
$json_data = json_decode($data, true);
|
|
||||||
|
|
||||||
// Validasi payload JSON
|
|
||||||
if (isset($json_data['results']['apiKey'])) {
|
|
||||||
$apiKey = $json_data['results']['apiKey'];
|
|
||||||
|
|
||||||
// Periksa jika bukan pesan grup
|
|
||||||
if (isset($json_data['results']['isGroupMsg']) && $json_data['results']['isGroupMsg'] === false) {
|
|
||||||
// Nama file log berdasarkan apiKey
|
|
||||||
$log_file = $apiKey . ".log";
|
|
||||||
|
|
||||||
// Menambahkan data baru dengan waktu (opsional)
|
|
||||||
$log_entry = "[" . date('Y-m-d H:i:s') . "] " . $data . PHP_EOL;
|
|
||||||
|
|
||||||
// Simpan ke file log sesuai apiKey
|
|
||||||
if (file_put_contents($log_file, $log_entry, FILE_APPEND) !== false) {
|
|
||||||
// Tanggapan ke pengirim webhook
|
|
||||||
http_response_code(200);
|
|
||||||
echo "Data webhook diterima dan disimpan di $log_file";
|
|
||||||
} else {
|
|
||||||
// Gagal menyimpan file log
|
|
||||||
http_response_code(500);
|
|
||||||
echo "Gagal menyimpan data ke file log.";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Pesan grup tidak diproses
|
|
||||||
http_response_code(400);
|
|
||||||
echo "Pesan grup tidak diproses.";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Jika `apiKey` tidak ditemukan
|
|
||||||
http_response_code(400);
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
Reference in New Issue
Block a user