jamboljack

All Proses Sync Data

Jan 10th, 2026
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 21.12 KB | None | 0 0
  1. public function syncdata()
  2.     {
  3.         try {
  4.             $invoice_ids = $this->input->post('invoice_id');
  5.            
  6.             if (empty($invoice_ids)) {
  7.                 return $this->_json_error('Tidak ada invoice yang dipilih');
  8.             }
  9.            
  10.             $invoice_ids = is_array($invoice_ids) ? $invoice_ids : explode(',', $invoice_ids);
  11.             $invoice_ids = array_filter(array_map('trim', $invoice_ids));
  12.            
  13.             // Validasi max 10
  14.             if (count($invoice_ids) > 10) {
  15.                 return $this->_json_error('Maksimal 10 invoice per sinkronisasi');
  16.             }
  17.            
  18.             $result = [
  19.                 'success_count' => 0,
  20.                 'failed_count'  => 0,
  21.                 'failed'        => []
  22.             ];
  23.            
  24.             foreach ($invoice_ids as $id) {
  25.                 $res = $this->process_invoice_simple($id);
  26.                
  27.                 if ($res['success']) {
  28.                     $result['success_count']++;
  29.                 } else {
  30.                     $result['failed_count']++;
  31.                     $result['failed'][] = [
  32.                         'invoice_id' => $id,
  33.                         'message'    => $res['message']
  34.                     ];
  35.                 }
  36.             }
  37.            
  38.             return $this->output
  39.                 ->set_content_type('application/json')
  40.                 ->set_output(json_encode($result));
  41.                
  42.         } catch (Exception $e) {
  43.             return $this->_json_error('Error: ' . $e->getMessage());
  44.         }
  45.     }
  46.    
  47.     private function extract_error_simple($response)
  48.     {
  49.         if (!empty($response['response']['error_full_messages'])) {
  50.             return is_array($response['response']['error_full_messages'])
  51.                 ? implode(' | ', $response['response']['error_full_messages'])
  52.                 : $response['response']['error_full_messages'];
  53.         }
  54.        
  55.         if (!empty($response['response']['error'])) {
  56.             return $response['response']['error'];
  57.         }
  58.        
  59.         if (!empty($response['response']['message'])) {
  60.             return $response['response']['message'];
  61.         }
  62.        
  63.         return 'Unknown error. HTTP Code: ' . ($response['http_code'] ?? 'N/A');
  64.     }
  65.  
  66.     private function _json_error($message)
  67.     {
  68.         return $this->output
  69.             ->set_content_type('application/json')
  70.             ->set_output(json_encode([
  71.                 'success' => false,
  72.                 'message' => $message
  73.             ]));
  74.     }
  75.  
  76.     private function check_customer($invoice)
  77.     {
  78.         // Jika customer sudah ada Jurnal ID, pakai yang ada
  79.         $pelanggan_jurnal_id = $invoice->pelanggan_jurnal_id;
  80.         if (!empty($pelanggan_jurnal_id)) {
  81.             // Verifikasi customer masih ada di Mekari
  82.             $verify_result = $this->verify_customer_exists($pelanggan_jurnal_id);
  83.             if ($verify_result['success']) {
  84.                 return [
  85.                     'success'               => true,
  86.                     'pelanggan_jurnal_id'   => $pelanggan_jurnal_id
  87.                 ];
  88.             }
  89.         }
  90.  
  91.         // Cek apakah customer sudah ada di Mekari berdasarkan nama
  92.         $customer_name = !empty($invoice->pelanggan_jurnal_nama) ? $invoice->pelanggan_jurnal_nama : $invoice->pelanggan_nama;
  93.         try {
  94.             // 1. SEARCH CUSTOMER BY NAME
  95.             $response = $this->mekari_jurnal->request(
  96.                 'GET',
  97.                 '/public/jurnal/api/v1/contacts',
  98.                 [ 'type' => 'customer', 'name' => trim($customer_name) ]
  99.             );
  100.            
  101.             $contacts = [];
  102.             if (isset($response['response']['contacts']) && is_array($response['response']['contacts'])) {
  103.                 $contacts = $response['response']['contacts'];
  104.             }
  105.             if (isset($response['response']['contact_list']['contact_data']) && is_array($response['response']['contact_list']['contact_data'])) {
  106.                 $contacts = $response['response']['contact_list']['contact_data'];
  107.             }
  108.  
  109.             if (!empty($contacts)) {
  110.                 $first                  = $contacts[0];
  111.                 $pelanggan_jurnal_id    = $first['id'] ?? $first['contact_id'] ?? null;
  112.                 $pelanggan_jurnal_nama  = $first['display_name'] ?? $first['name'] ?? $customer_name;
  113.  
  114.                 return ['success' => true, 'pelanggan_jurnal_id' => $pelanggan_jurnal_id];
  115.             }
  116.  
  117.             // 2. BUAT CUSTOMER BARU
  118.             $email = strtolower(trim($invoice->pelanggan_email ?? ''));
  119.             if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
  120.                 $email = '[email protected]';
  121.             }
  122.  
  123.             $payload = [
  124.                 'person' => [
  125.                     'display_name'  => $customer_name,
  126.                     'first_name'    => $customer_name,
  127.                     'is_customer'   => true,
  128.                     'people_type'   => 'customer',
  129.                     'email'         => $email,
  130.                     'phone'         => $invoice->pelanggan_telp ?? '',
  131.                     'address'       => $invoice->pelanggan_alamat ?? '',
  132.                     'notes'         => 'Created from ISKNet.id'
  133.                 ]
  134.             ];
  135.            
  136.             $create = $this->mekari_jurnal->request(
  137.                 'POST',
  138.                 '/public/jurnal/api/v1/contacts',
  139.                 $payload
  140.             );
  141.            
  142.             // Check different possible response structures
  143.             $pelanggan_jurnal_id    = null;
  144.             $pelanggan_jurnal_nama  = null;
  145.             if (isset($create['response']['person']['id'])) {
  146.                 $pelanggan_jurnal_id    = $create['response']['person']['id'];
  147.                 $pelanggan_jurnal_nama  = $create['response']['person']['display_name'] ?? $customer_name;
  148.             }
  149.             elseif (isset($create['response']['contact']['id'])) {
  150.                 $pelanggan_jurnal_id    = $create['response']['contact']['id'];
  151.                 $pelanggan_jurnal_nama  = $create['response']['contact']['display_name'] ?? $customer_name;
  152.             }
  153.             elseif (isset($create['response']['id'])) {
  154.                 $pelanggan_jurnal_id    = $create['response']['id'];
  155.                 $pelanggan_jurnal_nama  = $customer_name;
  156.             }
  157.             elseif (isset($create['response']['data']['id'])) {
  158.                 $pelanggan_jurnal_id    = $create['response']['data']['id'];
  159.                 $pelanggan_jurnal_nama  = $customer_name;
  160.             }
  161.            
  162.             if ($pelanggan_jurnal_id) {
  163.                 // Update database Pelanggan
  164.                 $this->db->where('pelanggan_id', $invoice->pelanggan_id)->update('sid_pelanggan', [
  165.                     'pelanggan_jurnal_id'       => $pelanggan_jurnal_id,
  166.                     'pelanggan_jurnal_nama'     => $pelanggan_jurnal_nama,
  167.                     'pelanggan_update'          => date('Y-m-d H:i:s'),
  168.                     'pelanggan_jurnal_response' => json_encode($create['response'])
  169.                 ]);
  170.                
  171.                 return ['success' => true, 'pelanggan_jurnal_id' => $pelanggan_jurnal_id];
  172.             } else {
  173.                 sleep(1);
  174.                 $search_again = $this->mekari_jurnal->request(
  175.                     'GET',
  176.                     '/public/jurnal/api/v1/contacts',
  177.                     [ 'type' => 'customer', 'name' => trim($customer_name) ]
  178.                 );
  179.                
  180.                 if (isset($search_again['response']['contacts'][0]['id'])) {
  181.                     $jurnal_id = $search_again['response']['contacts'][0]['id'];
  182.                     $this->db->where('pelanggan_id', $invoice->pelanggan_id)->update('sid_pelanggan', [
  183.                         'pelanggan_jurnal_id'   => $pelanggan_jurnal_id,
  184.                         'pelanggan_jurnal_nama' => $customer_name,
  185.                         'pelanggan_update'      => date('Y-m-d H:i:s'),
  186.                         'pelanggan_jurnal_response' => json_encode($search_again['response'])
  187.                     ]);
  188.  
  189.                     return ['success' => true, 'pelanggan_jurnal_id' => $pelanggan_jurnal_id];
  190.                 }
  191.                
  192.                 return [
  193.                     'success' => false,
  194.                     'message' => 'Gagal buat Customer Baru di Mekari. Response : ' . json_encode($create['response'] ?? [])
  195.                 ];
  196.             }
  197.         } catch (Exception $e) {
  198.             error_log("Customer sync exception: " . $e->getMessage());
  199.             return ['success' => false, 'message' => 'Customer sync error: ' . $e->getMessage()];
  200.         }
  201.     }
  202.  
  203.     private function verify_customer_exists($pelanggan_jurnal_id)
  204.     {
  205.         try {
  206.             $response = $this->mekari_jurnal->request(
  207.                 'GET',
  208.                 '/public/jurnal/api/v1/contacts/' . $pelanggan_jurnal_id
  209.             );
  210.  
  211.             return ['success' => ($response['http_code'] ?? 0) === 200];
  212.         } catch (Exception $e) {
  213.             return ['success' => false, 'message' => $e->getMessage()];
  214.         }
  215.     }
  216.  
  217.     private function process_invoice_simple($invoice_id)
  218.     {
  219.         try {
  220.             // 1. CEK INVOICE DI DATABASE
  221.             $invoice = $this->db->get_where('v_invoice', ['invoice_id' => $invoice_id])->row();
  222.             if (!$invoice) {
  223.                 return ['success' => false, 'message' => 'Invoice tidak ditemukan'];
  224.             }
  225.            
  226.             // Cek apakah sudah ada invoice_sales_order_id
  227.             if (!empty($invoice->invoice_sales_order_id)) {
  228.                 if (!empty($invoice->invoice_jurnal_id)) {
  229.                     return ['success' => true, 'message' => 'Invoice sudah lengkap'];
  230.                 } else {
  231.                     return $this->buat_sales_invoice($invoice, $invoice->invoice_sales_order_id);
  232.                 }
  233.             }
  234.            
  235.             // Jika sudah ada invoice_jurnal_id (SI lama), skip
  236.             if (!empty($invoice->invoice_jurnal_id)) {
  237.                 return [
  238.                     'success'   => true,
  239.                     'message'   => 'Invoice sudah sync sebelumnya',
  240.                     'skip'      => true
  241.                 ];
  242.             }
  243.            
  244.             // 2. CEK/SYNC CUSTOMER
  245.             $customer_result = $this->check_customer($invoice);
  246.             if (!$customer_result['success']) {
  247.                 return $customer_result;
  248.             }
  249.            
  250.             $customer_jurnal_id = $customer_result['pelanggan_jurnal_id'];
  251.             // 3. BUAT SALES ORDER (SO) DULU
  252.             return $this->buat_sales_order($invoice, $customer_jurnal_id);
  253.         } catch (Exception $e) {
  254.             return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
  255.         }
  256.     }
  257.  
  258.     private function buat_sales_order($invoice, $customer_jurnal_id)
  259.     {
  260.         try {
  261.             // Ambil detail invoice
  262.             $details = $this->db->order_by('invoice_detail_id', 'asc')->get_where('sid_invoice_detail', ['invoice_id' => $invoice->invoice_id])->result();
  263.             if (empty($details)) {
  264.                 return ['success' => false, 'message' => 'Detail Invoice kosong'];
  265.             }
  266.  
  267.             // Hitung total transaksi (nilai penuh)
  268.             $total_transaction  = 0;
  269.             $transactionLines   = [];
  270.             foreach ($details as $detail) {
  271.                 $product_name       = in_array($detail->invoice_detail_desc, ['Biaya Instalasi', 'Sewa Alat']) ? $detail->invoice_detail_desc : 'Tagihan Bulanan';
  272.                 $transactionLines[] = [
  273.                     'product_name'  => $product_name,
  274.                     'quantity'      => (int)($detail->invoice_detail_qty ?? 1),
  275.                     'rate'          => (int)($detail->invoice_detail_tarif ?? 0),
  276.                     'discount'      => (int)($detail->invoice_detail_disc ?? 0)
  277.                 ];
  278.             }
  279.  
  280.             // Siapkan payload untuk Sales Order (SO)
  281.             $email = strtolower(trim($invoice->pelanggan_email ?? ''));
  282.             if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
  283.                 $email = '[email protected]';
  284.             }
  285.             $payload = [
  286.                 'sales_order' => [
  287.                     'transaction_date'              => date('Y-m-d', strtotime($invoice->invoice_tanggal)),
  288.                     'due_date'                      => date('Y-m-d', strtotime($invoice->invoice_tanggal_tempo)),
  289.                     'transaction_no'                => 'SO-' . $invoice->invoice_nomor,
  290.                     'person_id'                     => $customer_jurnal_id,
  291.                     'email'                         => $email,
  292.                     'address'                       => $invoice->pelanggan_alamat ?? '',
  293.                     'term_name'                     => $invoice->jenis_bayar_nama ?? 'Custom',
  294.                     'transaction_lines_attributes'  => $transactionLines,
  295.                     'is_shipped'                    => false,
  296.                     'shipping_price'                => 0,
  297.                     'discount_unit'                 => $invoice->invoice_diskon ?? 0,
  298.                     'discount_type_name'            => 'Value',
  299.                     'source'                        => 'ISKNet.id',
  300.                     'memo'                          => 'Sales Order dari ISKNet.id (Total Tagihan: ' . number_format($invoice->invoice_total, 0, ',', '.') . ')'
  301.                 ]
  302.             ];
  303.            
  304.             // Kirim Sales Order ke Mekari
  305.             $response = $this->mekari_jurnal->request(
  306.                 'POST',
  307.                 '/public/jurnal/api/v1/sales_orders',
  308.                 $payload
  309.             );
  310.  
  311.             $httpCode = $response['http_code'] ?? 0;
  312.             if ($httpCode === 201 && isset($response['response']['sales_order']['id'])) {
  313.                 $so_jurnal_id = $response['response']['sales_order']['id'];
  314.                 $so_jurnal_no = $response['response']['sales_order']['transaction_no'];
  315.                
  316.                 // Update database dengan SO ID
  317.                 $this->db->where('invoice_id', $invoice->invoice_id)->update('sid_invoice', [
  318.                     'invoice_sales_order_id'    => $so_jurnal_id,
  319.                     'invoice_sales_order_no'    => $so_jurnal_no,
  320.                     'invoice_jurnal_response'   => json_encode($response['response']['sales_order']),
  321.                     'invoice_jurnal_sync_at'    => date('Y-m-d H:i:s'),
  322.                     'invoice_update'            => date('Y-m-d H:i:s')
  323.                 ]);
  324.                
  325.                 // Lanjutkan membuat Sales Invoice
  326.                 return $this->buat_sales_invoice($invoice, $customer_jurnal_id, $so_jurnal_id);
  327.             } else {
  328.                 $error = $this->extract_error_simple($response);
  329.                 // Update dengan status failed
  330.                 $this->db->where('invoice_id', $invoice->invoice_id)->update('sid_invoice', [
  331.                     'invoice_jurnal_status'     => 'failed',
  332.                     'invoice_jurnal_error'      => $error,
  333.                     'invoice_jurnal_response'   => json_encode($response['response'] ?? []),
  334.                     'invoice_jurnal_sync_at'    => date('Y-m-d H:i:s'),
  335.                     'invoice_update'            => date('Y-m-d H:i:s')
  336.                 ]);
  337.                
  338.                 return ['success' => false, 'message' => 'Gagal buat Sales Order : ' . $error];
  339.             }
  340.            
  341.         } catch (Exception $e) {
  342.             return ['success' => false, 'message' => 'API Error: ' . $e->getMessage()];
  343.         }
  344.     }
  345.  
  346.     private function buat_sales_invoice($invoice, $customer_jurnal_id, $so_jurnal_id = null)
  347.     {
  348.         try {
  349.             if (!$so_jurnal_id) {
  350.                 $so_jurnal_id = $invoice->invoice_sales_order_id;
  351.             }
  352.            
  353.             if (empty($so_jurnal_id)) {
  354.                 return ['success' => false, 'message' => 'Sales Order ID tidak ditemukan'];
  355.             }
  356.            
  357.             // Cek apakah sudah ada invoice_jurnal_id
  358.             if (!empty($invoice->invoice_jurnal_id)) {
  359.                 return [
  360.                     'success'   => true,
  361.                     'message'   => 'Sales Invoice Sudah Ada Sebelumnya',
  362.                     'skip'      => true
  363.                 ];
  364.             }
  365.  
  366.             // Ambil detail invoice untuk membuat SI dengan nilai yang dibayar
  367.             $details = $this->db->get_where('sid_invoice_detail', ['invoice_id' => $invoice->invoice_id])->result();
  368.             if (empty($details)) {
  369.                 return ['success' => false, 'message' => 'Detail Invoice Kosong'];
  370.             }
  371.            
  372.             $paid_amount        = (int) $invoice->invoice_dibayar ?? 0;
  373.             $transactionLines   = [];
  374.             // Untuk simplicity, kita buat satu line item dengan nilai yang dibayar
  375.             $transactionLines[] = [
  376.                 'product_name'  => 'Pembayaran Invoice',
  377.                 'quantity'      => 1,
  378.                 'rate'          => $paid_amount,
  379.                 'discount'      => 0
  380.             ];
  381.            
  382.             // Siapkan payload Sales Invoice
  383.             $email = strtolower(trim($invoice->pelanggan_email ?? ''));
  384.             if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
  385.                 $email = '[email protected]';
  386.             }
  387.             $payload = [
  388.                 'sales_invoice' => [
  389.                     'transaction_date'              => date('Y-m-d', strtotime($invoice->invoice_tanggal)),
  390.                     'due_date'                      => date('Y-m-d', strtotime($invoice->invoice_tanggal_tempo)),
  391.                     'transaction_no'                => $invoice->invoice_nomor,
  392.                     'person_id'                     => $customer_jurnal_id,
  393.                     'email'                         => $email,
  394.                     'address'                       => $invoice->pelanggan_alamat ?? '',
  395.                     'term_name'                     => $invoice->jenis_bayar_nama ?? 'Custom',
  396.                     'transaction_lines_attributes'  => $transactionLines,
  397.                     'is_shipped'                    => false,
  398.                     'shipping_price'                => 0,
  399.                     'discount_unit'                 => 0,
  400.                     'discount_type_name'            => 'value',
  401.                     'deposit_to_name'               => 'KAS KECIL KANTOR',
  402.                     'deposit'                       => $paid_amount,
  403.                     'selected_so_id'                => $so_jurnal_id,
  404.                     'source'                        => 'ISKNet.id',
  405.                     'memo'                          => 'Sales Invoice dari ISKNet.id (Pembayaran: ' . number_format($paid_amount, 0, ',', '.') . ')'
  406.                 ]
  407.             ];
  408.            
  409.             // Kirim Sales Invoice ke Mekari
  410.             $response = $this->mekari_jurnal->request(
  411.                 'POST',
  412.                 '/public/jurnal/api/v1/sales_invoices',
  413.                 $payload
  414.             );
  415.  
  416.             $httpCode = $response['http_code'] ?? 0;
  417.             if ($httpCode === 201 && isset($response['response']['sales_invoice']['id'])) {
  418.                 $si_jurnal_id = $response['response']['sales_invoice']['id'];
  419.                 $si_jurnal_no = $response['response']['sales_invoice']['transaction_no'];
  420.                
  421.                 // Update database dengan SI ID
  422.                 $this->db->where('invoice_id', $invoice->invoice_id)->update('sid_invoice', [
  423.                     'invoice_jurnal_id'         => $si_jurnal_id,
  424.                     'invoice_jurnal_no'         => $si_jurnal_no,
  425.                     'invoice_jurnal_status'     => $response['response']['sales_invoice']['status'] ?? 'paid',
  426.                     'invoice_jurnal_response'   => json_encode($response['response']['sales_invoice']),
  427.                     'invoice_jurnal_sync_at'    => date('Y-m-d H:i:s'),
  428.                     'invoice_update'            => date('Y-m-d H:i:s')
  429.                 ]);
  430.                
  431.                 return [
  432.                     'success'   => true,
  433.                     'message'   => 'Sales Order dan Sales Invoice berhasil dibuat',
  434.                     'so_jurnal_id' => $so_jurnal_id,
  435.                     'si_jurnal_id' => $si_jurnal_id
  436.                 ];
  437.             } else {
  438.                 $error = $this->extract_error_simple($response);
  439.                 // Update dengan status failed
  440.                 $this->db->where('invoice_id', $invoice->invoice_id)->update('sid_invoice', [
  441.                     'invoice_jurnal_status'     => 'failed',
  442.                     'invoice_jurnal_error'      => $error,
  443.                     'invoice_jurnal_response'   => json_encode($response['response'] ?? []),
  444.                     'invoice_jurnal_sync_at'    => date('Y-m-d H:i:s'),
  445.                     'invoice_update'            => date('Y-m-d H:i:s')
  446.                 ]);
  447.                
  448.                 return ['success' => false, 'message' => 'Gagal buat Sales Invoice: ' . $error];
  449.             }
  450.         } catch (Exception $e) {
  451.             return ['success' => false, 'message' => 'API Error: ' . $e->getMessage()];
  452.         }
  453.     }
Advertisement
Add Comment
Please, Sign In to add comment