update di penjualan invoice
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{"version":1,"defects":{"ApplicationContractTest::testInternalControllersUseAuthenticatedBaseController":3,"ApplicationContractTest::testResponsiveShellHasDesktopAndMobileRules":3,"ApplicationContractTest::testUiPreventsRepeatedSubmitAndHandlesAjaxFailure":4,"AccountingDatabaseTest::testAccountingInvariantsAgainstDevelopmentDatabase":3,"ApplicationContractTest::testPurchaseReturnsAreSeparatedAndIntegrated":3,"AccountingDatabaseTest::testPurchaseAdjustmentQueriesAndReportsRunAgainstActualSchema":3,"ApplicationContractTest::testMasterAdminHasFullAccessAndApprovalOverride":3},"times":{"ApplicationContractTest::testInternalControllersUseAuthenticatedBaseController":0.015,"ApplicationContractTest::testAjaxSessionExpiryReturnsJson401":0,"ApplicationContractTest::testResponsiveShellHasDesktopAndMobileRules":0.001,"ApplicationContractTest::testUiPreventsRepeatedSubmitAndHandlesAjaxFailure":0,"AccountingDatabaseTest::testAccountingInvariantsAgainstDevelopmentDatabase":0.9,"FormulaServiceTest::testPayrollFormulaHonorsPrecedenceAndVariables":0,"FormulaServiceTest::testProrataFormulaAndRounding":0,"FormulaServiceTest::testUnknownVariableIsZeroForBackwardCompatibleFormula":0,"FormulaServiceTest::testRejectsDivisionByZero":0.047,"FormulaServiceTest::testRejectsUnsafeTokens":0,"ApplicationContractTest::testMoneyInputsUseCentralParserBeforeAjax":0.001,"ApplicationContractTest::testMasterAdminHasFullAccessAndApprovalOverride":0,"ApplicationContractTest::testBalanceSheetAndProfitLossRemainInNavigation":0,"ApplicationContractTest::testProfessionalReportsHaveIndonesianFinancialStatements":0.001,"ApplicationContractTest::testPurchasePaymentsSeparatePrincipalAndBankCharge":0.001,"ApplicationContractTest::testPurchaseReturnsAreSeparatedAndIntegrated":0.005,"AccountingDatabaseTest::testPurchaseAdjustmentInvariantsAgainstDevelopmentDatabase":0.47,"ApplicationContractTest::testPurchaseAdjustmentsSupportReversalAuditAndProfessionalReports":0.001,"AccountingDatabaseTest::testPurchaseAdjustmentQueriesAndReportsRunAgainstActualSchema":0.615,"ApplicationContractTest::testProfessionalInventoryUsesOneLedgerAndSafeWorkflow":0.001,"AccountingDatabaseTest::testProfessionalInventoryRuntimeAgainstDevelopmentDatabase":0.603,"ApplicationContractTest::testInventoryFinalizationCoversRequiredOperationalScenarios":0.002,"ApplicationContractTest::testInventoryWriteEndpointsAndButtonsArePermissionAware":0.001,"AccountingDatabaseTest::testInventoryIntegrityAndNegativeStockGuardAgainstDevelopmentDatabase":0.611,"AccountingDatabaseTest::testInventoryReconciliationAlwaysProducesAuditableNumbers":0.224,"ApplicationContractTest::testFixedAssetsUseSingleProfessionalWorkflow":0.002,"AccountingDatabaseTest::testFixedAssetIntegrityAndRuntimeQueries":0.473}}
|
{"version":1,"defects":{"ApplicationContractTest::testInternalControllersUseAuthenticatedBaseController":3,"ApplicationContractTest::testResponsiveShellHasDesktopAndMobileRules":3,"ApplicationContractTest::testUiPreventsRepeatedSubmitAndHandlesAjaxFailure":4,"AccountingDatabaseTest::testAccountingInvariantsAgainstDevelopmentDatabase":3,"ApplicationContractTest::testPurchaseReturnsAreSeparatedAndIntegrated":3,"AccountingDatabaseTest::testPurchaseAdjustmentQueriesAndReportsRunAgainstActualSchema":3,"ApplicationContractTest::testMasterAdminHasFullAccessAndApprovalOverride":3,"ApplicationContractTest::testFixedAssetsUseSingleProfessionalWorkflow":3},"times":{"ApplicationContractTest::testInternalControllersUseAuthenticatedBaseController":0.087,"ApplicationContractTest::testAjaxSessionExpiryReturnsJson401":0.056,"ApplicationContractTest::testResponsiveShellHasDesktopAndMobileRules":0.11,"ApplicationContractTest::testUiPreventsRepeatedSubmitAndHandlesAjaxFailure":0.001,"AccountingDatabaseTest::testAccountingInvariantsAgainstDevelopmentDatabase":0.9,"FormulaServiceTest::testPayrollFormulaHonorsPrecedenceAndVariables":0.013,"FormulaServiceTest::testProrataFormulaAndRounding":0,"FormulaServiceTest::testUnknownVariableIsZeroForBackwardCompatibleFormula":0,"FormulaServiceTest::testRejectsDivisionByZero":0.003,"FormulaServiceTest::testRejectsUnsafeTokens":0,"ApplicationContractTest::testMoneyInputsUseCentralParserBeforeAjax":0.157,"ApplicationContractTest::testMasterAdminHasFullAccessAndApprovalOverride":0.001,"ApplicationContractTest::testBalanceSheetAndProfitLossRemainInNavigation":0,"ApplicationContractTest::testProfessionalReportsHaveIndonesianFinancialStatements":0.001,"ApplicationContractTest::testPurchasePaymentsSeparatePrincipalAndBankCharge":0.002,"ApplicationContractTest::testPurchaseReturnsAreSeparatedAndIntegrated":0.003,"AccountingDatabaseTest::testPurchaseAdjustmentInvariantsAgainstDevelopmentDatabase":0.47,"ApplicationContractTest::testPurchaseAdjustmentsSupportReversalAuditAndProfessionalReports":0.002,"AccountingDatabaseTest::testPurchaseAdjustmentQueriesAndReportsRunAgainstActualSchema":0.615,"ApplicationContractTest::testProfessionalInventoryUsesOneLedgerAndSafeWorkflow":0.003,"AccountingDatabaseTest::testProfessionalInventoryRuntimeAgainstDevelopmentDatabase":0.603,"ApplicationContractTest::testInventoryFinalizationCoversRequiredOperationalScenarios":0.003,"ApplicationContractTest::testInventoryWriteEndpointsAndButtonsArePermissionAware":0.001,"AccountingDatabaseTest::testInventoryIntegrityAndNegativeStockGuardAgainstDevelopmentDatabase":0.611,"AccountingDatabaseTest::testInventoryReconciliationAlwaysProducesAuditableNumbers":0.224,"ApplicationContractTest::testFixedAssetsUseSingleProfessionalWorkflow":0.065,"AccountingDatabaseTest::testFixedAssetIntegrityAndRuntimeQueries":0.473}}
|
||||||
@@ -7,6 +7,7 @@ class Customers extends MY_Controller {
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->load->model('DynamicModel', 'dm');
|
$this->load->model('DynamicModel', 'dm');
|
||||||
|
$this->load->library('SalesService');
|
||||||
|
|
||||||
if (!$this->session->userdata('logged_in')) {
|
if (!$this->session->userdata('logged_in')) {
|
||||||
redirect('auth');
|
redirect('auth');
|
||||||
@@ -15,9 +16,9 @@ class Customers extends MY_Controller {
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$data = ["active_menu" => "customers"];
|
$data = ["active_menu" => "customers", "summary" => $this->salesservice->dashboard()];
|
||||||
$this->load->view('partials/header', $data);
|
$this->load->view('partials/header', $data);
|
||||||
$this->load->view('customers/layout');
|
$this->load->view('customers/layout', $data);
|
||||||
$this->load->view('partials/footer');
|
$this->load->view('partials/footer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,14 +58,16 @@ class Invoices extends MY_Controller
|
|||||||
}
|
}
|
||||||
public function lookup_items()
|
public function lookup_items()
|
||||||
{
|
{
|
||||||
$q=trim((string)$this->input->get('q'));$page=max(1,(int)$this->input->get('page'));$limit=20;$this->db->select("i.id,CONCAT(i.kode_detail,' - ',i.nama_barang) text,i.kode_detail,i.nama_barang,i.harga_jual,i.stok,k.tracking_type,k.unit",false)->from('items i')->join('kode_barang k','k.id=i.kode_id','left')->where(array('i.company_id'=>$this->company(),'i.status'=>'active','i.stok >'=>'0'));if($q!=='')$this->db->group_start()->like('i.kode_detail',$q)->or_like('i.nama_barang',$q)->group_end();$rows=$this->db->order_by('i.nama_barang')->limit($limit+1,($page-1)*$limit)->get()->result();$more=count($rows)>$limit;if($more)array_pop($rows);return json_response(true,'Barang ditemukan.',array('results'=>$rows,'pagination'=>array('more'=>$more)));
|
$q=trim((string)$this->input->get('q'));$page=max(1,(int)$this->input->get('page'));$limit=20;
|
||||||
|
$available="(SELECT ib.item_id,SUM(CASE WHEN ib.status IN('available','reserved') THEN GREATEST(ib.qty_sisa-COALESCE(ib.reserved_qty,0)-COALESCE(ib.return_reserved_qty,0),0) ELSE 0 END) available_stock FROM item_barcodes ib GROUP BY ib.item_id) av";
|
||||||
|
$this->db->select("i.id,CONCAT(i.kode_detail,' - ',i.nama_barang,' - tersedia ',FORMAT(COALESCE(av.available_stock,0),0,'id_ID')) text,i.kode_detail,i.nama_barang,i.harga_jual,COALESCE(av.available_stock,0) stok,k.tracking_type,k.unit",false)->from('items i')->join('kode_barang k','k.id=i.kode_id','left')->join($available,'av.item_id=i.id','inner',false)->where(array('i.company_id'=>$this->company(),'i.status'=>'active'))->where('av.available_stock >',0);if($q!=='')$this->db->group_start()->like('i.kode_detail',$q)->or_like('i.nama_barang',$q)->group_end();$rows=$this->db->order_by('i.nama_barang')->limit($limit+1,($page-1)*$limit)->get()->result();$more=count($rows)>$limit;if($more)array_pop($rows);return json_response(true,'Barang ditemukan.',array('results'=>$rows,'pagination'=>array('more'=>$more)));
|
||||||
}
|
}
|
||||||
public function lookup_warehouses(){return$this->selectLookup('warehouses','nama',array('nama'),'Gudang ditemukan.');}
|
public function lookup_warehouses(){return$this->selectLookup('warehouses','nama',array('nama'),'Gudang ditemukan.');}
|
||||||
public function lookup_barcodes()
|
public function lookup_barcodes()
|
||||||
{
|
{
|
||||||
$q=trim((string)$this->input->get('q'));$item=(int)$this->input->get('item_id');$warehouse=(int)$this->input->get('warehouse_id');$exact=(int)$this->input->get('exact')===1;$page=max(1,(int)$this->input->get('page'));$limit=20;
|
$q=trim((string)$this->input->get('q'));$item=(int)$this->input->get('item_id');$warehouse=(int)$this->input->get('warehouse_id');$exact=(int)$this->input->get('exact')===1;$page=max(1,(int)$this->input->get('page'));$limit=20;
|
||||||
if(!$exact&&(!$item||!$warehouse))return json_response(true,'Pilih gudang dan barang terlebih dahulu.',array('results'=>array(),'pagination'=>array('more'=>false)));
|
if(!$exact&&(!$item||!$warehouse))return json_response(true,'Pilih gudang dan barang terlebih dahulu.',array('results'=>array(),'pagination'=>array('more'=>false)));
|
||||||
$this->db->select("b.id,CONCAT(b.barcode,IF(NULLIF(b.serial_number,'') IS NULL,'',CONCAT(' / ',b.serial_number)),' - tersedia ',ROUND(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0),4)) text,b.barcode,b.serial_number,b.item_id,b.warehouse_id,(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0)) available,i.kode_detail,i.nama_barang,i.harga_jual,k.tracking_type,k.unit,w.nama warehouse_name",false)->from('item_barcodes b')->join('items i','i.id=b.item_id')->join('kode_barang k','k.id=i.kode_id','left')->join('warehouses w','w.id=b.warehouse_id')->where(array('i.company_id'=>$this->company(),'b.status'=>'available'))->where('(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0)) >',0,false);if($item)$this->db->where('b.item_id',$item);if($warehouse)$this->db->where('b.warehouse_id',$warehouse);if($q!==''){$this->db->group_start();if($exact)$this->db->where('b.barcode',$q)->or_where('b.serial_number',$q);else$this->db->like('b.barcode',$q)->or_like('b.serial_number',$q);$this->db->group_end();}$rows=$this->db->order_by('b.id')->limit($limit+1,($page-1)*$limit)->get()->result();$more=count($rows)>$limit;if($more)array_pop($rows);return json_response(true,'Barcode ditemukan.',array('results'=>$rows,'pagination'=>array('more'=>$more)));
|
$this->db->select("b.id,CONCAT(b.barcode,IF(NULLIF(b.serial_number,'') IS NULL,'',CONCAT(' / ',b.serial_number)),' - tersedia ',FORMAT(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0),0,'id_ID')) text,b.barcode,b.serial_number,b.item_id,b.warehouse_id,(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0)) available,i.kode_detail,i.nama_barang,i.harga_jual,k.tracking_type,k.unit,w.nama warehouse_name",false)->from('item_barcodes b')->join('items i','i.id=b.item_id')->join('kode_barang k','k.id=i.kode_id','left')->join('warehouses w','w.id=b.warehouse_id')->where(array('i.company_id'=>$this->company(),'b.status'=>'available'))->where('(b.qty_sisa-b.reserved_qty-COALESCE(b.return_reserved_qty,0)) >',0,false)->where("(UPPER(COALESCE(k.tracking_type,'QTY'))<>'UNIT' OR NOT EXISTS(SELECT 1 FROM invoice_line_barcodes used JOIN invoice_details used_detail ON used_detail.id=used.invoice_detail_id AND used_detail.stock_posted_at IS NULL JOIN invoices used_invoice ON used_invoice.id=used.invoice_id WHERE used.barcode_id=b.id AND used_invoice.company_id=i.company_id AND used_invoice.deleted_at IS NULL AND COALESCE(used_invoice.status,'')<>'cancelled'))",null,false);if($item)$this->db->where('b.item_id',$item);if($warehouse)$this->db->where('b.warehouse_id',$warehouse);if($q!==''){$this->db->group_start();if($exact)$this->db->where('b.barcode',$q)->or_where('b.serial_number',$q);else$this->db->like('b.barcode',$q)->or_like('b.serial_number',$q);$this->db->group_end();}$rows=$this->db->order_by('b.id')->limit($limit+1,($page-1)*$limit)->get()->result();$more=count($rows)>$limit;if($more)array_pop($rows);return json_response(true,'Barcode ditemukan.',array('results'=>$rows,'pagination'=>array('more'=>$more)));
|
||||||
}
|
}
|
||||||
private function selectLookup($table,$label,array$fields,$message)
|
private function selectLookup($table,$label,array$fields,$message)
|
||||||
{
|
{
|
||||||
@@ -107,7 +109,7 @@ class Invoices extends MY_Controller
|
|||||||
public function submit($id){return$this->mutation('can_submit',function()use($id){return$this->salesservice->submitInvoice($id,$this->uid());},'Invoice berhasil diajukan.');}
|
public function submit($id){return$this->mutation('can_submit',function()use($id){return$this->salesservice->submitInvoice($id,$this->uid());},'Invoice berhasil diajukan.');}
|
||||||
public function approve($id){return$this->mutation('can_approve',function()use($id){return$this->salesservice->approveAndPostInvoice($id,$this->uid(),$this->roleId());},'Invoice disetujui dan otomatis diposting.');}
|
public function approve($id){return$this->mutation('can_approve',function()use($id){return$this->salesservice->approveAndPostInvoice($id,$this->uid(),$this->roleId());},'Invoice disetujui dan otomatis diposting.');}
|
||||||
public function reject($id){return$this->mutation('can_approve',function()use($id){return$this->salesservice->rejectInvoice($id,$this->input->post('reason',true),$this->uid(),$this->roleId());},'Invoice ditolak dan dikembalikan ke Draft.');}
|
public function reject($id){return$this->mutation('can_approve',function()use($id){return$this->salesservice->rejectInvoice($id,$this->input->post('reason',true),$this->uid(),$this->roleId());},'Invoice ditolak dan dikembalikan ke Draft.');}
|
||||||
public function delete_draft($id){return$this->mutation('can_delete',function()use($id){return$this->salesservice->deleteDraftInvoice($id,$this->uid(),is_master_admin_user());},'Draft invoice dibatalkan dan seluruh reservasi dilepas.');}
|
public function delete_draft($id){return$this->mutation('can_delete',function()use($id){return$this->salesservice->deleteDraftInvoice($id,$this->uid(),is_master_admin_user());},'Draft invoice dibatalkan, stok/barcode tersedia kembali, dan jurnal awal telah dibalik.');}
|
||||||
public function pdf($id)
|
public function pdf($id)
|
||||||
{
|
{
|
||||||
$this->requirePermission('invoices','can_export');$this->guardView($this->salesservice->invoiceForEditor($id));$data=$this->salesservice->invoiceDetail($id);$includePrevious=(int)$this->input->get('include_previous')===1;$data['previous_invoices']=$includePrevious?$this->salesservice->previousOutstandingInvoices($id):array();$this->addPdfCompanySettings($data);require_once FCPATH.'vendor/autoload.php';$html=$this->load->view('sales/invoice_pdf',$data,true);$pdf=new Dompdf\Dompdf();$pdf->loadHtml($html);$pdf->setPaper('A4','portrait');$pdf->render();$pdf->stream('Invoice-'.$data['invoice']->no_invoice.'.pdf',array('Attachment'=>false));
|
$this->requirePermission('invoices','can_export');$this->guardView($this->salesservice->invoiceForEditor($id));$data=$this->salesservice->invoiceDetail($id);$includePrevious=(int)$this->input->get('include_previous')===1;$data['previous_invoices']=$includePrevious?$this->salesservice->previousOutstandingInvoices($id):array();$this->addPdfCompanySettings($data);require_once FCPATH.'vendor/autoload.php';$html=$this->load->view('sales/invoice_pdf',$data,true);$pdf=new Dompdf\Dompdf();$pdf->loadHtml($html);$pdf->setPaper('A4','portrait');$pdf->render();$pdf->stream('Invoice-'.$data['invoice']->no_invoice.'.pdf',array('Attachment'=>false));
|
||||||
|
|||||||
@@ -693,6 +693,13 @@ class Items extends MY_Controller {
|
|||||||
return json_response(false, 'Barang tidak ditemukan.', array(), 404);
|
return json_response(false, 'Barang tidak ditemukan.', array(), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($item->status === 'active') {
|
||||||
|
$availability = $this->db->query("SELECT COUNT(*) barcode_count,COALESCE(SUM(CASE WHEN status IN('available','reserved') THEN GREATEST(qty_sisa-COALESCE(reserved_qty,0)-COALESCE(return_reserved_qty,0),0) ELSE 0 END),0) available_stock,COALESCE(SUM(COALESCE(reserved_qty,0)+COALESCE(return_reserved_qty,0)),0) reserved_stock FROM item_barcodes WHERE item_id=?", array((int)$item->id))->row();
|
||||||
|
$item->physical_stock = (float)$item->stok;
|
||||||
|
$item->available_stock = $availability && (int)$availability->barcode_count > 0 ? (float)$availability->available_stock : (float)$item->stok;
|
||||||
|
$item->reserved_stock = $availability ? (float)$availability->reserved_stock : 0;
|
||||||
|
}
|
||||||
|
|
||||||
$logs = $this->db
|
$logs = $this->db
|
||||||
->select('stock_logs.*, warehouses.nama as gudang')
|
->select('stock_logs.*, warehouses.nama as gudang')
|
||||||
->join('warehouses','warehouses.id = stock_logs.warehouse_id','left')
|
->join('warehouses','warehouses.id = stock_logs.warehouse_id','left')
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Receivables extends MY_Controller
|
|||||||
{
|
{
|
||||||
$focusId=(int)$this->input->get('invoice_id');$focus=null;
|
$focusId=(int)$this->input->get('invoice_id');$focus=null;
|
||||||
if($focusId)$focus=$this->db->select('i.id,i.customer_id,i.no_invoice,i.sisa_piutang,c.nama customer_name')->from('invoices i')->join('customers c','c.id=i.customer_id')->where(array('i.id'=>$focusId,'i.company_id'=>$this->company(),'i.workflow_status'=>'posted'))->where('i.sisa_piutang >',0)->get()->row();
|
if($focusId)$focus=$this->db->select('i.id,i.customer_id,i.no_invoice,i.sisa_piutang,c.nama customer_name')->from('invoices i')->join('customers c','c.id=i.customer_id')->where(array('i.id'=>$focusId,'i.company_id'=>$this->company(),'i.workflow_status'=>'posted'))->where('i.sisa_piutang >',0)->get()->row();
|
||||||
$data=array('active_menu'=>'receivables','aging'=>$this->receivableservice->aging($this->input->get('as_of')?:date('Y-m-d')),'focus_invoice'=>$focus,'can_post'=>is_master_admin_user()||check_permission('invoices','can_post'));
|
$data=array('active_menu'=>'receivables','aging'=>$this->receivableservice->aging($this->input->get('as_of')?:date('Y-m-d')),'focus_invoice'=>$focus,'can_post'=>is_master_admin_user()||check_permission('invoices','can_post'),'summary'=>$this->salesservice->dashboard());
|
||||||
$this->load->view('partials/header',$data);$this->load->view('receivables/index',$data);$this->load->view('partials/footer',$data);
|
$this->load->view('partials/header',$data);$this->load->view('receivables/index',$data);$this->load->view('partials/footer',$data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,34 @@ class Sales extends MY_Controller
|
|||||||
public function return_pdf($id){$data=$this->salesservice->returnDetail($id);$this->pdf('sales/return_pdf',$data,'Retur-'.$data['return']->return_no.'.pdf');}
|
public function return_pdf($id){$data=$this->salesservice->returnDetail($id);$this->pdf('sales/return_pdf',$data,'Retur-'.$data['return']->return_no.'.pdf');}
|
||||||
public function receipt_pdf($id)
|
public function receipt_pdf($id)
|
||||||
{
|
{
|
||||||
$company=(int)$this->companycontext->id();$data['payment']=$this->db->select('p.*,c.nama customer_name,c.alamat')->from('payments p')->join('customers c','c.id=p.customer_id')->where(array('p.id'=>(int)$id,'p.company_id'=>$company))->get()->row();if(!$data['payment'])show_404();$data['allocations']=$this->db->select('a.*,i.no_invoice')->from('payment_allocations a')->join('invoices i','i.id=a.invoice_id')->where(array('a.payment_id'=>(int)$id,'i.company_id'=>$company))->get()->result();$data['sources']=$this->db->select('s.*,a.kode_akun,a.nama_akun')->from('payment_sources s')->join('accounts a','a.id=s.account_id')->where(array('s.payment_id'=>(int)$id,'s.company_id'=>$company))->get()->result();$this->pdf('sales/receipt_pdf',$data,'Bukti-Penerimaan-'.$data['payment']->payment_no.'.pdf');
|
$company=(int)$this->companycontext->id();
|
||||||
|
$data['payment']=$this->db
|
||||||
|
->select('p.*,c.nama customer_name,c.alamat customer_address,c.telp customer_phone,c.email customer_email,u.nama creator_name')
|
||||||
|
->from('payments p')
|
||||||
|
->join('customers c','c.id=p.customer_id')
|
||||||
|
->join('users u','u.id=p.created_by','left')
|
||||||
|
->where(array('p.id'=>(int)$id,'p.company_id'=>$company))
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
if(!$data['payment'])show_404();
|
||||||
|
$data['allocations']=$this->db
|
||||||
|
->select('a.*,i.no_invoice,i.tanggal invoice_date,i.jatuh_tempo')
|
||||||
|
->from('payment_allocations a')
|
||||||
|
->join('invoices i','i.id=a.invoice_id')
|
||||||
|
->where(array('a.payment_id'=>(int)$id,'i.company_id'=>$company))
|
||||||
|
->order_by('i.tanggal','ASC')
|
||||||
|
->order_by('i.id','ASC')
|
||||||
|
->get()
|
||||||
|
->result();
|
||||||
|
$data['sources']=$this->db
|
||||||
|
->select('s.*,a.kode_akun,a.nama_akun')
|
||||||
|
->from('payment_sources s')
|
||||||
|
->join('accounts a','a.id=s.account_id')
|
||||||
|
->where(array('s.payment_id'=>(int)$id,'s.company_id'=>$company))
|
||||||
|
->order_by('s.id','ASC')
|
||||||
|
->get()
|
||||||
|
->result();
|
||||||
|
$this->pdf('sales/receipt_pdf',$data,'Bukti-Penerimaan-'.$data['payment']->payment_no.'.pdf');
|
||||||
}
|
}
|
||||||
private function decodeRows(){$rows=json_decode((string)$this->input->post('rows'),true);if(!is_array($rows))throw new BusinessException('Detail barang tidak valid.');return$rows;}
|
private function decodeRows(){$rows=json_decode((string)$this->input->post('rows'),true);if(!is_array($rows))throw new BusinessException('Detail barang tidak valid.');return$rows;}
|
||||||
private function action($fn,$message){if(strtoupper($this->input->method())!=='POST')return json_response(false,'Metode tidak diizinkan.',array(),405);try{return json_response(true,$message,array('result'=>$fn()));}catch(Throwable$e){return business_exception_response($e);}}
|
private function action($fn,$message){if(strtoupper($this->input->method())!=='POST')return json_response(false,'Metode tidak diizinkan.',array(),405);try{return json_response(true,$message,array('result'=>$fn()));}catch(Throwable$e){return business_exception_response($e);}}
|
||||||
|
|||||||
@@ -184,7 +184,9 @@ class SalesService
|
|||||||
if(!$bid||isset($seenBarcodes[$bid]))throw new BusinessException('Barcode tidak boleh dipilih dua kali pada satu baris.');
|
if(!$bid||isset($seenBarcodes[$bid]))throw new BusinessException('Barcode tidak boleh dipilih dua kali pada satu baris.');
|
||||||
$seenBarcodes[$bid]=true;
|
$seenBarcodes[$bid]=true;
|
||||||
if($this->CI->db->where(array('invoice_id'=>$invoice->id,'barcode_id'=>$bid))->count_all_results('invoice_line_barcodes'))throw new BusinessException('Barcode sudah dipakai pada item lain di invoice ini.');
|
if($this->CI->db->where(array('invoice_id'=>$invoice->id,'barcode_id'=>$bid))->count_all_results('invoice_line_barcodes'))throw new BusinessException('Barcode sudah dipakai pada item lain di invoice ini.');
|
||||||
$bq=$this->qty($b['qty']??1);$barcode=$this->CI->db->query("SELECT * FROM item_barcodes WHERE id=? AND item_id=? AND warehouse_id=? AND status='available' FOR UPDATE",array($bid,$item->id,$warehouse->id))->row();if(!$barcode)throw new BusinessException('Barcode barang '.$item->nama_barang.' tidak tersedia di gudang terpilih.');$available=(float)$barcode->qty_sisa-(float)$barcode->reserved_qty-(float)($barcode->return_reserved_qty??0);if($bq>$available+.0001)throw new BusinessException('Qty barcode '.$barcode->barcode.' melebihi saldo tersedia.');$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',array('reserved_qty'=>(float)$barcode->reserved_qty+$bq,'version'=>(int)$barcode->version+1));if($this->CI->db->affected_rows()!==1)throw new BusinessException('Barcode sedang dipilih pengguna lain. Silakan ulangi.');$barcode->reserved_qty=(float)$barcode->reserved_qty+$bq;$barcode->version=(int)$barcode->version+1;$barcodeQty+=$bq;$cleanBarcodes[]=array('row'=>$barcode,'qty'=>$bq);
|
$bq=$this->qty($b['qty']??1);$barcode=$this->CI->db->query("SELECT * FROM item_barcodes WHERE id=? AND item_id=? AND warehouse_id=? AND status='available' FOR UPDATE",array($bid,$item->id,$warehouse->id))->row();if(!$barcode)throw new BusinessException('Barcode barang '.$item->nama_barang.' tidak tersedia di gudang terpilih.');
|
||||||
|
if($kb&&strtoupper((string)$kb->tracking_type)==='UNIT'){$used=(int)$this->CI->db->select('COUNT(*) total',false)->from('invoice_line_barcodes used')->join('invoice_details used_detail','used_detail.id=used.invoice_detail_id AND used_detail.stock_posted_at IS NULL')->join('invoices used_invoice','used_invoice.id=used.invoice_id')->where(array('used.barcode_id'=>$barcode->id,'used_invoice.company_id'=>$this->company()))->where('used_invoice.deleted_at IS NULL',null,false)->where("COALESCE(used_invoice.status,'') <> 'cancelled'",null,false)->get()->row()->total;if($used>0)throw new BusinessException('Barcode/Serial '.$barcode->barcode.' sudah digunakan pada invoice lain.');}
|
||||||
|
$available=(float)$barcode->qty_sisa-(float)$barcode->reserved_qty-(float)($barcode->return_reserved_qty??0);if($bq>$available+.0001)throw new BusinessException('Qty barcode '.$barcode->barcode.' melebihi saldo tersedia.');$reservedAfter=(float)$barcode->reserved_qty+$bq;$reserveUpdate=array('reserved_qty'=>$reservedAfter,'version'=>(int)$barcode->version+1);if($kb&&strtoupper((string)$kb->tracking_type)==='UNIT')$reserveUpdate['status']='reserved';$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',$reserveUpdate);if($this->CI->db->affected_rows()!==1)throw new BusinessException('Barcode sedang dipilih pengguna lain. Silakan ulangi.');$barcode->reserved_qty=$reservedAfter;$barcode->version=(int)$barcode->version+1;$barcodeQty+=$bq;$cleanBarcodes[]=array('row'=>$barcode,'qty'=>$bq);
|
||||||
}
|
}
|
||||||
if(abs($barcodeQty-$q)>.0001)throw new BusinessException('Total qty barcode harus sama dengan qty barang '.$item->nama_barang.'.');if($kb&&$kb->tracking_type==='UNIT')foreach($cleanBarcodes as$b)if(abs($b['qty']-1)>.0001)throw new BusinessException('Barcode UNIT harus memiliki qty 1.');
|
if(abs($barcodeQty-$q)>.0001)throw new BusinessException('Total qty barcode harus sama dengan qty barang '.$item->nama_barang.'.');if($kb&&$kb->tracking_type==='UNIT')foreach($cleanBarcodes as$b)if(abs($b['qty']-1)>.0001)throw new BusinessException('Barcode UNIT harus memiliki qty 1.');
|
||||||
}
|
}
|
||||||
@@ -315,7 +317,12 @@ class SalesService
|
|||||||
private function releaseInvoiceLineBarcodes($lineId)
|
private function releaseInvoiceLineBarcodes($lineId)
|
||||||
{
|
{
|
||||||
$bars=$this->CI->db->where(array('invoice_detail_id'=>(int)$lineId,'company_id'=>$this->company()))->get('invoice_line_barcodes')->result();
|
$bars=$this->CI->db->where(array('invoice_detail_id'=>(int)$lineId,'company_id'=>$this->company()))->get('invoice_line_barcodes')->result();
|
||||||
foreach($bars as$b){$barcode=$this->CI->db->query('SELECT * FROM item_barcodes WHERE id=? FOR UPDATE',array($b->barcode_id))->row();if($barcode)$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',array('reserved_qty'=>max(0,(float)$barcode->reserved_qty-(float)$b->qty),'status'=>'available','version'=>(int)$barcode->version+1));}
|
foreach($bars as$b){
|
||||||
|
$barcode=$this->CI->db->query('SELECT ib.* FROM item_barcodes ib JOIN items i ON i.id=ib.item_id WHERE ib.id=? AND i.company_id=? FOR UPDATE',array($b->barcode_id,$this->company()))->row();
|
||||||
|
if(!$barcode)throw new BusinessException('Barcode reservasi invoice tidak ditemukan. Pembatalan dihentikan agar stok dan jurnal tetap sinkron.');
|
||||||
|
$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',array('reserved_qty'=>max(0,(float)$barcode->reserved_qty-(float)$b->qty),'status'=>'available','version'=>(int)$barcode->version+1));
|
||||||
|
if($this->CI->db->affected_rows()!==1)throw new BusinessException('Barcode sedang berubah pada proses lain. Silakan ulangi pembatalan invoice.');
|
||||||
|
}
|
||||||
$this->CI->db->where(array('invoice_detail_id'=>(int)$lineId,'company_id'=>$this->company()))->delete('invoice_line_barcodes');
|
$this->CI->db->where(array('invoice_detail_id'=>(int)$lineId,'company_id'=>$this->company()))->delete('invoice_line_barcodes');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +360,7 @@ class SalesService
|
|||||||
$totalCost=0;$inventoryReclass=0;
|
$totalCost=0;$inventoryReclass=0;
|
||||||
foreach($lines as$l){
|
foreach($lines as$l){
|
||||||
if($l->stock_posted_at)continue;$bars=$this->CI->db->where('sales_delivery_line_id',$l->id)->get('sales_delivery_barcodes')->result();$allocated=0;
|
if($l->stock_posted_at)continue;$bars=$this->CI->db->where('sales_delivery_line_id',$l->id)->get('sales_delivery_barcodes')->result();$allocated=0;
|
||||||
foreach($bars as$b){$barcode=$this->CI->db->query('SELECT * FROM item_barcodes WHERE id=? AND item_id=? AND warehouse_id=? FOR UPDATE',array($b->barcode_id,$l->item_id,$d->warehouse_id))->row();if(!$barcode||$barcode->status!=='available'||(float)$barcode->qty_sisa<(float)$b->qty-.0001||(float)$barcode->reserved_qty<(float)$b->qty-.0001)throw new BusinessException('Barcode pada Surat Jalan sudah tidak tersedia atau reservasinya tidak valid.');$left=(float)$barcode->qty_sisa-(float)$b->qty;$reserved=max(0,(float)$barcode->reserved_qty-(float)$b->qty);$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',array('qty_sisa'=>$left,'reserved_qty'=>$reserved,'status'=>$left<=.0001?'sold_out':'available','version'=>(int)$barcode->version+1));if($this->CI->db->affected_rows()!==1)throw new BusinessException('Barcode sedang diproses pengguna lain. Silakan ulangi.');$this->CI->db->where('id',$b->id)->update('sales_delivery_barcodes',array('status'=>'delivered'));$allocated+=(float)$b->qty;}
|
foreach($bars as$b){$barcode=$this->CI->db->query('SELECT * FROM item_barcodes WHERE id=? AND item_id=? AND warehouse_id=? FOR UPDATE',array($b->barcode_id,$l->item_id,$d->warehouse_id))->row();if(!$barcode||!in_array($barcode->status,array('available','reserved'),true)||(float)$barcode->qty_sisa<(float)$b->qty-.0001||(float)$barcode->reserved_qty<(float)$b->qty-.0001)throw new BusinessException('Barcode pada Surat Jalan sudah tidak tersedia atau reservasinya tidak valid.');$left=(float)$barcode->qty_sisa-(float)$b->qty;$reserved=max(0,(float)$barcode->reserved_qty-(float)$b->qty);$this->CI->db->where(array('id'=>$barcode->id,'version'=>$barcode->version))->update('item_barcodes',array('qty_sisa'=>$left,'reserved_qty'=>$reserved,'status'=>$left<=.0001?'sold_out':($reserved>.0001?'reserved':'available'),'version'=>(int)$barcode->version+1));if($this->CI->db->affected_rows()!==1)throw new BusinessException('Barcode sedang diproses pengguna lain. Silakan ulangi.');$this->CI->db->where('id',$b->id)->update('sales_delivery_barcodes',array('status'=>'delivered'));$allocated+=(float)$b->qty;}
|
||||||
if(abs($allocated-(float)$l->qty)>.0001)throw new BusinessException('Alokasi barcode Surat Jalan tidak sama dengan qty barang.');
|
if(abs($allocated-(float)$l->qty)>.0001)throw new BusinessException('Alokasi barcode Surat Jalan tidak sama dengan qty barang.');
|
||||||
$detailBefore=$this->CI->db->get_where('invoice_details',array('id'=>$l->invoice_detail_id,'company_id'=>$this->company()))->row();$initialJournal=$detailBefore?$this->initialLineJournal($detailBefore->id):null;$hadInitialJournal=$initialJournal&&!$initialJournal->is_reversed&&$initialJournal->status==='posted';$previousCost=$detailBefore?(float)$detailBefore->total_hpp_barang:0;
|
$detailBefore=$this->CI->db->get_where('invoice_details',array('id'=>$l->invoice_detail_id,'company_id'=>$this->company()))->row();$initialJournal=$detailBefore?$this->initialLineJournal($detailBefore->id):null;$hadInitialJournal=$initialJournal&&!$initialJournal->is_reversed&&$initialJournal->status==='posted';$previousCost=$detailBefore?(float)$detailBefore->total_hpp_barang:0;
|
||||||
$cost=$this->consumeCost($l->item_id,$d->warehouse_id,$l->qty);$totalCost+=$cost;$inventoryReclass+=$hadInitialJournal?($cost-$previousCost):$cost;$key='SALES-DELIVERY-LINE-'.$l->id;$desc='[AUTO] Surat Jalan '.$d->delivery_no.' | '.$l->description.' | Qty '.number_format($l->qty,0,',','.');
|
$cost=$this->consumeCost($l->item_id,$d->warehouse_id,$l->qty);$totalCost+=$cost;$inventoryReclass+=$hadInitialJournal?($cost-$previousCost):$cost;$key='SALES-DELIVERY-LINE-'.$l->id;$desc='[AUTO] Surat Jalan '.$d->delivery_no.' | '.$l->description.' | Qty '.number_format($l->qty,0,',','.');
|
||||||
@@ -378,7 +385,7 @@ class SalesService
|
|||||||
|
|
||||||
public function submitInvoice($id,$user)
|
public function submitInvoice($id,$user)
|
||||||
{
|
{
|
||||||
return$this->CI->transactionservice->run(function()use($id,$user){$i=$this->lockInvoice($id,'draft');$this->assertDraftOwner($i,$user);$open=(int)$this->CI->db->where(array('invoice_id'=>$i->id,'company_id'=>$this->company(),'status'=>'draft'))->count_all_results('sales_deliveries');if($open)throw new BusinessException('Seluruh Surat Jalan Draft harus diposting sebelum invoice diajukan.');$this->refreshInvoiceTotals($i->id);$this->updateInvoiceDeliveryStatus($i->id);$i=$this->lockInvoice($id,'draft');if((float)$i->total<=0)throw new BusinessException('Invoice belum mempunyai nilai.');if($i->delivery_status!=='delivered')throw new BusinessException('Pengiriman barang pada invoice belum selesai.');$this->CI->approvalservice->create('invoice','invoice',$i->id,$i->total,$user,array('invoice_no'=>$i->no_invoice,'customer_id'=>$i->customer_id));$this->CI->db->where('id',$i->id)->update('invoices',array('workflow_status'=>'submitted','finalized_at'=>date('Y-m-d H:i:s'),'finalized_by'=>$user,'submitted_at'=>date('Y-m-d H:i:s'),'submitted_by'=>$user));$this->CI->auditservice->record('sales','invoice',$i->id,'submit',$i,array('status'=>'submitted'),$user);return$i->id;});
|
return$this->CI->transactionservice->run(function()use($id,$user){$i=$this->lockInvoice($id,'draft');$this->assertDraftOwner($i,$user);$this->refreshInvoiceTotals($i->id);$this->updateInvoiceDeliveryStatus($i->id);$i=$this->lockInvoice($id,'draft');if((float)$i->total<=0)throw new BusinessException('Invoice belum mempunyai nilai.');$this->CI->approvalservice->create('invoice','invoice',$i->id,$i->total,$user,array('invoice_no'=>$i->no_invoice,'customer_id'=>$i->customer_id));$this->CI->db->where('id',$i->id)->update('invoices',array('workflow_status'=>'submitted','finalized_at'=>date('Y-m-d H:i:s'),'finalized_by'=>$user,'submitted_at'=>date('Y-m-d H:i:s'),'submitted_by'=>$user));$this->CI->auditservice->record('sales','invoice',$i->id,'submit',$i,array('status'=>'submitted','delivery_status'=>$i->delivery_status,'delivery_optional'=>true),$user);return$i->id;});
|
||||||
}
|
}
|
||||||
public function rejectInvoice($id,$reason,$user,$roleId)
|
public function rejectInvoice($id,$reason,$user,$roleId)
|
||||||
{
|
{
|
||||||
@@ -390,7 +397,7 @@ class SalesService
|
|||||||
}
|
}
|
||||||
private function postInvoiceInternal($id,$user)
|
private function postInvoiceInternal($id,$user)
|
||||||
{
|
{
|
||||||
$i=$this->lockInvoice($id,'approved');$this->CI->fiscalperiodservice->assertOpen($i->tanggal);if($i->journal_id)throw new BusinessException('Invoice sudah pernah diposting.');if($i->delivery_status!=='delivered')throw new BusinessException('Invoice hanya dapat diposting setelah seluruh Surat Jalan diposting.');$lines=$this->CI->db->where(array('invoice_id'=>$i->id,'company_id'=>$this->company()))->get('invoice_details')->result();if(!$lines)throw new BusinessException('Invoice belum mempunyai item.');
|
$i=$this->lockInvoice($id,'approved');$this->CI->fiscalperiodservice->assertOpen($i->tanggal);if($i->journal_id)throw new BusinessException('Invoice sudah pernah diposting.');$lines=$this->CI->db->where(array('invoice_id'=>$i->id,'company_id'=>$this->company()))->get('invoice_details')->result();if(!$lines)throw new BusinessException('Invoice belum mempunyai item.');
|
||||||
$family=$this->lineFamily($lines[0]->line_type);$entries=array();$cogs=0;$revenueAmount=0;$hasSales=false;$hasSavings=false;$hasLoan=false;foreach($lines as$l){if(in_array($l->line_type,array('inventory','service'),true))$hasSales=true;elseif($l->line_type==='savings')$hasSavings=true;elseif($l->line_type==='loan')$hasLoan=true;}
|
$family=$this->lineFamily($lines[0]->line_type);$entries=array();$cogs=0;$revenueAmount=0;$hasSales=false;$hasSavings=false;$hasLoan=false;foreach($lines as$l){if(in_array($l->line_type,array('inventory','service'),true))$hasSales=true;elseif($l->line_type==='savings')$hasSavings=true;elseif($l->line_type==='loan')$hasLoan=true;}
|
||||||
if($hasSavings&&!$hasSales&&!$hasLoan){
|
if($hasSavings&&!$hasSales&&!$hasLoan){
|
||||||
$this->CI->db->where('id',$i->id)->update('invoices',array('workflow_status'=>'posted','posted'=>1,'posted_by'=>$user,'posted_at'=>date('Y-m-d H:i:s'),'journal_id'=>null,'status'=>'unpaid','sisa_piutang'=>$i->total,'recognized_revenue'=>0,'recognized_cogs'=>0,'recognition_policy'=>'on_payment'));
|
$this->CI->db->where('id',$i->id)->update('invoices',array('workflow_status'=>'posted','posted'=>1,'posted_by'=>$user,'posted_at'=>date('Y-m-d H:i:s'),'journal_id'=>null,'status'=>'unpaid','sisa_piutang'=>$i->total,'recognized_revenue'=>0,'recognized_cogs'=>0,'recognition_policy'=>'on_payment'));
|
||||||
@@ -484,7 +491,22 @@ class SalesService
|
|||||||
|
|
||||||
private function recordCashSubledger($glAccountId,$date,$direction,$amount,$partyType,$partyId,$sourceType,$sourceId,$journalId,$description,$user)
|
private function recordCashSubledger($glAccountId,$date,$direction,$amount,$partyType,$partyId,$sourceType,$sourceId,$journalId,$description,$user)
|
||||||
{
|
{
|
||||||
if(!$this->CI->db->table_exists('cash_transactions'))return;$cash=$this->CI->db->get_where('cash_accounts',array('company_id'=>$this->company(),'gl_account_id'=>(int)$glAccountId,'is_active'=>1))->row();if(!$cash)return;
|
if(!$this->CI->db->table_exists('cash_accounts')||!$this->CI->db->table_exists('cash_transactions'))return;
|
||||||
|
|
||||||
|
// cash_accounts pada database lama belum memiliki company_id. Scope tenant
|
||||||
|
// tetap dijaga melalui akun GL yang terhubung karena accounts.company_id
|
||||||
|
// merupakan sumber kepemilikan akun yang digunakan saat pembayaran.
|
||||||
|
$cash=$this->CI->db
|
||||||
|
->select('cash_accounts.*')
|
||||||
|
->from('cash_accounts')
|
||||||
|
->join('accounts','accounts.id=cash_accounts.gl_account_id')
|
||||||
|
->where('accounts.company_id',$this->company())
|
||||||
|
->where('cash_accounts.gl_account_id',(int)$glAccountId)
|
||||||
|
->where('cash_accounts.is_active',1)
|
||||||
|
->limit(1)
|
||||||
|
->get()
|
||||||
|
->row();
|
||||||
|
if(!$cash)return;
|
||||||
$key='C'.$this->company().'-'.strtoupper($sourceType).'-'.(int)$sourceId.'-'.(int)$cash->id.'-'.$direction;if($this->CI->db->where('idempotency_key',$key)->count_all_results('cash_transactions'))return;
|
$key='C'.$this->company().'-'.strtoupper($sourceType).'-'.(int)$sourceId.'-'.(int)$cash->id.'-'.$direction;if($this->CI->db->where('idempotency_key',$key)->count_all_results('cash_transactions'))return;
|
||||||
$row=$this->columns('cash_transactions',array('company_id'=>$this->company(),'transaction_no'=>$this->CI->numberingservice->next('cash_transaction',$date),'transaction_date'=>$date,'cash_account_id'=>$cash->id,'transaction_type'=>$direction==='in'?'receipt':'payment','direction'=>$direction,'amount'=>$amount,'counter_account_id'=>null,'party_type'=>$partyType,'party_id'=>$partyId,'reference_no'=>null,'description'=>'[AUTO] '.$description,'status'=>'posted','requires_approval'=>0,'source_type'=>$sourceType,'source_id'=>$sourceId,'journal_id'=>$journalId,'idempotency_key'=>$key,'created_by'=>$user,'posted_by'=>$user,'posted_at'=>date('Y-m-d H:i:s'),'created_at'=>date('Y-m-d H:i:s')));$this->CI->db->insert('cash_transactions',$row);
|
$row=$this->columns('cash_transactions',array('company_id'=>$this->company(),'transaction_no'=>$this->CI->numberingservice->next('cash_transaction',$date),'transaction_date'=>$date,'cash_account_id'=>$cash->id,'transaction_type'=>$direction==='in'?'receipt':'payment','direction'=>$direction,'amount'=>$amount,'counter_account_id'=>null,'party_type'=>$partyType,'party_id'=>$partyId,'reference_no'=>null,'description'=>'[AUTO] '.$description,'status'=>'posted','requires_approval'=>0,'source_type'=>$sourceType,'source_id'=>$sourceId,'journal_id'=>$journalId,'idempotency_key'=>$key,'created_by'=>$user,'posted_by'=>$user,'posted_at'=>date('Y-m-d H:i:s'),'created_at'=>date('Y-m-d H:i:s')));$this->CI->db->insert('cash_transactions',$row);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
<div class="container mt-4">
|
<link rel="stylesheet" href="<?=base_url('assets/css/invoices-professional.css').'?v='.filemtime(FCPATH.'assets/css/invoices-professional.css')?>">
|
||||||
|
<section class="invoice-workspace">
|
||||||
|
<header class="invoice-hero">
|
||||||
|
<div><span>SIKLUS PENJUALAN</span><h2>Customer</h2><p>Kelola identitas, termin pembayaran, dan kebijakan kredit customer.</p></div>
|
||||||
|
</header>
|
||||||
|
<?php $this->load->view('sales/_section_nav',array('sales_section'=>'customer','sales_summary'=>$summary)); ?>
|
||||||
|
<div class="container-fluid px-0">
|
||||||
<div class="card modern-card shadow-sm border-0 rounded-4">
|
<div class="card modern-card shadow-sm border-0 rounded-4">
|
||||||
<div class="card-body p-4">
|
<div class="card-body p-4">
|
||||||
|
|
||||||
@@ -24,9 +30,10 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
<!-- MODAL -->
|
|
||||||
|
<!-- MODAL -->
|
||||||
<div class="modal fade" id="modalCustomer">
|
<div class="modal fade" id="modalCustomer">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function invLabel($value){$labels=array('draft'=>'Draft','submitted'=>'Menunggu
|
|||||||
<div class="hero-actions"><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-arrow-left"></i> Daftar Invoice</a><?php if($invoice&&$p['export']):?><button class="btn btn-outline-danger open-invoice-pdf" data-id="<?=$invoice->id?>" data-url="<?=base_url('invoices/pdf/'.$invoice->id)?>"><i class="bi bi-file-pdf"></i> PDF</button><?php endif?></div>
|
<div class="hero-actions"><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-arrow-left"></i> Daftar Invoice</a><?php if($invoice&&$p['export']):?><button class="btn btn-outline-danger open-invoice-pdf" data-id="<?=$invoice->id?>" data-url="<?=base_url('invoices/pdf/'.$invoice->id)?>"><i class="bi bi-file-pdf"></i> PDF</button><?php endif?></div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<?php if($invoice):?><div class="invoice-progress"><span class="done"><i class="bi bi-check-lg"></i> Header Draft</span><span class="<?=$invoice->delivery_status==='delivered'?'done':''?>"><i class="bi bi-truck"></i> <?=$invoice->inventory_line_count?'Pengiriman':'Tanpa Surat Jalan'?></span><span class="<?=in_array($invoice->workflow_status,array('submitted','approved','posted'),true)?'done':''?>"><i class="bi bi-send"></i> Diajukan</span><span class="<?=$invoice->workflow_status==='posted'?'done':''?>"><i class="bi bi-patch-check"></i> Approved & Posted</span></div><?php endif?>
|
<?php if($invoice):?><div class="invoice-progress"><span class="done"><i class="bi bi-check-lg"></i> Header Draft</span><span class="<?=$invoice->delivery_status==='delivered'?'done':'optional'?>"><i class="bi bi-truck"></i> <?=$invoice->inventory_line_count?'Surat Jalan (Opsional)':'Tanpa Surat Jalan'?></span><span class="<?=in_array($invoice->workflow_status,array('submitted','approved','posted'),true)?'done':''?>"><i class="bi bi-send"></i> Diajukan</span><span class="<?=$invoice->workflow_status==='posted'?'done':''?>"><i class="bi bi-patch-check"></i> Approved & Posted</span></div><?php endif?>
|
||||||
|
|
||||||
<div class="invoice-editor-grid <?=$creating?'is-creating':''?>">
|
<div class="invoice-editor-grid <?=$creating?'is-creating':''?>">
|
||||||
<main class="invoice-editor-main">
|
<main class="invoice-editor-main">
|
||||||
@@ -57,7 +57,7 @@ function invLabel($value){$labels=array('draft'=>'Draft','submitted'=>'Menunggu
|
|||||||
</div>
|
</div>
|
||||||
<?php if($editable):?><button class="btn btn-primary btn-lg w-100 add-invoice-item-button" type="button" data-bs-toggle="modal" data-bs-target="#invoiceItemModal"><i class="bi bi-plus-lg"></i> Tambah Item</button><?php if((int)$invoice->pending_delivery_count>0):?><button class="btn btn-outline-primary w-100 generate-delivery"><i class="bi bi-truck"></i> Buat Surat Jalan</button><?php endif?><?php endif?>
|
<?php if($editable):?><button class="btn btn-primary btn-lg w-100 add-invoice-item-button" type="button" data-bs-toggle="modal" data-bs-target="#invoiceItemModal"><i class="bi bi-plus-lg"></i> Tambah Item</button><?php if((int)$invoice->pending_delivery_count>0):?><button class="btn btn-outline-primary w-100 generate-delivery"><i class="bi bi-truck"></i> Buat Surat Jalan</button><?php endif?><?php endif?>
|
||||||
<?php endif?>
|
<?php endif?>
|
||||||
<?php if($invoice):?><div class="card editor-card invoice-sidebar-actions"><div class="card-body"><div class="sidebar-next-status"><small>Status selanjutnya</small><b><?=$draft?($invoice->pending_delivery_count?'Buat dan posting Surat Jalan, lalu ajukan invoice.':'Ajukan invoice untuk approval.'):invLabel($invoice->workflow_status)?></b></div><div class="sidebar-action-buttons"><?php if($draft&&$p['submit']):?><button class="btn btn-primary submit-invoice"><i class="bi bi-send"></i> Ajukan Invoice</button><?php endif?><?php if($draft&&$p['delete']):?><button class="btn btn-outline-danger delete-invoice"><i class="bi bi-trash"></i> Batalkan Draft</button><?php endif?><?php if($invoice->workflow_status==='submitted'&&$p['approve']):?><button class="btn btn-success approve-invoice"><i class="bi bi-check-lg"></i> Setujui & Posting</button><button class="btn btn-outline-danger reject-invoice"><i class="bi bi-x-lg"></i> Tolak</button><?php endif?><?php if($invoice->workflow_status==='posted'&&in_array($invoice->status,array('unpaid','partial'),true)&&$p['post']):?><a class="btn btn-warning" href="<?=base_url('receivables?invoice_id='.$invoice->id)?>"><i class="bi bi-cash-coin"></i> Terima Pembayaran</a><?php endif?></div></div></div><?php endif?>
|
<?php if($invoice):?><div class="card editor-card invoice-sidebar-actions"><div class="card-body"><div class="sidebar-next-status"><small>Status selanjutnya</small><b><?=$draft?'Ajukan invoice untuk approval. Surat Jalan dapat dibuat bila diperlukan.':invLabel($invoice->workflow_status)?></b></div><div class="sidebar-action-buttons"><?php if($draft&&$p['submit']):?><button class="btn btn-primary submit-invoice"><i class="bi bi-send"></i> Ajukan Invoice</button><?php endif?><?php if($draft&&$p['delete']):?><button class="btn btn-outline-danger delete-invoice"><i class="bi bi-trash"></i> Batalkan Draft</button><?php endif?><?php if($invoice->workflow_status==='submitted'&&$p['approve']):?><button class="btn btn-success approve-invoice"><i class="bi bi-check-lg"></i> Setujui & Posting</button><button class="btn btn-outline-danger reject-invoice"><i class="bi bi-x-lg"></i> Tolak</button><?php endif?><?php if($invoice->workflow_status==='posted'&&in_array($invoice->status,array('unpaid','partial'),true)&&$p['post']):?><a class="btn btn-warning" href="<?=base_url('receivables?invoice_id='.$invoice->id)?>"><i class="bi bi-cash-coin"></i> Terima Pembayaran</a><?php endif?></div></div></div><?php endif?>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,14 +5,7 @@
|
|||||||
<div><span>SIKLUS PENJUALAN</span><h2>Invoice Penjualan</h2><p>Kelola tagihan customer, pengiriman barang bila diperlukan, dan penerimaan pembayaran.</p></div>
|
<div><span>SIKLUS PENJUALAN</span><h2>Invoice Penjualan</h2><p>Kelola tagihan customer, pengiriman barang bila diperlukan, dan penerimaan pembayaran.</p></div>
|
||||||
<?php if($p['create']):?><a class="btn btn-primary" href="<?=base_url('invoices/create')?>"><i class="bi bi-plus-lg"></i> Buat Invoice</a><?php endif?>
|
<?php if($p['create']):?><a class="btn btn-primary" href="<?=base_url('invoices/create')?>"><i class="bi bi-plus-lg"></i> Buat Invoice</a><?php endif?>
|
||||||
</header>
|
</header>
|
||||||
<nav class="sales-section-nav" aria-label="Bagian Penjualan">
|
<?php $this->load->view('sales/_section_nav',array('sales_section'=>'invoice','sales_summary'=>$summary)); ?>
|
||||||
<a href="<?=base_url('sales')?>"><i class="bi bi-speedometer2"></i><span>Ringkasan</span></a>
|
|
||||||
<a class="active" href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i><span>Invoice</span><?php if($summary['draft']):?><b><?=$summary['draft']?></b><?php endif?></a>
|
|
||||||
<a href="<?=base_url('sales/deliveries')?>"><i class="bi bi-truck"></i><span>Surat Jalan</span><?php if($summary['delivery']):?><b><?=$summary['delivery']?></b><?php endif?></a>
|
|
||||||
<a href="<?=base_url('receivables')?>"><i class="bi bi-cash-coin"></i><span>Piutang</span><?php if($summary['open_invoice']):?><b><?=$summary['open_invoice']?></b><?php endif?></a>
|
|
||||||
<a href="<?=base_url('sales/returns')?>"><i class="bi bi-arrow-counterclockwise"></i><span>Retur</span><?php if($summary['return']):?><b><?=$summary['return']?></b><?php endif?></a>
|
|
||||||
<a href="<?=base_url('customers')?>"><i class="bi bi-people"></i><span>Customer</span></a>
|
|
||||||
</nav>
|
|
||||||
<div class="invoice-metrics">
|
<div class="invoice-metrics">
|
||||||
<article><small>Penjualan bulan ini</small><strong>Rp <?=number_format($summary['month_sales'],2,',','.')?></strong></article>
|
<article><small>Penjualan bulan ini</small><strong>Rp <?=number_format($summary['month_sales'],2,',','.')?></strong></article>
|
||||||
<article><small>Invoice belum lunas</small><strong><?=$summary['open_invoice']?></strong><span><?=$summary['overdue']?> sudah jatuh tempo</span></article>
|
<article><small>Invoice belum lunas</small><strong><?=$summary['open_invoice']?></strong><span><?=$summary['overdue']?> sudah jatuh tempo</span></article>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
$(function(){
|
$(function(){
|
||||||
const esc=v=>$('<div>').text(v==null?'-':v).html(),money=v=>'Rp '+Number(v||0).toLocaleString('id-ID',{minimumFractionDigits:2,maximumFractionDigits:2});
|
const esc=v=>$('<div>').text(v==null?'-':v).html(),money=v=>'Rp '+Number(v||0).toLocaleString('id-ID',{minimumFractionDigits:2,maximumFractionDigits:2});
|
||||||
const table=$('#tableItems').DataTable({responsive:true,processing:true,serverSide:true,searchDelay:350,ajax:{url:'<?=base_url('items/get_data')?>',data:d=>{d.s='active';d.server=1}},pageLength:25,language:{search:'Cari:',processing:'Memuat data...',lengthMenu:'Tampilkan _MENU_',info:'_START_–_END_ dari _TOTAL_',paginate:{previous:'Sebelumnya',next:'Berikutnya'}}});
|
const table=$('#tableItems').DataTable({responsive:true,processing:true,serverSide:true,searchDelay:350,ajax:{url:'<?=base_url('items/get_data')?>',data:d=>{d.s='active';d.server=1}},pageLength:25,language:{search:'Cari:',processing:'Memuat data...',lengthMenu:'Tampilkan _MENU_',info:'_START_–_END_ dari _TOTAL_',paginate:{previous:'Sebelumnya',next:'Berikutnya'}}});
|
||||||
$(document).on('click','.btn-detail',function(){let id=$(this).data('id');$('#itemDetailBody').html('<div class="inventory-loading"><span class="spinner-border spinner-border-sm"></span> Memuat detail…</div>');bootstrap.Modal.getOrCreateInstance('#itemDetailModal').show();$.get('<?=base_url('items/detail')?>/'+id).done(function(r){let rows=(r.logs||[]).map(x=>'<tr><td>'+esc(x.created_at)+'</td><td>'+esc(x.gudang)+'</td><td><span class="status-chip '+(x.tipe==='masuk'?'status-approved':'status-rejected')+'">'+esc(x.tipe)+'</span></td><td class="text-end">'+Number(x.qty||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</td><td>'+esc(x.keterangan)+'</td><td>'+esc(x.ref_type)+' #'+esc(x.ref_id)+'</td></tr>').join('');$('#itemDetailBody').html('<div class="document-meta"><span>Kode<strong>'+esc(r.item.kode_detail)+'</strong></span><span>Nama Barang<strong>'+esc(r.item.nama_barang)+'</strong></span><span>Stok<strong>'+Number(r.item.stok||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</strong></span><span>Harga Beli<strong>'+money(r.item.harga_beli)+'</strong></span><span>Harga Jual<strong>'+money(r.item.harga_jual)+'</strong></span><span>Status<strong><span class="status-chip status-approved">AKTIF</span></strong></span></div><div class="d-flex justify-content-between align-items-center mt-4 mb-2"><h6 class="mb-0">Riwayat Stok</h6><button class="btn btn-sm btn-outline-danger stock-pdf" data-id="'+r.item.id+'"><i class="bi bi-file-earmark-pdf"></i> PDF Audit</button></div><div class="table-responsive"><table class="table inventory-table"><thead><tr><th>Tanggal</th><th>Gudang</th><th>Arah</th><th class="text-end">Qty</th><th>Keterangan</th><th>Sumber</th></tr></thead><tbody>'+rows+'</tbody></table></div>')}).fail(()=>AppAlert.toast('Detail barang tidak dapat dimuat.','error'))});
|
$(document).on('click','.btn-detail',function(){let id=$(this).data('id');$('#itemDetailBody').html('<div class="inventory-loading"><span class="spinner-border spinner-border-sm"></span> Memuat detail…</div>');bootstrap.Modal.getOrCreateInstance('#itemDetailModal').show();$.get('<?=base_url('items/detail')?>/'+id).done(function(r){let rows=(r.logs||[]).map(x=>'<tr><td>'+esc(x.created_at)+'</td><td>'+esc(x.gudang)+'</td><td><span class="status-chip '+(x.tipe==='masuk'?'status-approved':'status-rejected')+'">'+esc(x.tipe)+'</span></td><td class="text-end">'+Number(x.qty||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</td><td>'+esc(x.keterangan)+'</td><td>'+esc(x.ref_type)+' #'+esc(x.ref_id)+'</td></tr>').join('');$('#itemDetailBody').html('<div class="document-meta"><span>Kode<strong>'+esc(r.item.kode_detail)+'</strong></span><span>Nama Barang<strong>'+esc(r.item.nama_barang)+'</strong></span><span>Stok Tersedia<strong>'+Number(r.item.available_stock||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</strong></span><span>Dalam Invoice/Reservasi<strong>'+Number(r.item.reserved_stock||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</strong></span><span>Stok Fisik<strong>'+Number(r.item.physical_stock||0).toLocaleString('id-ID',{maximumFractionDigits:4})+'</strong></span><span>Harga Beli<strong>'+money(r.item.harga_beli)+'</strong></span><span>Harga Jual<strong>'+money(r.item.harga_jual)+'</strong></span><span>Status<strong><span class="status-chip status-approved">AKTIF</span></strong></span></div><div class="d-flex justify-content-between align-items-center mt-4 mb-2"><h6 class="mb-0">Riwayat Stok</h6><button class="btn btn-sm btn-outline-danger stock-pdf" data-id="'+r.item.id+'"><i class="bi bi-file-earmark-pdf"></i> PDF Audit</button></div><div class="table-responsive"><table class="table inventory-table"><thead><tr><th>Tanggal</th><th>Gudang</th><th>Arah</th><th class="text-end">Qty</th><th>Keterangan</th><th>Sumber</th></tr></thead><tbody>'+rows+'</tbody></table></div>')}).fail(()=>AppAlert.toast('Detail barang tidak dapat dimuat.','error'))});
|
||||||
$(document).on('click','.stock-pdf',function(){$('#barcodePrintModal .modal-title').text('PDF Kartu Stok');$('#barcodePrintModal iframe').attr('src','<?=base_url('items/stock_log_pdf')?>/'+$(this).data('id'));bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()});
|
$(document).on('click','.stock-pdf',function(){$('#barcodePrintModal .modal-title').text('PDF Kartu Stok');$('#barcodePrintModal iframe').attr('src','<?=base_url('items/stock_log_pdf')?>/'+$(this).data('id'));bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()});
|
||||||
$(document).on('click','.btn-print',function(){let id=$(this).data('id');AppAlert.prompt({title:'Cetak Barcode',html:'<label class="form-label d-block text-start">Status barcode</label><select id="printStatus" class="form-select mb-3"><option value="available">Tersedia / Belum Dijual</option><option value="sold_out">Sudah Terjual / Habis</option><option value="all">Semua Status</option></select><label class="form-label d-block text-start">Jumlah kolom</label><select id="printColumn" class="form-select mb-3"><option value="2">2 Kolom</option><option value="3" selected>3 Kolom</option><option value="4">4 Kolom</option></select><label class="form-label d-block text-start">Salinan per barcode</label><input id="printCopies" type="number" min="1" max="20" value="1" class="form-control">',preConfirm:()=>({status:$('#printStatus').val(),column:$('#printColumn').val(),duplicat:$('#printCopies').val()}),confirmButtonText:'Preview'}).then(r=>{if(!r.isConfirmed)return;let url='<?=base_url('items/print_barcode')?>/'+id+'?column='+r.value.column+'&duplicat='+r.value.duplicat+'&status='+encodeURIComponent(r.value.status);$('#barcodePrintModal .modal-title').text('Preview Barcode');$('#barcodePrintModal iframe').attr('src',url);bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()})});
|
$(document).on('click','.btn-print',function(){let id=$(this).data('id');AppAlert.prompt({title:'Cetak Barcode',html:'<label class="form-label d-block text-start">Status barcode</label><select id="printStatus" class="form-select mb-3"><option value="available">Tersedia / Belum Dijual</option><option value="sold_out">Sudah Terjual / Habis</option><option value="all">Semua Status</option></select><label class="form-label d-block text-start">Jumlah kolom</label><select id="printColumn" class="form-select mb-3"><option value="2">2 Kolom</option><option value="3" selected>3 Kolom</option><option value="4">4 Kolom</option></select><label class="form-label d-block text-start">Salinan per barcode</label><input id="printCopies" type="number" min="1" max="20" value="1" class="form-control">',preConfirm:()=>({status:$('#printStatus').val(),column:$('#printColumn').val(),duplicat:$('#printCopies').val()}),confirmButtonText:'Preview'}).then(r=>{if(!r.isConfirmed)return;let url='<?=base_url('items/print_barcode')?>/'+id+'?column='+r.value.column+'&duplicat='+r.value.duplicat+'&status='+encodeURIComponent(r.value.status);$('#barcodePrintModal .modal-title').text('Preview Barcode');$('#barcodePrintModal iframe').attr('src',url);bootstrap.Modal.getOrCreateInstance(document.getElementById('barcodePrintModal')).show()})});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<link rel="stylesheet" href="<?=base_url('assets/css/receivables-professional.css').'?v='.filemtime(FCPATH.'assets/css/receivables-professional.css')?>">
|
<link rel="stylesheet" href="<?=base_url('assets/css/receivables-professional.css').'?v='.filemtime(FCPATH.'assets/css/receivables-professional.css')?>">
|
||||||
<section class="receivable-workspace">
|
<section class="receivable-workspace">
|
||||||
<header class="invoice-hero"><div><span>SIKLUS PENJUALAN</span><h2>Piutang & Pembayaran</h2><p>Alokasikan pelunasan melalui akun Aktiva atau Passiva, termasuk pemindahbukuan simpanan customer.</p></div><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i> Daftar Invoice</a></header>
|
<header class="invoice-hero"><div><span>SIKLUS PENJUALAN</span><h2>Piutang & Pembayaran</h2><p>Alokasikan pelunasan melalui akun Aktiva atau Passiva, termasuk pemindahbukuan simpanan customer.</p></div><a class="btn btn-light" href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i> Daftar Invoice</a></header>
|
||||||
<nav class="sales-section-nav" aria-label="Bagian Penjualan"><a href="<?=base_url('sales')?>"><i class="bi bi-speedometer2"></i><span>Ringkasan</span></a><a href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i><span>Invoice</span></a><a href="<?=base_url('sales/deliveries')?>"><i class="bi bi-truck"></i><span>Surat Jalan</span></a><a class="active" href="<?=base_url('receivables')?>"><i class="bi bi-cash-coin"></i><span>Piutang</span></a><a href="<?=base_url('sales/returns')?>"><i class="bi bi-arrow-counterclockwise"></i><span>Retur</span></a><a href="<?=base_url('customers')?>"><i class="bi bi-people"></i><span>Customer</span></a></nav>
|
<?php $this->load->view('sales/_section_nav',array('sales_section'=>'receivable','sales_summary'=>$summary)); ?>
|
||||||
|
|
||||||
<div class="receivable-grid">
|
<div class="receivable-grid">
|
||||||
<div class="card receivable-card">
|
<div class="card receivable-card">
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
defined('BASEPATH') OR exit('No direct script access allowed');
|
||||||
|
|
||||||
|
$section = isset($sales_section) ? (string) $sales_section : '';
|
||||||
|
$counts = isset($sales_summary) && is_array($sales_summary) ? $sales_summary : array();
|
||||||
|
$count = static function ($key) use ($counts) {
|
||||||
|
return max(0, (int) ($counts[$key] ?? 0));
|
||||||
|
};
|
||||||
|
$links = array(
|
||||||
|
array('key'=>'summary', 'url'=>'sales', 'icon'=>'bi-speedometer2', 'label'=>'Ringkasan', 'badge'=>0),
|
||||||
|
array('key'=>'invoice', 'url'=>'invoices', 'icon'=>'bi-receipt', 'label'=>'Invoice', 'badge'=>$count('draft')),
|
||||||
|
array('key'=>'delivery','url'=>'sales/deliveries', 'icon'=>'bi-truck', 'label'=>'Surat Jalan', 'badge'=>$count('delivery')),
|
||||||
|
array('key'=>'receivable','url'=>'receivables', 'icon'=>'bi-cash-coin', 'label'=>'Piutang', 'badge'=>$count('open_invoice')),
|
||||||
|
array('key'=>'return', 'url'=>'sales/returns', 'icon'=>'bi-arrow-counterclockwise','label'=>'Retur', 'badge'=>$count('return')),
|
||||||
|
array('key'=>'customer','url'=>'customers', 'icon'=>'bi-people', 'label'=>'Customer', 'badge'=>0),
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<nav class="sales-section-nav" aria-label="Bagian Penjualan">
|
||||||
|
<?php foreach ($links as $link): ?>
|
||||||
|
<a class="<?= $section === $link['key'] ? 'active' : '' ?>" href="<?= base_url($link['url']) ?>">
|
||||||
|
<i class="bi <?= html_escape($link['icon']) ?>"></i>
|
||||||
|
<span><?= html_escape($link['label']) ?></span>
|
||||||
|
<?php if ($link['badge'] > 0): ?><b><?= number_format($link['badge'], 0, ',', '.') ?></b><?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</nav>
|
||||||
@@ -11,7 +11,7 @@ function saleStatus($v){$m=array('draft'=>'Draft','submitted'=>'Menunggu Approva
|
|||||||
<style>.sales-page[data-section="summary"] #salesDelivery,.sales-page[data-section="delivery"] .sales-metrics,.sales-page[data-section="delivery"] #salesReturn,.sales-page[data-section="return"] .sales-metrics,.sales-page[data-section="return"] #salesDelivery{display:none!important}</style>
|
<style>.sales-page[data-section="summary"] #salesDelivery,.sales-page[data-section="delivery"] .sales-metrics,.sales-page[data-section="delivery"] #salesReturn,.sales-page[data-section="return"] .sales-metrics,.sales-page[data-section="return"] #salesDelivery{display:none!important}</style>
|
||||||
<section class="sales-page" data-section="<?=html_escape($section)?>">
|
<section class="sales-page" data-section="<?=html_escape($section)?>">
|
||||||
<header class="sales-hero"><div><span>SIKLUS PENJUALAN</span><h2><?=html_escape($pageTitle)?></h2><p><?=html_escape($pageIntro)?></p></div><?php if($section==='return'&&$p['create']):?><a class="btn btn-primary" href="<?=base_url('sales/deliveries')?>"><i class="bi bi-arrow-counterclockwise"></i> Ajukan dari Surat Jalan</a><?php elseif($section==='delivery'):?><a class="btn btn-outline-primary" href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i> Lihat Invoice</a><?php elseif($p['create']):?><a class="btn btn-primary" href="<?=base_url('invoices/create')?>"><i class="bi bi-plus-lg"></i> Buat Invoice</a><?php endif?></header>
|
<header class="sales-hero"><div><span>SIKLUS PENJUALAN</span><h2><?=html_escape($pageTitle)?></h2><p><?=html_escape($pageIntro)?></p></div><?php if($section==='return'&&$p['create']):?><a class="btn btn-primary" href="<?=base_url('sales/deliveries')?>"><i class="bi bi-arrow-counterclockwise"></i> Ajukan dari Surat Jalan</a><?php elseif($section==='delivery'):?><a class="btn btn-outline-primary" href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i> Lihat Invoice</a><?php elseif($p['create']):?><a class="btn btn-primary" href="<?=base_url('invoices/create')?>"><i class="bi bi-plus-lg"></i> Buat Invoice</a><?php endif?></header>
|
||||||
<nav class="sales-section-nav" aria-label="Bagian Penjualan"><a class="<?=$section==='summary'?'active':''?>" href="<?=base_url('sales')?>"><i class="bi bi-speedometer2"></i><span>Ringkasan</span></a><a href="<?=base_url('invoices')?>"><i class="bi bi-receipt"></i><span>Invoice</span><?php if($summary['draft']):?><b><?=$summary['draft']?></b><?php endif?></a><a class="<?=$section==='delivery'?'active':''?>" href="<?=base_url('sales/deliveries')?>"><i class="bi bi-truck"></i><span>Surat Jalan</span><?php if($summary['delivery']):?><b><?=$summary['delivery']?></b><?php endif?></a><a href="<?=base_url('receivables')?>"><i class="bi bi-cash-coin"></i><span>Piutang</span><?php if($summary['open_invoice']):?><b><?=$summary['open_invoice']?></b><?php endif?></a><a class="<?=$section==='return'?'active':''?>" href="<?=base_url('sales/returns')?>"><i class="bi bi-arrow-counterclockwise"></i><span>Retur</span><?php if($summary['return']):?><b><?=$summary['return']?></b><?php endif?></a><a href="<?=base_url('customers')?>"><i class="bi bi-people"></i><span>Customer</span></a></nav>
|
<?php $this->load->view('sales/_section_nav',array('sales_section'=>$section,'sales_summary'=>$summary)); ?>
|
||||||
<div class="sales-metrics"><article><small>Penjualan bulan ini</small><strong><?=saleMoney($summary['month_sales'])?></strong></article><article><small>Invoice belum lunas</small><strong><?=$summary['open_invoice']?></strong><span><?=$summary['overdue']?> jatuh tempo</span></article><article><small>Draft / approval</small><strong><?=$summary['draft']?></strong><span><a href="<?=base_url('invoices')?>">Buka daftar invoice</a></span></article><article><small>Operasional</small><strong><?=$summary['delivery']+$summary['return']?></strong><span><?=$summary['delivery']?> pengiriman · <?=$summary['return']?> retur</span></article></div>
|
<div class="sales-metrics"><article><small>Penjualan bulan ini</small><strong><?=saleMoney($summary['month_sales'])?></strong></article><article><small>Invoice belum lunas</small><strong><?=$summary['open_invoice']?></strong><span><?=$summary['overdue']?> jatuh tempo</span></article><article><small>Draft / approval</small><strong><?=$summary['draft']?></strong><span><a href="<?=base_url('invoices')?>">Buka daftar invoice</a></span></article><article><small>Operasional</small><strong><?=$summary['delivery']+$summary['return']?></strong><span><?=$summary['delivery']?> pengiriman · <?=$summary['return']?> retur</span></article></div>
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-12" id="salesDelivery"><div class="card"><div class="card-header"><div><b>Pengiriman / Surat Jalan</b><small>Posting Surat Jalan adalah satu-satunya proses pengurangan stok fisik.</small></div><a class="btn btn-sm btn-outline-primary" href="<?=base_url('invoices')?>">Lihat Invoice</a></div><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Surat Jalan</th><th>Customer / Invoice</th><th>Tanggal</th><th>Gudang</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php foreach($deliveries as$d):?><tr><td><b><?=html_escape($d->delivery_no)?></b></td><td><?=html_escape($d->customer_name)?><small><?=html_escape($d->no_invoice?:'-')?></small></td><td><?=html_escape($d->delivery_date)?></td><td><?=html_escape($d->warehouse_name?:'-')?></td><td><span class="status status-<?=html_escape($d->status)?>"><?=saleStatus($d->status)?></span></td><td class="actions"><button class="btn btn-sm btn-outline-primary detail-delivery" data-id="<?=$d->id?>">Detail</button><?php if($p['export']):?><button class="btn btn-sm btn-outline-danger pdf-open" data-url="<?=base_url('sales/delivery_pdf/'.$d->id)?>">PDF</button><?php endif?><?php if($d->status==='draft'&&$p['post']):?><button class="btn btn-sm btn-success sale-action" data-url="<?=base_url('sales/post_delivery/'.$d->id)?>" data-confirm="Posting Surat Jalan dan keluarkan stok?">Post Pengiriman</button><?php endif?><?php if(in_array($d->status,array('posted','partially_returned'),true)&&$p['create']):?><button class="btn btn-sm btn-warning new-return" data-id="<?=$d->id?>">Ajukan Retur</button><?php endif?></td></tr><?php endforeach?><?php if(!$deliveries):?><tr><td colspan="6" class="empty">Belum ada dokumen pengiriman.</td></tr><?php endif?></tbody></table></div></div></div>
|
<div class="col-12" id="salesDelivery"><div class="card"><div class="card-header"><div><b>Pengiriman / Surat Jalan</b><small>Posting Surat Jalan adalah satu-satunya proses pengurangan stok fisik.</small></div><a class="btn btn-sm btn-outline-primary" href="<?=base_url('invoices')?>">Lihat Invoice</a></div><div class="table-responsive"><table class="table align-middle mb-0"><thead><tr><th>Surat Jalan</th><th>Customer / Invoice</th><th>Tanggal</th><th>Gudang</th><th>Status</th><th>Aksi</th></tr></thead><tbody><?php foreach($deliveries as$d):?><tr><td><b><?=html_escape($d->delivery_no)?></b></td><td><?=html_escape($d->customer_name)?><small><?=html_escape($d->no_invoice?:'-')?></small></td><td><?=html_escape($d->delivery_date)?></td><td><?=html_escape($d->warehouse_name?:'-')?></td><td><span class="status status-<?=html_escape($d->status)?>"><?=saleStatus($d->status)?></span></td><td class="actions"><button class="btn btn-sm btn-outline-primary detail-delivery" data-id="<?=$d->id?>">Detail</button><?php if($p['export']):?><button class="btn btn-sm btn-outline-danger pdf-open" data-url="<?=base_url('sales/delivery_pdf/'.$d->id)?>">PDF</button><?php endif?><?php if($d->status==='draft'&&$p['post']):?><button class="btn btn-sm btn-success sale-action" data-url="<?=base_url('sales/post_delivery/'.$d->id)?>" data-confirm="Posting Surat Jalan dan keluarkan stok?">Post Pengiriman</button><?php endif?><?php if(in_array($d->status,array('posted','partially_returned'),true)&&$p['create']):?><button class="btn btn-sm btn-warning new-return" data-id="<?=$d->id?>">Ajukan Retur</button><?php endif?></td></tr><?php endforeach?><?php if(!$deliveries):?><tr><td colspan="6" class="empty">Belum ada dokumen pengiriman.</td></tr><?php endif?></tbody></table></div></div></div>
|
||||||
|
|||||||
@@ -1 +1,62 @@
|
|||||||
<!doctype html><html><head><meta charset="utf-8"><style>@page{margin:35px}body{font-family:DejaVu Sans,sans-serif;font-size:11px;color:#20242c}.head{width:100%;margin-bottom:24px}.right{text-align:right}.box{border:1px solid #d8dee8;border-radius:8px;padding:14px}.grid{width:100%;border-collapse:collapse;margin-top:15px}.grid th,.grid td{border:1px solid #d8dee8;padding:8px}.grid th{background:#eef2f6}.total{font-size:18px;text-align:right;margin-top:16px}</style></head><body><table class="head"><tr><td><h2><?=html_escape($pdf_company->name??'Perusahaan')?></h2></td><td class="right"><h2>BUKTI PENERIMAAN</h2><b><?=html_escape($payment->payment_no)?></b></td></tr></table><div class="box"><b>Diterima dari:</b> <?=html_escape($payment->customer_name)?><br><b>Tanggal:</b> <?=$payment->tanggal?><br><b>Referensi:</b> <?=html_escape($payment->reference_no?:'-')?><br><b>Catatan:</b> <?=html_escape($payment->notes?:'-')?></div><h3>Alokasi Invoice</h3><table class="grid"><thead><tr><th>Invoice</th><th class="right">Nilai</th></tr></thead><tbody><?php foreach($allocations as$a):?><tr><td><?=html_escape($a->no_invoice)?></td><td class="right">Rp <?=number_format($a->amount,2,',','.')?></td></tr><?php endforeach?></tbody></table><h3>Sumber Kas/Bank</h3><table class="grid"><thead><tr><th>Akun</th><th class="right">Nilai</th></tr></thead><tbody><?php foreach($sources as$s):?><tr><td><?=html_escape($s->kode_akun.' - '.$s->nama_akun)?></td><td class="right">Rp <?=number_format($s->amount,2,',','.')?></td></tr><?php endforeach?></tbody></table><div class="total"><b>Total diterima: Rp <?=number_format($payment->jumlah,2,',','.')?></b></div></body></html>
|
<?php
|
||||||
|
$company=$pdf_company;
|
||||||
|
$currencyCode=isset($pdf_currency->code)?$pdf_currency->code:($company->base_currency??'IDR');
|
||||||
|
$currencySymbol=isset($pdf_currency->symbol)&&trim((string)$pdf_currency->symbol)!==''?$pdf_currency->symbol:'Rp';
|
||||||
|
$allocatedTotal=0;foreach($allocations as$allocation)$allocatedTotal+=(float)$allocation->amount;
|
||||||
|
$sourceTotal=0;foreach($sources as$source)$sourceTotal+=(float)$source->amount;
|
||||||
|
$advance=max(0,round((float)$payment->jumlah-$allocatedTotal,2));
|
||||||
|
function receiptMoney($value){return number_format((float)$value,2,',','.');}
|
||||||
|
function receiptDate($value){
|
||||||
|
if(!$value)return'-';$time=strtotime($value);if(!$time)return$value;
|
||||||
|
$months=array(1=>'Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember');
|
||||||
|
return date('j',$time).' '.$months[(int)date('n',$time)].' '.date('Y',$time);
|
||||||
|
}
|
||||||
|
function receiptWords($number){
|
||||||
|
$number=abs((int)$number);$base=array('','satu','dua','tiga','empat','lima','enam','tujuh','delapan','sembilan','sepuluh','sebelas');
|
||||||
|
if($number<12)return$base[$number];
|
||||||
|
if($number<20)return receiptWords($number-10).' belas';
|
||||||
|
if($number<100)return trim(receiptWords(intdiv($number,10)).' puluh '.receiptWords($number%10));
|
||||||
|
if($number<200)return trim('seratus '.receiptWords($number-100));
|
||||||
|
if($number<1000)return trim(receiptWords(intdiv($number,100)).' ratus '.receiptWords($number%100));
|
||||||
|
if($number<2000)return trim('seribu '.receiptWords($number-1000));
|
||||||
|
if($number<1000000)return trim(receiptWords(intdiv($number,1000)).' ribu '.receiptWords($number%1000));
|
||||||
|
if($number<1000000000)return trim(receiptWords(intdiv($number,1000000)).' juta '.receiptWords($number%1000000));
|
||||||
|
if($number<1000000000000)return trim(receiptWords(intdiv($number,1000000000)).' miliar '.receiptWords($number%1000000000));
|
||||||
|
return trim(receiptWords(intdiv($number,1000000000000)).' triliun '.receiptWords($number%1000000000000));
|
||||||
|
}
|
||||||
|
$amountWords=ucfirst(receiptWords((int)floor((float)$payment->jumlah))).' rupiah';
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Bukti Penerimaan <?=html_escape($payment->payment_no)?></title>
|
||||||
|
<style>
|
||||||
|
@page{margin:25px 30px 35px}body{font-family:DejaVu Sans,sans-serif;font-size:9px;color:#172033;line-height:1.45;margin:0}.header{width:100%;border-collapse:collapse;margin-bottom:16px}.header td{vertical-align:top}.brand{width:62%}.logo{float:left;width:58px;height:58px;object-fit:contain;margin-right:10px}.company-name{font-size:14px;font-weight:700;color:#172b4d;margin-bottom:2px}.company-legal{font-size:8px;color:#667085;margin-bottom:3px}.company-contact{font-size:8px;color:#475467;line-height:1.4}.document{text-align:right}.document-title{font-size:18px;font-weight:700;color:#172b4d;letter-spacing:.03em}.document-number{font-size:10px;font-weight:700;margin-top:3px}.status{display:inline-block;background:#e8f7ef;color:#087443;border:1px solid #a9dfc4;padding:3px 9px;margin-top:7px;font-size:7.5px;font-weight:700;letter-spacing:.08em}.accent{height:3px;background:#f47b20;margin-bottom:15px}.amount-panel{width:100%;border-collapse:collapse;background:#172b4d;color:#fff;margin-bottom:14px}.amount-panel td{padding:12px 14px}.amount-label{font-size:7.5px;letter-spacing:.12em;color:#d7e0ef}.amount-value{text-align:right;font-size:17px;font-weight:700}.info{width:100%;border-collapse:collapse;margin-bottom:15px}.info td{width:50%;vertical-align:top;border:1px solid #d9e0ea;padding:10px 11px}.info td+td{border-left:0}.eyebrow{font-size:7px;color:#667085;font-weight:700;letter-spacing:.1em;text-transform:uppercase;margin-bottom:4px}.customer{font-size:11px;font-weight:700;color:#172b4d;margin-bottom:3px}.meta{width:100%;border-collapse:collapse}.meta td{border:0!important;padding:1px 0!important;font-size:8.5px}.meta .label{width:42%;color:#667085}.meta .value{text-align:right;font-weight:600}.section{margin-top:14px}.section-title{font-size:10px;font-weight:700;color:#172b4d;margin:0 0 6px}.section-subtitle{font-size:7.5px;color:#667085;font-weight:400}.grid{width:100%;border-collapse:collapse}.grid th{background:#f1f4f8;color:#344054;font-size:7px;letter-spacing:.06em;text-transform:uppercase;text-align:left}.grid th,.grid td{border:1px solid #d9e0ea;padding:6px 7px}.grid .number{width:24px;text-align:center}.right{text-align:right!important}.center{text-align:center!important}.strong{font-weight:700;color:#172b4d}.empty{text-align:center;color:#667085;padding:12px!important}.summary{width:46%;margin:8px 0 0 auto;border-collapse:collapse}.summary td{padding:3px 2px}.summary td:last-child{text-align:right}.summary .grand td{border-top:1px solid #98a2b3;padding-top:6px;font-size:10px;font-weight:700;color:#172b4d}.words{border-left:3px solid #f47b20;background:#fff8f1;padding:8px 10px;margin-top:13px;color:#344054}.words-label{font-size:7px;color:#a14b0b;letter-spacing:.08em;font-weight:700;text-transform:uppercase}.notes{margin-top:10px;padding:8px 10px;border:1px solid #d9e0ea;background:#fafbfc}.signatures{width:100%;border-collapse:collapse;margin-top:27px;text-align:center}.signatures td{width:50%;height:72px;vertical-align:top;color:#475467}.signature-name{font-weight:700;color:#172b4d;border-top:1px solid #98a2b3;padding-top:4px;margin:42px auto 0;width:70%}.legal-note{font-size:7.5px;color:#667085;text-align:center;border-top:1px solid #e4e7ec;padding-top:7px;margin-top:12px}.footer{position:fixed;left:0;right:0;bottom:-22px;font-size:7px;color:#98a2b3}.footer-right{float:right}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table class="header"><tr><td class="brand">
|
||||||
|
<?php if(!empty($pdf_logo_data)):?><img class="logo" src="<?=$pdf_logo_data?>" alt="Logo"><?php endif?>
|
||||||
|
<div class="company-name"><?=html_escape($company->name??'Perusahaan')?></div>
|
||||||
|
<?php if(!empty($company->legal_name)&&$company->legal_name!==$company->name):?><div class="company-legal"><?=html_escape($company->legal_name)?></div><?php endif?>
|
||||||
|
<div class="company-contact"><?=nl2br(html_escape($company->address?:'-'))?><br>Telp: <?=html_escape($company->phone?:'-')?><?php if(!empty($company->email)):?> | <?=html_escape($company->email)?><?php endif?></div>
|
||||||
|
</td><td class="document"><div class="document-title">BUKTI PENERIMAAN</div><div class="document-number"><?=html_escape($payment->payment_no)?></div><span class="status">PEMBAYARAN TERCATAT</span></td></tr></table>
|
||||||
|
<div class="accent"></div>
|
||||||
|
|
||||||
|
<table class="amount-panel"><tr><td><div class="amount-label">TOTAL DANA DITERIMA</div><div><?=html_escape($currencyCode)?> • <?=receiptDate($payment->tanggal)?></div></td><td class="amount-value"><?=html_escape($currencySymbol)?> <?=receiptMoney($payment->jumlah)?></td></tr></table>
|
||||||
|
|
||||||
|
<table class="info"><tr><td><div class="eyebrow">Diterima dari</div><div class="customer"><?=html_escape($payment->customer_name)?></div><div><?=nl2br(html_escape($payment->customer_address?:'-'))?></div><?php if(!empty($payment->customer_phone)||!empty($payment->customer_email)):?><div style="margin-top:3px;color:#667085"><?=html_escape($payment->customer_phone?:'-')?><?php if(!empty($payment->customer_email)):?> • <?=html_escape($payment->customer_email)?><?php endif?></div><?php endif?></td><td><div class="eyebrow">Informasi penerimaan</div><table class="meta"><tr><td class="label">Tanggal</td><td class="value"><?=receiptDate($payment->tanggal)?></td></tr><tr><td class="label">Referensi</td><td class="value"><?=html_escape($payment->reference_no?:'-')?></td></tr><tr><td class="label">Metode</td><td class="value"><?=html_escape($payment->metode==='multi_account'?'Multi Akun':ucwords(str_replace('_',' ',$payment->metode?:'Pembayaran'))) ?></td></tr><tr><td class="label">Status</td><td class="value">TERCATAT</td></tr></table></td></tr></table>
|
||||||
|
|
||||||
|
<div class="section"><div class="section-title">Alokasi Pembayaran <span class="section-subtitle">— rincian tagihan yang dilunasi</span></div><table class="grid"><thead><tr><th class="number">No.</th><th>Nomor Invoice</th><th>Tanggal Invoice</th><th>Jatuh Tempo</th><th class="right">Nilai Dialokasikan</th></tr></thead><tbody><?php foreach($allocations as$i=>$allocation):?><tr><td class="number"><?=$i+1?></td><td class="strong"><?=html_escape($allocation->no_invoice)?></td><td><?=receiptDate($allocation->invoice_date)?></td><td><?=receiptDate($allocation->jatuh_tempo)?></td><td class="right strong"><?=html_escape($currencySymbol)?> <?=receiptMoney($allocation->amount)?></td></tr><?php endforeach?><?php if(!$allocations):?><tr><td colspan="5" class="empty">Pembayaran belum dialokasikan ke invoice tertentu.</td></tr><?php endif?></tbody></table><?php if($advance>.001):?><table class="summary"><tr><td>Alokasi invoice</td><td><?=receiptMoney($allocatedTotal)?></td></tr><tr><td>Uang muka customer</td><td><?=receiptMoney($advance)?></td></tr><tr class="grand"><td>Total diterima</td><td><?=html_escape($currencySymbol)?> <?=receiptMoney($payment->jumlah)?></td></tr></table><?php endif?></div>
|
||||||
|
|
||||||
|
<div class="section"><div class="section-title">Sumber Penerimaan <span class="section-subtitle">— akun tujuan pencatatan dana</span></div><table class="grid"><thead><tr><th class="number">No.</th><th>Kode Akun</th><th>Nama Akun Kas/Bank</th><th class="right">Nominal</th></tr></thead><tbody><?php foreach($sources as$i=>$source):?><tr><td class="number"><?=$i+1?></td><td><?=html_escape($source->kode_akun)?></td><td class="strong"><?=html_escape($source->nama_akun)?></td><td class="right strong"><?=html_escape($currencySymbol)?> <?=receiptMoney($source->amount)?></td></tr><?php endforeach?><?php if(!$sources):?><tr><td colspan="4" class="empty">Sumber penerimaan tidak tersedia.</td></tr><?php endif?></tbody><tfoot><tr><td colspan="3" class="right strong">TOTAL PENERIMAAN</td><td class="right strong"><?=html_escape($currencySymbol)?> <?=receiptMoney($sourceTotal)?></td></tr></tfoot></table></div>
|
||||||
|
|
||||||
|
<div class="words"><div class="words-label">Terbilang</div><b><?=html_escape($amountWords)?></b></div>
|
||||||
|
<div class="notes"><div class="eyebrow">Catatan pembayaran</div><?=nl2br(html_escape($payment->notes?:'Tidak ada catatan tambahan.'))?></div>
|
||||||
|
|
||||||
|
<table class="signatures"><tr><td>Dicatat oleh<div class="signature-name"><?=html_escape($payment->creator_name?:'-')?></div><div>Finance / Administrasi</div></td><td>Pihak Pembayar<div class="signature-name"><?=html_escape($payment->customer_name)?></div><div>Customer</div></td></tr></table>
|
||||||
|
<div class="legal-note">Dokumen ini merupakan bukti penerimaan pembayaran yang tercatat pada sistem <?=html_escape($company->name??'perusahaan')?> dengan nomor referensi unik <?=html_escape($payment->payment_no)?>.</div>
|
||||||
|
<div class="footer"><span>Dicetak <?=date('d-m-Y H:i')?> • <?=html_escape($payment->payment_no)?></span><span class="footer-right"><?=html_escape($company->company_code??'')?></span></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
@@ -196,6 +196,11 @@
|
|||||||
color: #067647;
|
color: #067647;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
.invoice-progress span.optional {
|
||||||
|
background: #fff6ed;
|
||||||
|
color: #b54708;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
.invoice-editor-grid {
|
.invoice-editor-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(330px, 37%) minmax(0, 63%);
|
grid-template-columns: minmax(330px, 37%) minmax(0, 63%);
|
||||||
|
|||||||
@@ -111,13 +111,17 @@
|
|||||||
}
|
}
|
||||||
function invoiceButtons(row) {
|
function invoiceButtons(row) {
|
||||||
var p = cfg.permissions || {},
|
var p = cfg.permissions || {},
|
||||||
html =
|
isDraft = row.workflow_status === "draft",
|
||||||
'<div class="invoice-table-actions"><a class="btn btn-sm btn-outline-primary" href="' +
|
isPaid = row.status === "paid",
|
||||||
|
html = '<div class="invoice-table-actions">';
|
||||||
|
if (!isPaid && (!isDraft || !p.update))
|
||||||
|
html +=
|
||||||
|
'<a class="btn btn-sm btn-outline-primary" href="' +
|
||||||
cfg.base +
|
cfg.base +
|
||||||
"invoices/detail/" +
|
"invoices/detail/" +
|
||||||
row.id +
|
row.id +
|
||||||
'"><i class="bi bi-eye"></i> Detail</a>';
|
'"><i class="bi bi-eye"></i> Detail</a>';
|
||||||
if (row.workflow_status === "draft" && p.update)
|
if (!isPaid && isDraft && p.update)
|
||||||
html +=
|
html +=
|
||||||
'<a class="btn btn-sm btn-outline-success" href="' +
|
'<a class="btn btn-sm btn-outline-success" href="' +
|
||||||
cfg.base +
|
cfg.base +
|
||||||
@@ -125,7 +129,8 @@
|
|||||||
row.id +
|
row.id +
|
||||||
'"><i class="bi bi-pencil"></i> Kelola</a>';
|
'"><i class="bi bi-pencil"></i> Kelola</a>';
|
||||||
if (
|
if (
|
||||||
row.workflow_status === "draft" &&
|
!isPaid &&
|
||||||
|
isDraft &&
|
||||||
Number(row.pending_delivery_count || 0) > 0 &&
|
Number(row.pending_delivery_count || 0) > 0 &&
|
||||||
p.update
|
p.update
|
||||||
)
|
)
|
||||||
@@ -142,12 +147,12 @@
|
|||||||
"invoices/pdf/" +
|
"invoices/pdf/" +
|
||||||
row.id +
|
row.id +
|
||||||
'"><i class="bi bi-file-pdf"></i></button>';
|
'"><i class="bi bi-file-pdf"></i></button>';
|
||||||
if (row.workflow_status === "draft" && p.submit)
|
if (!isPaid && isDraft && p.submit)
|
||||||
html +=
|
html +=
|
||||||
'<button class="btn btn-sm btn-primary row-submit" data-id="' +
|
'<button class="btn btn-sm btn-primary row-submit" data-id="' +
|
||||||
row.id +
|
row.id +
|
||||||
'">Ajukan</button>';
|
'">Ajukan</button>';
|
||||||
if (row.workflow_status === "submitted" && p.approve)
|
if (!isPaid && row.workflow_status === "submitted" && p.approve)
|
||||||
html +=
|
html +=
|
||||||
'<button class="btn btn-sm btn-success row-approve" data-id="' +
|
'<button class="btn btn-sm btn-success row-approve" data-id="' +
|
||||||
row.id +
|
row.id +
|
||||||
@@ -155,6 +160,7 @@
|
|||||||
row.id +
|
row.id +
|
||||||
'">Tolak</button>';
|
'">Tolak</button>';
|
||||||
if (
|
if (
|
||||||
|
!isPaid &&
|
||||||
row.workflow_status === "posted" &&
|
row.workflow_status === "posted" &&
|
||||||
["unpaid", "partial"].indexOf(row.status) >= 0 &&
|
["unpaid", "partial"].indexOf(row.status) >= 0 &&
|
||||||
p.post
|
p.post
|
||||||
@@ -165,7 +171,7 @@
|
|||||||
"receivables?invoice_id=" +
|
"receivables?invoice_id=" +
|
||||||
row.id +
|
row.id +
|
||||||
'">Bayar</a>';
|
'">Bayar</a>';
|
||||||
if (row.workflow_status === "draft" && p.delete)
|
if (!isPaid && isDraft && p.delete)
|
||||||
html +=
|
html +=
|
||||||
'<button class="btn btn-sm btn-outline-danger row-delete" data-id="' +
|
'<button class="btn btn-sm btn-outline-danger row-delete" data-id="' +
|
||||||
row.id +
|
row.id +
|
||||||
@@ -1066,7 +1072,7 @@
|
|||||||
workflow(
|
workflow(
|
||||||
"submit",
|
"submit",
|
||||||
"Ajukan invoice?",
|
"Ajukan invoice?",
|
||||||
"Pastikan seluruh Surat Jalan barang sudah diposting.",
|
"Pastikan data item sudah benar. Surat Jalan bersifat opsional dan tidak menghambat pengajuan.",
|
||||||
"Ya, ajukan",
|
"Ya, ajukan",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1085,7 +1091,7 @@
|
|||||||
workflow(
|
workflow(
|
||||||
"delete_draft",
|
"delete_draft",
|
||||||
"Batalkan Draft invoice?",
|
"Batalkan Draft invoice?",
|
||||||
"Reservasi barcode akan dilepas. Tindakan ini tidak dapat dibatalkan.",
|
"Stok/barcode akan tersedia kembali dan jurnal awal akan dibalik otomatis. Tindakan ini tidak dapat dibatalkan.",
|
||||||
"Ya, batalkan",
|
"Ya, batalkan",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -1127,11 +1133,17 @@
|
|||||||
icon: "warning",
|
icon: "warning",
|
||||||
title: "Tolak invoice?",
|
title: "Tolak invoice?",
|
||||||
input: "textarea",
|
input: "textarea",
|
||||||
|
inputLabel: "Alasan penolakan",
|
||||||
|
inputValidator: function (v) {
|
||||||
|
return !String(v || "").trim() ? "Alasan wajib diisi." : undefined;
|
||||||
|
},
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
})
|
})
|
||||||
).then(function (r) {
|
).then(function (r) {
|
||||||
if (!r.isConfirmed) return;
|
if (!r.isConfirmed) return;
|
||||||
post(cfg.base + "invoices/reject/" + id, { reason: r.value })
|
var reason = String(r.value || "").trim();
|
||||||
|
if (!reason) return notify("Alasan penolakan wajib diisi.", "error");
|
||||||
|
post(cfg.base + "invoices/reject/" + id, { reason: reason })
|
||||||
.done(function (x) {
|
.done(function (x) {
|
||||||
if (!x.status) return notify(x.message, "error");
|
if (!x.status) return notify(x.message, "error");
|
||||||
notify(x.message, "success");
|
notify(x.message, "success");
|
||||||
@@ -1147,7 +1159,7 @@
|
|||||||
$(this).data("id"),
|
$(this).data("id"),
|
||||||
"submit",
|
"submit",
|
||||||
"Ajukan invoice?",
|
"Ajukan invoice?",
|
||||||
"Pastikan data item dan pengiriman sudah lengkap.",
|
"Pastikan data item sudah benar. Surat Jalan bersifat opsional dan tidak menghambat pengajuan.",
|
||||||
"Ya, ajukan",
|
"Ya, ajukan",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
@@ -1180,7 +1192,7 @@
|
|||||||
$(this).data("id"),
|
$(this).data("id"),
|
||||||
"delete_draft",
|
"delete_draft",
|
||||||
"Batalkan Draft invoice?",
|
"Batalkan Draft invoice?",
|
||||||
"Reservasi barcode akan dilepas dan histori pembatalan tetap dicatat.",
|
"Stok/barcode akan tersedia kembali, jurnal awal dibalik otomatis, dan histori pembatalan tetap dicatat.",
|
||||||
"Ya, batalkan",
|
"Ya, batalkan",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 638 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 638 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 638 KiB |
+569
@@ -0,0 +1,569 @@
|
|||||||
|
{
|
||||||
|
"codeToName": {
|
||||||
|
"32": "space",
|
||||||
|
"160": "space",
|
||||||
|
"33": "exclam",
|
||||||
|
"34": "quotedbl",
|
||||||
|
"35": "numbersign",
|
||||||
|
"36": "dollar",
|
||||||
|
"37": "percent",
|
||||||
|
"38": "ampersand",
|
||||||
|
"146": "quoteright",
|
||||||
|
"40": "parenleft",
|
||||||
|
"41": "parenright",
|
||||||
|
"42": "asterisk",
|
||||||
|
"43": "plus",
|
||||||
|
"44": "comma",
|
||||||
|
"45": "hyphen",
|
||||||
|
"173": "hyphen",
|
||||||
|
"46": "period",
|
||||||
|
"47": "slash",
|
||||||
|
"48": "zero",
|
||||||
|
"49": "one",
|
||||||
|
"50": "two",
|
||||||
|
"51": "three",
|
||||||
|
"52": "four",
|
||||||
|
"53": "five",
|
||||||
|
"54": "six",
|
||||||
|
"55": "seven",
|
||||||
|
"56": "eight",
|
||||||
|
"57": "nine",
|
||||||
|
"58": "colon",
|
||||||
|
"59": "semicolon",
|
||||||
|
"60": "less",
|
||||||
|
"61": "equal",
|
||||||
|
"62": "greater",
|
||||||
|
"63": "question",
|
||||||
|
"64": "at",
|
||||||
|
"65": "A",
|
||||||
|
"66": "B",
|
||||||
|
"67": "C",
|
||||||
|
"68": "D",
|
||||||
|
"69": "E",
|
||||||
|
"70": "F",
|
||||||
|
"71": "G",
|
||||||
|
"72": "H",
|
||||||
|
"73": "I",
|
||||||
|
"74": "J",
|
||||||
|
"75": "K",
|
||||||
|
"76": "L",
|
||||||
|
"77": "M",
|
||||||
|
"78": "N",
|
||||||
|
"79": "O",
|
||||||
|
"80": "P",
|
||||||
|
"81": "Q",
|
||||||
|
"82": "R",
|
||||||
|
"83": "S",
|
||||||
|
"84": "T",
|
||||||
|
"85": "U",
|
||||||
|
"86": "V",
|
||||||
|
"87": "W",
|
||||||
|
"88": "X",
|
||||||
|
"89": "Y",
|
||||||
|
"90": "Z",
|
||||||
|
"91": "bracketleft",
|
||||||
|
"92": "backslash",
|
||||||
|
"93": "bracketright",
|
||||||
|
"94": "asciicircum",
|
||||||
|
"95": "underscore",
|
||||||
|
"145": "quoteleft",
|
||||||
|
"97": "a",
|
||||||
|
"98": "b",
|
||||||
|
"99": "c",
|
||||||
|
"100": "d",
|
||||||
|
"101": "e",
|
||||||
|
"102": "f",
|
||||||
|
"103": "g",
|
||||||
|
"104": "h",
|
||||||
|
"105": "i",
|
||||||
|
"106": "j",
|
||||||
|
"107": "k",
|
||||||
|
"108": "l",
|
||||||
|
"109": "m",
|
||||||
|
"110": "n",
|
||||||
|
"111": "o",
|
||||||
|
"112": "p",
|
||||||
|
"113": "q",
|
||||||
|
"114": "r",
|
||||||
|
"115": "s",
|
||||||
|
"116": "t",
|
||||||
|
"117": "u",
|
||||||
|
"118": "v",
|
||||||
|
"119": "w",
|
||||||
|
"120": "x",
|
||||||
|
"121": "y",
|
||||||
|
"122": "z",
|
||||||
|
"123": "braceleft",
|
||||||
|
"124": "bar",
|
||||||
|
"125": "braceright",
|
||||||
|
"126": "asciitilde",
|
||||||
|
"161": "exclamdown",
|
||||||
|
"162": "cent",
|
||||||
|
"163": "sterling",
|
||||||
|
"165": "yen",
|
||||||
|
"131": "florin",
|
||||||
|
"167": "section",
|
||||||
|
"164": "currency",
|
||||||
|
"39": "quotesingle",
|
||||||
|
"147": "quotedblleft",
|
||||||
|
"171": "guillemotleft",
|
||||||
|
"139": "guilsinglleft",
|
||||||
|
"155": "guilsinglright",
|
||||||
|
"150": "endash",
|
||||||
|
"134": "dagger",
|
||||||
|
"135": "daggerdbl",
|
||||||
|
"183": "periodcentered",
|
||||||
|
"182": "paragraph",
|
||||||
|
"149": "bullet",
|
||||||
|
"130": "quotesinglbase",
|
||||||
|
"132": "quotedblbase",
|
||||||
|
"148": "quotedblright",
|
||||||
|
"187": "guillemotright",
|
||||||
|
"133": "ellipsis",
|
||||||
|
"137": "perthousand",
|
||||||
|
"191": "questiondown",
|
||||||
|
"96": "grave",
|
||||||
|
"180": "acute",
|
||||||
|
"136": "circumflex",
|
||||||
|
"152": "tilde",
|
||||||
|
"175": "macron",
|
||||||
|
"168": "dieresis",
|
||||||
|
"184": "cedilla",
|
||||||
|
"151": "emdash",
|
||||||
|
"198": "AE",
|
||||||
|
"170": "ordfeminine",
|
||||||
|
"216": "Oslash",
|
||||||
|
"140": "OE",
|
||||||
|
"186": "ordmasculine",
|
||||||
|
"230": "ae",
|
||||||
|
"248": "oslash",
|
||||||
|
"156": "oe",
|
||||||
|
"223": "germandbls",
|
||||||
|
"207": "Idieresis",
|
||||||
|
"233": "eacute",
|
||||||
|
"159": "Ydieresis",
|
||||||
|
"247": "divide",
|
||||||
|
"221": "Yacute",
|
||||||
|
"194": "Acircumflex",
|
||||||
|
"225": "aacute",
|
||||||
|
"219": "Ucircumflex",
|
||||||
|
"253": "yacute",
|
||||||
|
"234": "ecircumflex",
|
||||||
|
"220": "Udieresis",
|
||||||
|
"218": "Uacute",
|
||||||
|
"203": "Edieresis",
|
||||||
|
"169": "copyright",
|
||||||
|
"229": "aring",
|
||||||
|
"224": "agrave",
|
||||||
|
"227": "atilde",
|
||||||
|
"154": "scaron",
|
||||||
|
"237": "iacute",
|
||||||
|
"251": "ucircumflex",
|
||||||
|
"226": "acircumflex",
|
||||||
|
"231": "ccedilla",
|
||||||
|
"222": "Thorn",
|
||||||
|
"179": "threesuperior",
|
||||||
|
"210": "Ograve",
|
||||||
|
"192": "Agrave",
|
||||||
|
"215": "multiply",
|
||||||
|
"250": "uacute",
|
||||||
|
"255": "ydieresis",
|
||||||
|
"238": "icircumflex",
|
||||||
|
"202": "Ecircumflex",
|
||||||
|
"228": "adieresis",
|
||||||
|
"235": "edieresis",
|
||||||
|
"205": "Iacute",
|
||||||
|
"177": "plusminus",
|
||||||
|
"166": "brokenbar",
|
||||||
|
"174": "registered",
|
||||||
|
"200": "Egrave",
|
||||||
|
"142": "Zcaron",
|
||||||
|
"208": "Eth",
|
||||||
|
"199": "Ccedilla",
|
||||||
|
"193": "Aacute",
|
||||||
|
"196": "Adieresis",
|
||||||
|
"232": "egrave",
|
||||||
|
"211": "Oacute",
|
||||||
|
"243": "oacute",
|
||||||
|
"239": "idieresis",
|
||||||
|
"212": "Ocircumflex",
|
||||||
|
"217": "Ugrave",
|
||||||
|
"254": "thorn",
|
||||||
|
"178": "twosuperior",
|
||||||
|
"214": "Odieresis",
|
||||||
|
"181": "mu",
|
||||||
|
"236": "igrave",
|
||||||
|
"190": "threequarters",
|
||||||
|
"153": "trademark",
|
||||||
|
"204": "Igrave",
|
||||||
|
"189": "onehalf",
|
||||||
|
"244": "ocircumflex",
|
||||||
|
"241": "ntilde",
|
||||||
|
"201": "Eacute",
|
||||||
|
"188": "onequarter",
|
||||||
|
"138": "Scaron",
|
||||||
|
"176": "degree",
|
||||||
|
"242": "ograve",
|
||||||
|
"249": "ugrave",
|
||||||
|
"209": "Ntilde",
|
||||||
|
"245": "otilde",
|
||||||
|
"195": "Atilde",
|
||||||
|
"197": "Aring",
|
||||||
|
"213": "Otilde",
|
||||||
|
"206": "Icircumflex",
|
||||||
|
"172": "logicalnot",
|
||||||
|
"246": "odieresis",
|
||||||
|
"252": "udieresis",
|
||||||
|
"240": "eth",
|
||||||
|
"158": "zcaron",
|
||||||
|
"185": "onesuperior",
|
||||||
|
"128": "Euro"
|
||||||
|
},
|
||||||
|
"isUnicode": false,
|
||||||
|
"FontName": "Times-Bold",
|
||||||
|
"FullName": "Times Bold",
|
||||||
|
"FamilyName": "Times",
|
||||||
|
"Weight": "Bold",
|
||||||
|
"ItalicAngle": "0",
|
||||||
|
"IsFixedPitch": "false",
|
||||||
|
"CharacterSet": "ExtendedRoman",
|
||||||
|
"FontBBox": [
|
||||||
|
"-168",
|
||||||
|
"-218",
|
||||||
|
"1000",
|
||||||
|
"935"
|
||||||
|
],
|
||||||
|
"UnderlinePosition": "-100",
|
||||||
|
"UnderlineThickness": "50",
|
||||||
|
"Version": "002.000",
|
||||||
|
"EncodingScheme": "WinAnsiEncoding",
|
||||||
|
"CapHeight": "676",
|
||||||
|
"XHeight": "461",
|
||||||
|
"Ascender": "683",
|
||||||
|
"Descender": "-217",
|
||||||
|
"StdHW": "44",
|
||||||
|
"StdVW": "139",
|
||||||
|
"StartCharMetrics": "317",
|
||||||
|
"C": {
|
||||||
|
"32": 250,
|
||||||
|
"160": 250,
|
||||||
|
"33": 333,
|
||||||
|
"34": 555,
|
||||||
|
"35": 500,
|
||||||
|
"36": 500,
|
||||||
|
"37": 1000,
|
||||||
|
"38": 833,
|
||||||
|
"146": 333,
|
||||||
|
"40": 333,
|
||||||
|
"41": 333,
|
||||||
|
"42": 500,
|
||||||
|
"43": 570,
|
||||||
|
"44": 250,
|
||||||
|
"45": 333,
|
||||||
|
"173": 333,
|
||||||
|
"46": 250,
|
||||||
|
"47": 278,
|
||||||
|
"48": 500,
|
||||||
|
"49": 500,
|
||||||
|
"50": 500,
|
||||||
|
"51": 500,
|
||||||
|
"52": 500,
|
||||||
|
"53": 500,
|
||||||
|
"54": 500,
|
||||||
|
"55": 500,
|
||||||
|
"56": 500,
|
||||||
|
"57": 500,
|
||||||
|
"58": 333,
|
||||||
|
"59": 333,
|
||||||
|
"60": 570,
|
||||||
|
"61": 570,
|
||||||
|
"62": 570,
|
||||||
|
"63": 500,
|
||||||
|
"64": 930,
|
||||||
|
"65": 722,
|
||||||
|
"66": 667,
|
||||||
|
"67": 722,
|
||||||
|
"68": 722,
|
||||||
|
"69": 667,
|
||||||
|
"70": 611,
|
||||||
|
"71": 778,
|
||||||
|
"72": 778,
|
||||||
|
"73": 389,
|
||||||
|
"74": 500,
|
||||||
|
"75": 778,
|
||||||
|
"76": 667,
|
||||||
|
"77": 944,
|
||||||
|
"78": 722,
|
||||||
|
"79": 778,
|
||||||
|
"80": 611,
|
||||||
|
"81": 778,
|
||||||
|
"82": 722,
|
||||||
|
"83": 556,
|
||||||
|
"84": 667,
|
||||||
|
"85": 722,
|
||||||
|
"86": 722,
|
||||||
|
"87": 1000,
|
||||||
|
"88": 722,
|
||||||
|
"89": 722,
|
||||||
|
"90": 667,
|
||||||
|
"91": 333,
|
||||||
|
"92": 278,
|
||||||
|
"93": 333,
|
||||||
|
"94": 581,
|
||||||
|
"95": 500,
|
||||||
|
"145": 333,
|
||||||
|
"97": 500,
|
||||||
|
"98": 556,
|
||||||
|
"99": 444,
|
||||||
|
"100": 556,
|
||||||
|
"101": 444,
|
||||||
|
"102": 333,
|
||||||
|
"103": 500,
|
||||||
|
"104": 556,
|
||||||
|
"105": 278,
|
||||||
|
"106": 333,
|
||||||
|
"107": 556,
|
||||||
|
"108": 278,
|
||||||
|
"109": 833,
|
||||||
|
"110": 556,
|
||||||
|
"111": 500,
|
||||||
|
"112": 556,
|
||||||
|
"113": 556,
|
||||||
|
"114": 444,
|
||||||
|
"115": 389,
|
||||||
|
"116": 333,
|
||||||
|
"117": 556,
|
||||||
|
"118": 500,
|
||||||
|
"119": 722,
|
||||||
|
"120": 500,
|
||||||
|
"121": 500,
|
||||||
|
"122": 444,
|
||||||
|
"123": 394,
|
||||||
|
"124": 220,
|
||||||
|
"125": 394,
|
||||||
|
"126": 520,
|
||||||
|
"161": 333,
|
||||||
|
"162": 500,
|
||||||
|
"163": 500,
|
||||||
|
"fraction": 167,
|
||||||
|
"165": 500,
|
||||||
|
"131": 500,
|
||||||
|
"167": 500,
|
||||||
|
"164": 500,
|
||||||
|
"39": 278,
|
||||||
|
"147": 500,
|
||||||
|
"171": 500,
|
||||||
|
"139": 333,
|
||||||
|
"155": 333,
|
||||||
|
"fi": 556,
|
||||||
|
"fl": 556,
|
||||||
|
"150": 500,
|
||||||
|
"134": 500,
|
||||||
|
"135": 500,
|
||||||
|
"183": 250,
|
||||||
|
"182": 540,
|
||||||
|
"149": 350,
|
||||||
|
"130": 333,
|
||||||
|
"132": 500,
|
||||||
|
"148": 500,
|
||||||
|
"187": 500,
|
||||||
|
"133": 1000,
|
||||||
|
"137": 1000,
|
||||||
|
"191": 500,
|
||||||
|
"96": 333,
|
||||||
|
"180": 333,
|
||||||
|
"136": 333,
|
||||||
|
"152": 333,
|
||||||
|
"175": 333,
|
||||||
|
"breve": 333,
|
||||||
|
"dotaccent": 333,
|
||||||
|
"168": 333,
|
||||||
|
"ring": 333,
|
||||||
|
"184": 333,
|
||||||
|
"hungarumlaut": 333,
|
||||||
|
"ogonek": 333,
|
||||||
|
"caron": 333,
|
||||||
|
"151": 1000,
|
||||||
|
"198": 1000,
|
||||||
|
"170": 300,
|
||||||
|
"Lslash": 667,
|
||||||
|
"216": 778,
|
||||||
|
"140": 1000,
|
||||||
|
"186": 330,
|
||||||
|
"230": 722,
|
||||||
|
"dotlessi": 278,
|
||||||
|
"lslash": 278,
|
||||||
|
"248": 500,
|
||||||
|
"156": 722,
|
||||||
|
"223": 556,
|
||||||
|
"207": 389,
|
||||||
|
"233": 444,
|
||||||
|
"abreve": 500,
|
||||||
|
"uhungarumlaut": 556,
|
||||||
|
"ecaron": 444,
|
||||||
|
"159": 722,
|
||||||
|
"247": 570,
|
||||||
|
"221": 722,
|
||||||
|
"194": 722,
|
||||||
|
"225": 500,
|
||||||
|
"219": 722,
|
||||||
|
"253": 500,
|
||||||
|
"scommaaccent": 389,
|
||||||
|
"234": 444,
|
||||||
|
"Uring": 722,
|
||||||
|
"220": 722,
|
||||||
|
"aogonek": 500,
|
||||||
|
"218": 722,
|
||||||
|
"uogonek": 556,
|
||||||
|
"203": 667,
|
||||||
|
"Dcroat": 722,
|
||||||
|
"commaaccent": 250,
|
||||||
|
"169": 747,
|
||||||
|
"Emacron": 667,
|
||||||
|
"ccaron": 444,
|
||||||
|
"229": 500,
|
||||||
|
"Ncommaaccent": 722,
|
||||||
|
"lacute": 278,
|
||||||
|
"224": 500,
|
||||||
|
"Tcommaaccent": 667,
|
||||||
|
"Cacute": 722,
|
||||||
|
"227": 500,
|
||||||
|
"Edotaccent": 667,
|
||||||
|
"154": 389,
|
||||||
|
"scedilla": 389,
|
||||||
|
"237": 278,
|
||||||
|
"lozenge": 494,
|
||||||
|
"Rcaron": 722,
|
||||||
|
"Gcommaaccent": 778,
|
||||||
|
"251": 556,
|
||||||
|
"226": 500,
|
||||||
|
"Amacron": 722,
|
||||||
|
"rcaron": 444,
|
||||||
|
"231": 444,
|
||||||
|
"Zdotaccent": 667,
|
||||||
|
"222": 611,
|
||||||
|
"Omacron": 778,
|
||||||
|
"Racute": 722,
|
||||||
|
"Sacute": 556,
|
||||||
|
"dcaron": 672,
|
||||||
|
"Umacron": 722,
|
||||||
|
"uring": 556,
|
||||||
|
"179": 300,
|
||||||
|
"210": 778,
|
||||||
|
"192": 722,
|
||||||
|
"Abreve": 722,
|
||||||
|
"215": 570,
|
||||||
|
"250": 556,
|
||||||
|
"Tcaron": 667,
|
||||||
|
"partialdiff": 494,
|
||||||
|
"255": 500,
|
||||||
|
"Nacute": 722,
|
||||||
|
"238": 278,
|
||||||
|
"202": 667,
|
||||||
|
"228": 500,
|
||||||
|
"235": 444,
|
||||||
|
"cacute": 444,
|
||||||
|
"nacute": 556,
|
||||||
|
"umacron": 556,
|
||||||
|
"Ncaron": 722,
|
||||||
|
"205": 389,
|
||||||
|
"177": 570,
|
||||||
|
"166": 220,
|
||||||
|
"174": 747,
|
||||||
|
"Gbreve": 778,
|
||||||
|
"Idotaccent": 389,
|
||||||
|
"summation": 600,
|
||||||
|
"200": 667,
|
||||||
|
"racute": 444,
|
||||||
|
"omacron": 500,
|
||||||
|
"Zacute": 667,
|
||||||
|
"142": 667,
|
||||||
|
"greaterequal": 549,
|
||||||
|
"208": 722,
|
||||||
|
"199": 722,
|
||||||
|
"lcommaaccent": 278,
|
||||||
|
"tcaron": 416,
|
||||||
|
"eogonek": 444,
|
||||||
|
"Uogonek": 722,
|
||||||
|
"193": 722,
|
||||||
|
"196": 722,
|
||||||
|
"232": 444,
|
||||||
|
"zacute": 444,
|
||||||
|
"iogonek": 278,
|
||||||
|
"211": 778,
|
||||||
|
"243": 500,
|
||||||
|
"amacron": 500,
|
||||||
|
"sacute": 389,
|
||||||
|
"239": 278,
|
||||||
|
"212": 778,
|
||||||
|
"217": 722,
|
||||||
|
"Delta": 612,
|
||||||
|
"254": 556,
|
||||||
|
"178": 300,
|
||||||
|
"214": 778,
|
||||||
|
"181": 556,
|
||||||
|
"236": 278,
|
||||||
|
"ohungarumlaut": 500,
|
||||||
|
"Eogonek": 667,
|
||||||
|
"dcroat": 556,
|
||||||
|
"190": 750,
|
||||||
|
"Scedilla": 556,
|
||||||
|
"lcaron": 394,
|
||||||
|
"Kcommaaccent": 778,
|
||||||
|
"Lacute": 667,
|
||||||
|
"153": 1000,
|
||||||
|
"edotaccent": 444,
|
||||||
|
"204": 389,
|
||||||
|
"Imacron": 389,
|
||||||
|
"Lcaron": 667,
|
||||||
|
"189": 750,
|
||||||
|
"lessequal": 549,
|
||||||
|
"244": 500,
|
||||||
|
"241": 556,
|
||||||
|
"Uhungarumlaut": 722,
|
||||||
|
"201": 667,
|
||||||
|
"emacron": 444,
|
||||||
|
"gbreve": 500,
|
||||||
|
"188": 750,
|
||||||
|
"138": 556,
|
||||||
|
"Scommaaccent": 556,
|
||||||
|
"Ohungarumlaut": 778,
|
||||||
|
"176": 400,
|
||||||
|
"242": 500,
|
||||||
|
"Ccaron": 722,
|
||||||
|
"249": 556,
|
||||||
|
"radical": 549,
|
||||||
|
"Dcaron": 722,
|
||||||
|
"rcommaaccent": 444,
|
||||||
|
"209": 722,
|
||||||
|
"245": 500,
|
||||||
|
"Rcommaaccent": 722,
|
||||||
|
"Lcommaaccent": 667,
|
||||||
|
"195": 722,
|
||||||
|
"Aogonek": 722,
|
||||||
|
"197": 722,
|
||||||
|
"213": 778,
|
||||||
|
"zdotaccent": 444,
|
||||||
|
"Ecaron": 667,
|
||||||
|
"Iogonek": 389,
|
||||||
|
"kcommaaccent": 556,
|
||||||
|
"minus": 570,
|
||||||
|
"206": 389,
|
||||||
|
"ncaron": 556,
|
||||||
|
"tcommaaccent": 333,
|
||||||
|
"172": 570,
|
||||||
|
"246": 500,
|
||||||
|
"252": 556,
|
||||||
|
"notequal": 549,
|
||||||
|
"gcommaaccent": 500,
|
||||||
|
"240": 500,
|
||||||
|
"158": 444,
|
||||||
|
"ncommaaccent": 556,
|
||||||
|
"185": 300,
|
||||||
|
"imacron": 278,
|
||||||
|
"128": 500
|
||||||
|
},
|
||||||
|
"CIDtoGID_Compressed": true,
|
||||||
|
"CIDtoGID": "eJwDAAAAAAE=",
|
||||||
|
"_version_": 6
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user