first commit

This commit is contained in:
2026-10-29 13:34:31 +07:00
commit 45e4595c57
255 changed files with 35457 additions and 0 deletions
+381
View File
@@ -0,0 +1,381 @@
<?php
/*******************************************************************
PHP Class : /Controller/Ppob/PrabayarController
Description : Transaksi Prabayar PPOB
Created By : Siau Pheng ([email protected]).
Created Date : March 15th, 2017.
Last Modified : September 16th, 2026.
(c) 3FONIA Software; WWW.3FONIA.COM.
*******************************************************************/
declare(strict_types=1);
namespace App\Controller\Ppob;
use App\Utils\PPOBClient;
use flight\Engine;
use flight\database\SimplePdo;
use flight\Session;
use Webapp\DB\SQL;
use Webapp\Web\Form;
use Webapp\Web\Param;
use Webapp\Web\Table;
class PrabayarController {
private array $web_app;
private int $id_cab;
private string $mode;
private string $mode_detail;
private string $no_tx;
private int $id_kate;
private int $id_ope;
private int $id_produk;
private string $tujuan;
private string $no_hp;
private PPOBClient $ppob;
protected Engine $app;
protected SimplePdo $db;
public function __construct(Engine $app, SimplePdo $db, Session $session) {
$this->app = $app;
$this->db = $db;
$this->web_app = (array) $session->get('WEB_APP');
$this->id_cab = Param::Int("CabID", (int) $session->get('APP_INV')['CABANGID']);
$this->mode = Param::Get("mode", "");
$this->mode_detail = Param::Get("mode_detail", "");
$this->no_tx = Param::Get("No_TX", "");
$this->id_kate = Param::Int("KateID", 0);
$this->id_ope = Param::Int("OpeID", 0);
$this->id_produk = Param::Int("ProdukID", 0);
$this->tujuan = Param::Get("Tujuan", "");
$this->no_hp = Param::Get("No_HP", "");
$this->ppob = new PPOBClient($app);
}
public function table_tx() {
if (in_array($this->mode_detail, ["reproc","delete"])) {
$adetail = $this->db->fetchRow("SELECT * FROM ppob_tx WHERE No_TX=?", [$this->no_tx]);
$proses = (int) $adetail['Proses'] ?? 0;
if ($this->mode_detail === "delete") {
if ($proses === 0) {
$this->db->delete("ppob_tx", "No_TX=?", [$this->no_tx]);
$ajson[] = ['type'=>"msg", 'mode'=>"info", 'wait'=>2000, 'value'=>"Transaksi sukses dihapus !"];
} else {
$ajson[] = ['type'=>"msg", 'mode'=>"error", 'wait'=>2000, 'value'=>"Ada masalah dalam proses transaksi !"];
}
} else if ($this->mode_detail === "reproc") {
if ($proses === 0) {
// PROSES API TRIFONIA PULSA
$appob = $this->ppob->TopUp($adetail['Kode'], $adetail['Tujuan'], $adetail['No_TX'], $adetail['No_HP']);
if (count($appob) > 0) {
$ajson[] = ['type'=>"msg", 'mode'=>"info", 'wait'=>2000, 'value'=>$appob['Message']];
}
} else {
$ajson[] = ['type'=>"msg", 'mode'=>"error", 'wait'=>2000, 'value'=>"Ada masalah dalam Proses !"];
}
}
}
$tcari = Param::Get("Cari_PPOB", "");
$tsql = 'CabID=?'; $asql = [$this->id_cab];
if (empty($tcari)) {
$tsql .= " AND UserID=? AND Tgl_TX=?";
array_push($asql, $this->app->user()->id(), tgl_ymd());
} else {
$tsql .= " AND CONCAT(No_TX,Tujuan,No_HP,DATE_FORMAT(Tgl_TX,'%d-%m-%Y')) LIKE ?";
$asql[] = '%' . $tcari . '%';
}
$obj = new Table($this->app);
$obj->set_table("(SELECT *,CONCAT(DATE_FORMAT(DateStamp,'%d-%m-%Y %H:%i:%s'),' - ',Kode,'<br><b>',Tujuan,'</b>',IF(No_HP='','',CONCAT('<br><i>HP : ',No_HP,'</i>'))) Info_TX FROM ppob_tx WHERE ".$tsql.") T LEFT JOIN (SELECT ProdukID,KateID FROM ppob_produk) P ON (P.ProdukID=T.ProdukID)", "T.*,IFNULL(P.KateID,0) KateID", "", $asql);
$obj->set_footer("SUM(Harga_Jual) Harga_Jual");
$obj->add_field("No_TX", "No. TX", "c");
$obj->add_field("KateID", "Kate", "c", "App\Utils\PPOBClient::Icon_Kate");
$obj->add_field("Info_TX", "Informasi Transaksi", "l");
$obj->add_field("Harga_Jual", "Harga", "r", "rupiah", "rupiah");
$obj->add_field("Proses", "P", "c", "checkbox");
$obj->add_field("Status", "Status", "c", "App\Utils\PPOBClient::Badge_Status");
$obj->set_field_order("No_TX", "D");
$obj->add_row_btn("printer", "Cetak Nota", "PrabayarJS.nota_print", "Status", 4);
$obj->add_row_btn("arrow-left-right", "Proses Ulang", "PrabayarJS.nota_reproc", "Proses", 0);
$obj->add_row_btn("clipboard", "Detail", "PrabayarJS.nota_detail", "Proses", 1);
if ($this->app->user()->is_level(1)) $obj->add_row_btn("trash", "Hapus", "PrabayarJS.nota_delete", "Status", 0);
$this->app->json([ $obj->json_table("divPOS1", 5) ]);
}
public function form_master() {
$tkembali = "0";
if ($this->mode === "save") {
$this->no_tx = $this->ppob->Nomor_Baru("P", tgl_dmy());
$no_seq = $this->db->fetchField("SELECT COALESCE(MAX(Counter),0)+1 Seq_TX FROM ppob_tx WHERE Tgl_TX=? AND ProdukID=? AND Tujuan=?", [tgl_ymd(), $this->id_produk, $this->tujuan]) ?? 1;
$id_kartu = Param::Int("KartuID", 0);
$no_kartu = ""; $nama_kartu = "";
if ($id_kartu > 0) {
$no_kartu = Param::Get("No_Kartu", "");
$nama_kartu = Param::Get("Nama_Kartu", "");
}
$apul = $this->db->fetchRow("SELECT * FROM ppob_produk WHERE ProdukID=?", [$this->id_produk]);
$sql = new SQL($this->app);
$sql->set_table("ppob_tx");
$sql->add_param("No_TX", $this->no_tx);
$sql->add_param_date("Tgl_TX", tgl_dmy());
$sql->add_param("CabID", $this->id_cab);
$sql->add_param("ProdukID");
$sql->add_param("Kode", $apul['Kode']);
$sql->add_param("Tujuan");
$sql->add_param("No_HP");
$sql->add_param("Counter", $no_seq);
$sql->add_param("Harga_Beli", $apul['Harga_Pokok']);
$sql->add_param("Harga_Jual", $apul['Harga_Jual']);
$sql->add_param("Total_Bayar");
$sql->add_param("KartuID", $id_kartu);
$sql->add_param("No_Kartu", $no_kartu);
$sql->add_param("Nama_Kartu", $nama_kartu);
$sql->add_param_userid();
$sql->InsertDB();
$this->mode = "reproc";
$tkembali = '<span style="color:red;">'.rupiah($apul['Harga_Jual']-Param::Get("Total_Bayar",0)).'</span>';
//jika token pln
if (($apul['KateID'] ?? 0) === 5) {
$this->db->runQuery("INSERT IGNORE INTO ppob_pend (No_TX,CabID,UserID) VALUES (?, ?, ?)", [$this->no_tx, $this->id_cab, $this->app->user()->id()]);
}
}
$form = new Form($this->app);
$tkate = $form->option_que("_", "KateID", $this->id_kate, true, false, "SELECT * FROM ppob_kategori WHERE KateID IN (SELECT KateID FROM ppob_produk WHERE Status=1 AND Harga_Jual>0)", ["KateID","N_Kate"], null, null, "PrabayarJS.oc_KateID");
$tope = $form->option("_", "OpeID", 0, true, false, [0=>""], null, "PrabayarJS.oc_OpeID");
$tproduk = $form->option("_", "ProdukID", 0, true, false, [0=>""], null, "PrabayarJS.oc_ProdukID");
$ttujuan = $form->textbox("_", "Tujuan", "", true, true, "phone", "Ketik Nomor Tujuan");
$tno_hp = $form->textbox("_", "No_HP", "", true, true, "phone", "no hp untuk pengiriman kode token");
$ajson['html'] = '
<div class="row mb-3">
<div class="col-6">
<div class="card bg-light"><img class="img-fluid p-1" src="'.PROJECT_BASE.'assets/images/logo60.png" style="opacity:.75;"></div>
</div>
<div class="col-6">
<div class="border border-success rounded pe-2 display-6 text-end" id="Total_Disp">'.$tkembali.'</div>
</div>
</div>
<div class="row mb-2">
<label class="col-sm-4 col-lg-3 col-form-label" for="KateID">Kategori PPOB</label>
<div class="col">'.$tkate.'</div>
</div>
<div class="row mb-2">
<label class="col-sm-4 col-lg-3 col-form-label" for="Tujuan">Nomor Tujuan</label>
<div class="col">'.$ttujuan.'</div>
</div>
<div class="row mb-2 rowToken">
<label class="col-sm-4 col-lg-3 col-form-label" for="No_HP">Nomor HP</label>
<div class="col">'.$tno_hp.'</div>
</div>
<div class="row mb-2 rowPulsa">
<label class="col-sm-4 col-lg-3 col-form-label" for="OpeID">Operator</label>
<div class="col">'.$tope.'</div>
</div>
<div class="row mb-2">
<label class="col-sm-4 col-lg-3 col-form-label" for="ProdukID">Produk</label>
<div class="col">'.$tproduk.'</div>
</div>
<div class="row mt-3">
<div class="col-sm-6 col-lg-4">
</div>
<div class="col-sm-6 col-lg-4 d-grid">
<button type="button" class="btn btn-danger" id="ppobBATAL"><i class="bi-x-lg me-1"></i>Batal</button>
</div>
<div class="col-sm-6 col-lg-4 d-grid">
<button type="button" class="btn btn-success" id="ppobSIMPAN"><i class="bi-cart-plus me-1"></i>Bayar</button>
</div>
</div>
<input type="hidden" id="No_TX" value="'.$this->no_tx.'" />
<input type="hidden" id="Harga_Jual" value="0" />
<input type="hidden" id="Total_Tunai" value="0" />
<input type="hidden" id="Total_Kartu" value="0" />
<input type="hidden" id="Total_Bayar" value="0" />
<input type="hidden" id="KartuID" value="0" />
<input type="hidden" id="No_Kartu" value="" />
<input type="hidden" id="Nama_Kartu" value="" />
<input type="hidden" id="mode" value="'.$this->mode.'" />';
$this->app->json($ajson);
}
public function form_tx() {
$ainfo = $this->db->fetchRow("SELECT T.*,DATE_FORMAT(T.DateStamp,'%d-%m-%Y %H:%i:%s') Tgl_TX1,IFNULL(P.KateID,0) KateID,P.Nama_Produk FROM (SELECT * FROM ppob_tx WHERE No_TX=? LIMIT 1) T LEFT JOIN ppob_produk P ON (P.ProdukID=T.ProdukID)", [$this->no_tx]) ?? ['No_TX'=>$this->no_tx, 'Tgl_TX1'=>tgl_dmy(true), 'Tujuan'=>"", 'No_HP'=>"", 'Nama_Produk'=>"", 'Harga_Jual'=>0, 'Status'=>0, 'KateID'=>0];
$atoken = $this->ppob->SN_PLN($ainfo['SN']);
$ajson['html'] = '
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Nomor TX</label>
<label class="col-sm-12 col-lg-7 col-form-label"><strong>'.$ainfo['No_TX'].'</strong></label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Tanggal TX</label>
<label class="col-sm-12 col-lg-7 col-form-label"><strong>'.$ainfo['Tgl_TX1'].'</strong></label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Nomor Tujuan</label>
<label class="col-sm-12 col-lg-7 col-form-label"><strong>'.$ainfo['Tujuan'].'</strong></label>
</div>
<div class="row text-start'.($ainfo['KateID']==5?'':' d-none').'">
<label class="col-sm-12 col-lg-5 col-form-label">Nomor HP</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.($ainfo['No_HP']==""?"<i>tidak tersedia</i>":$ainfo['No_HP']).'</label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Nama Produk</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.$ainfo['Nama_Produk'].'</label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Harga Jual</label>
<label class="col-sm-12 col-lg-7 col-form-label"><strong>Rp. '.rupiah($ainfo['Harga_Jual']).'</strong></label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Status TX</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.$this->ppob->Badge_Status($ainfo['Status']).'</label>
</div>';
if ((int) $ainfo['KateID'] === 5 && (int) $ainfo['Status'] === 4) {
$ajson['html'] .= '
<div class="row mt-1"><div class="col"><hr class="my-2"></div></div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Nama Pelanggan</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.$atoken['Nama'].'</label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Tarif / Daya</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.$atoken['Daya'].'</label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Nilai Token</label>
<label class="col-sm-12 col-lg-7 col-form-label">'.$atoken['Kwh'].'</label>
</div>
<div class="row text-start">
<label class="col-sm-12 col-lg-5 col-form-label">Kode Token</label>
<label class="col-sm-12 col-lg-7 col-form-label"><strong>'.$atoken['Token'].'</strong></label>
</div>';
}
$this->app->json($ajson);
}
public function form_kasir() {
$tot_jual = Param::Float("Harga_Jual", 0);
$form = new Form($this->app);
$tjual = $form->textbox("_", "popTotal_Jual", uang($tot_jual), false, false, "double");
$ttunai = $form->textbox("_", "popTotal_Tunai", 0, true, false, "double");
$tkartu = $form->textbox("_", "popTotal_Kartu", 0, true, false, "double");
$tsisa = $form->textbox("_", "popTotal_Sisa", 0, false, false, "double");
$okartu = $form->option_db("_", "popKartuID", 0, true, false, "para_rek_pos", ["KartuID","Kode_Kartu"], "Aktif=1", [0,"Pilihan Non Tunai"]);
$tnokartu = $form->textbox("_", "popNo_Kartu", "", true, false, "text");
$tnamakartu = $form->textbox("_", "popNama_Kartu", "", true, false, "text");
$ajson['html'] = '
<div class="row mb-1"><div class="col-sm-6 col-lg-5 col-form-label">Total PPOB Rp.</div><div class="col-sm-6 col-lg-7">'.$tjual.'</div></div>
<div class="row mb-1"><div class="col-sm-6 col-lg-5 col-form-label">Tunai Rp.</div><div class="col-sm-6 col-lg-7">'.$ttunai.'</div></div>
<div class="row mb-1"><div class="col-sm-6 col-lg-5">'.$okartu.'</div><div class="col-sm-6 col-lg-7">'.$tkartu.'</div></div>
<div class="row mb-1"><div class="col-sm-6 col-lg-5 col-form-label">Kembali Rp.</div><div class="col-sm-6 col-lg-7">'.$tsisa.'</div></div>
<hr class="my-2 ckartu d-none">
<div class="row mb-1 ckartu d-none"><div class="col-sm-6 col-lg-5 col-form-label">Nomor Kartu</div><div class="col-sm-6 col-lg-7">'.$tnokartu.'</div></div>
<div class="row mb-1 ckartu d-none"><div class="col-sm-6 col-lg-5 col-form-label">Nama Pemilik</div><div class="col-sm-6 col-lg-7">'.$tnamakartu.'</div></div>
<hr class="my-2">
<div class="row mt-1">
<div class="col-6">&nbsp;</div>
<div class="col-3 d-grid"><button type="button" class="btn btn-danger" id="butKBatal" data-bs-dismiss="modal">Batal</button></div>
<div class="col-3 d-grid"><button type="button" class="btn btn-success" id="butKBayar">Bayar</button></div>
</div>
<input type="hidden" id="popTotal_Bayar" value="0" />';
$ajson['Total_Disp'] = rupiah($tot_jual);
$this->app->json($ajson);
}
public function option_operator() {
$aoption = ['type' => "option", 'id' => "OpeID", 'value' => 0, 'avalue' => []];
if ($this->id_kate === 5) {//token
$aoption['avalue'][] = ['value'=>10, 'html'=>"PLN Prabayar"];
} else if ($this->id_kate === 6) {//emoney & ojek
//todo: di update database, sesuaikan dg pola baru !
$aoption['avalue'][] = ['value'=>11, 'html'=>"OVO"];
$aoption['avalue'][] = ['value'=>12, 'html'=>"GoPay"];
$aoption['avalue'][] = ['value'=>13, 'html'=>"Gojek Driver"];
$aoption['avalue'][] = ['value'=>14, 'html'=>"Grab"];
$aoption['avalue'][] = ['value'=>15, 'html'=>"Dana"];
} else if ($this->id_kate === 8) {//voucher
$aoption['avalue'][] = ['value'=>0, 'html'=>""];
} else {//pulsa, data, sms, transfer
$tsql = (strlen($this->tujuan) >= 4) ? " AND Prefix_Ope LIKE '%".substr($this->tujuan,0,4)."%'" : "";
$aope = $this->db->fetchAll("SELECT * FROM ppob_operator WHERE OpeID IN (SELECT OpeID FROM ppob_produk WHERE Status=1 AND Harga_Jual>0 AND KateID<5)".$tsql);
if (count($aope) > 1) $aoption['avalue'][] = ['value'=>0, 'html'=>""];
foreach ($aope as $ope) {
if (count($aope) === 1) $aoption['value'] = $ope['OpeID'];
$aoption['avalue'][] = ['value'=>$ope['OpeID'], 'html'=>$ope['N_Ope']];
}
}
$this->app->json([ $aoption ]);
}
public function option_produk() {
$aoption = ['type' => "option", 'id' => "ProdukID", 'value' => 0, 'avalue' => [['value'=>0, 'label'=>0, 'html'=>""]]];
$aproduk = $this->db->fetchAll("SELECT * FROM ppob_produk WHERE Status=1 AND KateID=? AND OpeID=? AND Harga_Jual>0 ORDER BY Harga_Jual", [$this->id_kate, $this->id_ope]);
foreach ($aproduk as $produk) {
$aoption['avalue'][] = ['value'=>$produk['ProdukID'], 'label'=>$produk['Harga_Jual'], 'html'=>$produk['Nama_Produk'].' - Rp. '.rupiah($produk['Harga_Jual'])];
}
$this->app->json([ $aoption ]);
}
public function config_pole() {
$ajson['pole'] = [];
$apole = $this->db->fetchRow("SELECT * FROM disp_config WHERE REG_ID=?", [$this->web_app['APP_CODE']]);
foreach ($apole as $_key => $_val) {
if (str_contains($_key, "POLE")) {
if (str_contains($_key, "ENABLE")) $_val = (int) $_val;
$ajson['pole'][str_replace("POLE_","",$_key)] = $_val;
}
}
$this->app->json($ajson);
}
public function index() {
$this->app->json(['html' => '
<div class="fade-in">
<div class="card"><div class="card-body">
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tx-tab" data-bs-toggle="tab" data-bs-target="#tx" type="button" role="tab" aria-controls="tx" aria-selected="true"><i class="bi-database me-2"></i>Transaksi Prabayar PPOB</button>
</li>
</ul>
<div class="tab-content border border-top-0 p-3">
<div class="tab-pane fade active show" id="tx" role="tabpanel" aria-labelledby="tx-tab">
<div class="row flex-column-reverse flex-md-row">
<div class="col-sm-12 col-lg-7 mt-3 mt-md-0">
<div class="card"><div class="card-body">
<div class="row mb-1">
<div class="col">
<div class="input-group">
<input class="form-control" id="Cari_PPOB" placeholder="Kunci Pencarian" type="text">
<button class="btn btn-info shadow-none" type="button" id="butSearch">Cari</button>
<button class="btn btn-secondary shadow-none" type="button" id="butAll">Semua</button>
</div>
</div>
</div>
<div id="divPOS1">&nbsp;</div>
</div></div>
</div>
<div class="col-sm-12 col-lg-5">
<div class="card"><div class="card-body">
<div id="divPOS2">&nbsp;</div>
</div></div>
</div>
</div>
</div>
</div>
</div></div>
</div>'
]);
}
}