From 1e28298aea8387660425d5bc70cc8b3ccd7d91d3 Mon Sep 17 00:00:00 2001 From: VE10-Sanjeev Date: Wed, 15 May 2024 13:10:17 +0000 Subject: [PATCH] FIX_Change 1 : ps --- app/Config/Routes.php | 7 + app/Controllers/Purchaseorder.php | 150 +++-- app/Controllers/User.php | 551 +++++++++--------- app/Helpers/datetime_helper.php | 22 + .../{zoho_helper.php => zohobook_helper.php} | 64 ++ app/Views/serviceporeport.php | 2 +- app/Views/supplierListing.php | 2 +- app/Views/userListing.php | 2 +- app/Views/viewfullpurchaseorder.php | 2 +- public/assets/images/spinner.gif | Bin 0 -> 17380 bytes public/uploads/spinner.gif | Bin 0 -> 17380 bytes 11 files changed, 488 insertions(+), 314 deletions(-) rename app/Helpers/{zoho_helper.php => zohobook_helper.php} (57%) create mode 100644 public/assets/images/spinner.gif create mode 100644 public/uploads/spinner.gif diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 670f66f9..53adc2dd 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -128,6 +128,8 @@ $routes->get('purchaseorder/AddComplaint','Purchaseorder::AddComplaint'); $routes->post('purchaseorder/SaveComplaint','Purchaseorder::SaveComplaint'); $routes->get('purchaseorder/Nonconfirmativelist','Purchaseorder::Nonconfirmativelist'); +//Zohobooks sync +$routes->post('user/zohobooks_api_fetch_all','User::zohobooks_api_fetch_all'); // Application Payslip Routes $routes->match(['get', 'post', 'put', 'delete'],'monthlyListings', 'Monthlypay::monthlyListing'); @@ -175,6 +177,7 @@ $routes->match(['get', 'post', 'put', 'delete'],'EmergencyPO', 'Emergencypurchas $routes->match(['get', 'post', 'put', 'delete'],'AdvanceRequest', 'Purchaseorder::advancerequest'); $routes->match(['get', 'post', 'put', 'delete'],'PORelease', 'Purchaseorder::porelease'); $routes->match(['get', 'post', 'put', 'delete'],'ViewPO', 'Purchaseorder::viewfullpurchaseorder'); + // $routes->match(['get', 'post', 'put', 'delete'],'POApproval', 'Purchaseorder::poapproval'); $routes->get('amendmentpurchaseorder','Amendmentpurchaseorder::index'); $routes->get('EditAmendPO', 'Amendmentpurchaseorder::EditAmendPurchaseOrder'); @@ -195,6 +198,7 @@ $routes->get('EditPO', 'Purchaseorder::EditPurchaseOrder'); $routes->get('purchaseorder/CreatePOPrint', 'Purchaseorder::CreatePOPrint'); $routes->post('purchaseorder/ReleasePO', 'Purchaseorder::ReleasePO'); +$routes->post('purchaseorder/EditRevenuePurchaseOrder', 'Purchaseorder/EditRevenuePurchaseOrder'); $routes->post('VerifyWithSupplierForPendingPO', 'Purchaseorder::VerifyWithSupplierForPendingPO'); @@ -310,3 +314,6 @@ $routes->get('qualityreportlist', 'Quality::reportList'); $routes->get('qualityreportlistinward', 'Quality::reportListInward'); $routes->get('shortagematerialListing', 'Rawmaterialdetails::shortagematerialListing'); +$routes->get('/pdf', 'PdfController::index'); +$routes->match(['get', 'post', 'put', 'delete'],'pdf/preview', 'PdfController::preview'); +$routes->match(['get', 'post', 'put', 'delete'],'pdf/download', 'PdfController::download'); diff --git a/app/Controllers/Purchaseorder.php b/app/Controllers/Purchaseorder.php index ab012300..19255697 100644 --- a/app/Controllers/Purchaseorder.php +++ b/app/Controllers/Purchaseorder.php @@ -1297,69 +1297,133 @@ class Purchaseorder extends BaseController // echo \Mpdf\Mpdf::VERSION; // die; - $mpdf = new Mpdf([ - 'mode' => 'utf-8', - 'format' => 'A4', // Page format: A4 with portrait orientation - // 'format' => [148, 210], // Set custom width and height in millimeters - 'default_font_size' => 6, - 'default_font' => 'sans-serif', - 'margin_left' => 10, - 'margin_right' => 10, - 'margin_top' => 10, - 'margin_bottom' => 10, - 'margin_header' => 82, - 'margin_footer' => 38, - 'orientation' => 'P', - ]); + // $mpdf = new Mpdf([ + // 'mode' => 'utf-8', + // 'format' => 'A4', // Page format: A4 with portrait orientation + // // 'format' => [148, 210], // Set custom width and height in millimeters + // 'default_font_size' => 6, + // 'default_font' => 'sans-serif', + // 'margin_left' => 10, + // 'margin_right' => 10, + // 'margin_top' => 10, + // 'margin_bottom' => 10, + // 'margin_header' => 82, + // 'margin_footer' => 38, + // 'orientation' => 'P', + // ]); - $mpdf->autoLangToFont = true; - $mpdf->autoScriptToLang = true; - // Set PDF properties - $mpdf->SetTitle('Invoice'); - $mpdf->SetAuthor($data['CompanyDetails'][0]->CompanyName); - $mpdf->SetCreator(''); + // $mpdf->autoLangToFont = true; + // $mpdf->autoScriptToLang = true; + // // Set PDF properties + // $mpdf->SetTitle('Invoice'); + // $mpdf->SetAuthor($data['CompanyDetails'][0]->CompanyName); + // $mpdf->SetCreator(''); - $htmlFooter = '
-
'; - $mpdf->setHTMLFooter($htmlFooter); + // $htmlFooter = '
+ //
'; + // $mpdf->setHTMLFooter($htmlFooter); - // Generate the PDF content (HTML) - if ($PoStatus == PO_RELEASED || $PoStatus == PO_SERVICE_COMPLETED || $PoStatus == MRIR_APPROVED || $PoStatus == MRIR_REJECTED || $PoStatus == IGR_CREATED || $PoStatus == '' || $PoStatus == SPECIAL_PO) { - $mpdf->SetWatermarkText(''); - } else { - $mpdf->SetWatermarkText('DRAFT'); - } + // // Generate the PDF content (HTML) + // if ($PoStatus == PO_RELEASED || $PoStatus == PO_SERVICE_COMPLETED || $PoStatus == MRIR_APPROVED || $PoStatus == MRIR_REJECTED || $PoStatus == IGR_CREATED || $PoStatus == '' || $PoStatus == SPECIAL_PO) { + // $mpdf->SetWatermarkText(''); + // } else { + // $mpdf->SetWatermarkText('DRAFT'); + // } - $WatermarkImage = base_url()."public/assets/images/mpdf.png"; - $mpdf->SetWatermarkImage($WatermarkImage, 8, 10); + // $WatermarkImage = base_url()."public/assets/images/mpdf.png"; + // $mpdf->SetWatermarkImage($WatermarkImage, 8, 10); - $mpdf->showWatermarkImage = true; - $mpdf->watermark_font = 'DejaVuSansCondensed'; - $mpdf->showWatermarkText = true; + // $mpdf->showWatermarkImage = true; + // $mpdf->watermark_font = 'DejaVuSansCondensed'; + // $mpdf->showWatermarkText = true; // Set auto margins - $mpdf->setAutoTopMargin = 'stretch'; - $mpdf->setAutoBottomMargin = 'stretch'; + // $mpdf->setAutoTopMargin = 'stretch'; + // $mpdf->setAutoBottomMargin = 'stretch'; // Set HTML header - $HtmlHeading = view('includes/pdfheader', $data); - $mpdf->SetHTMLHeader($HtmlHeading); + // $HtmlHeading = view('includes/pdfheader', $data); + // $mpdf->SetHTMLHeader($HtmlHeading); // Set HTML body - $html = view('capitalpopdf', $data); - $mpdf->WriteHTML($html); // Use WriteHTML() method to add body content + // $html = view('capitalpopdf', $data); + // $mpdf->WriteHTML($html); // Use WriteHTML() method to add body content // Set HTML footer - $HTMLFooter = view('includes/pdffooter', $data); - $mpdf->setFooter($HTMLFooter . "Page {PAGENO} of {nb}"); + // $HTMLFooter = view('includes/pdffooter', $data); + // $mpdf->setFooter($HTMLFooter . "Page {PAGENO} of {nb}"); // Output PDF - $mpdf->Output('CapitalPOReport' . $PONO . '.pdf', 'D'); + // $mpdf->Output('CapitalPOReport' . $PONO . '.pdf', 'D'); + // $pdf = myPdf('P'); + + // $pdf->writeHTML( "Hello World" ); + + // $pdf->Output( FCPATH . "writable/uploads/test.pdf", 'F'); + + // return redirect()->to( site_url('/') ); } + function myPdf( $orientation ) { + + $defaultFontConfig = ( new Mpdf\Config\FontVariables() )->getDefaults(); + $fontData = $defaultFontConfig[ 'fontdata' ] + [ + 'homemadeapple' => [ + 'R' => 'HomemadeApple-Regular.ttf', + ], + 'roboto' => [ + 'R' => 'Roboto-Regular.ttf', + 'I' => 'Roboto-Italic.ttf', + 'B' => 'Roboto-Bold.ttf', + 'BI' => 'Roboto-BoldItalic.ttf', + ], + 'robotocondensed' => [ + 'R' => 'RobotoCondensed-Regular.ttf', + 'I' => 'RobotoCondensed-Italic.ttf', + 'B' => 'RobotoCondensed-Bold.ttf', + 'BI' => 'RobotoCondensed-BoldItalic.ttf', + ], + ]; + $defaultConfig = ( new Mpdf\Config\ConfigVariables() )->getDefaults(); + $fontDirs = $defaultConfig[ 'fontDir' ]; + if ( $orientation == 'L' ) { + $myPdf = new \Mpdf\Mpdf( + array( + 'format' => 'A4-L', + 'margin_left' => 10, + 'margin_right' => 10, + 'margin_top' => 30, + 'margin_bottom' => 20, + 'margin_header' => 8, + 'margin_footer' => 8, + 'orientation' => 'L', + 'mode' => 's', + 'fontDir' => array_merge( $fontDirs, [ FCPATH . 'public/assets-app/fonts', ] ), + 'fontdata' => $fontData, + ) ); + } + else { + $myPdf = new \Mpdf\Mpdf( array( + 'format' => 'A4-P', + 'margin_left' => 20, + 'margin_right' => 10, + 'margin_top' => 40, + 'margin_bottom' => 20, + 'margin_header' => 8, + 'margin_footer' => 8, + 'orientation' => 'P', + 'mode' => 's', + 'fontDir' => array_merge( $fontDirs, [ FCPATH . 'public/assets-app/fonts', ] ), + 'fontdata' => $fontData, + ) ); + } + + return $myPdf; + + } diff --git a/app/Controllers/User.php b/app/Controllers/User.php index 3c513982..451f6115 100644 --- a/app/Controllers/User.php +++ b/app/Controllers/User.php @@ -10,7 +10,8 @@ use App\Models\Costcenter_model; use App\Models\Dashboard_model; use App\Models\Employeedetails_model; use App\Models\User_model; - +use App\Models\Zohobooks_api_model; +require_once 'vendor/autoload.php'; /** * Module : User @@ -1269,310 +1270,326 @@ class User extends BaseController } } - - // start zoho API function zohobooks_api_fetch_all() { + + helper('zohobook'); + $Zohobook_model = model('Zohobook_api_model'); + + try { + + $from = $this->request->getPost('from'); + $to = $this->request->getPost('to'); - if (isset($_POST['sync'])) { - $con = new mysqli($this->db->hostname, $this->db->username, $this->db->password, $this->db->database); - - $ch = curl_init(); - - $organization_id = '776847408'; - $client_id = '1000.0WMDLCXAZV5DR60IKE9P49YTYGVL6C'; - $refresh_token = '1000.0fcf314cc7b7b598df6e519461bbe9b8.f77688a2254137532ae33ad5e152a064'; - $client_secret = '99da3a05cfa13cf91eb6476a3c44cfa3e21b6106a8'; - $redirect_uri = 'https://resicoindustries.com/RIA'; - - $date_today = get_current_date(); - // $date_yesterday = format_date($date_today, 1); - //$date_today = '2022-08-23'; - $date_yesterday = format_date($date_today, 7); - // echo $date_yesterday;die(); - - - $url_org = "https://books.zoho.com/api/v3/invoices?"; - - $fields = array( - - "usestate" => "true", - "organization_id" => "776847408", - "date_start" => $date_yesterday, - "date_end" => $date_today - - ); - - $data_all = http_build_query($fields); - - $accesstoken = '1000.095b66fc95fc81874c1cfc7d15b0904e.10bc9956d9b9ec14cce1350ee0cf8254'; - - //code => 57 -->expired - //code => 0 -->not expired - $headers = array( - 'Authorization:Zoho-oauthtoken ' . $accesstoken, - 'Content-Type:application/json' - ); - - $data_access = $url_org . $data_all; - - curl_setopt($ch, CURLOPT_URL, $data_access); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $body = '{}'; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - - $res = json_decode($result); - - - - if ($res->code == "57") { - - //echo 'new token';//die(); - $url_getauthtoken = 'https://accounts.zoho.com/oauth/v2/token?refresh_token=' . $refresh_token . '&client_id=' . $client_id . '&client_secret=' . $client_secret . '&redirect_uri=' . $redirect_uri . '&grant_type=refresh_token'; - curl_setopt($ch, CURLOPT_URL, $url_getauthtoken); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $body = '{}'; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $res_token = curl_exec($ch); - - $ress = json_decode($res_token); - - $newaccesstoken = $ress->access_token; - - - $headers_new = array( - 'Authorization:Zoho-oauthtoken ' . $newaccesstoken, - 'Content-Type:application/json' - ); - - - - curl_setopt($ch, CURLOPT_URL, $url_org . $data_access); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_new); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $body = '{}'; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - - $res = json_decode($result, true); + if (isset($from) && isset($to) && $from !== null && $to !== null) { + $date_today = $to; + $date_yesterday = $from; + } else { + $date_today = get_current_date(); // refer datetime helper + $date_yesterday = get_date_days_ago($date_today,'Y-m-d','-3 day'); // refer datetime helper + } + + $chk_acc_token_val = $Zohobook_model->get_data('zohobook_accesstoken', 'id', 1); + + $newDate = add_one_hour_date($chk_acc_token_val[0]['created_at']); // refer datetime helper + $token = 0; + + if ($newDate > get_current_date('Y-m-d H:i:s')) { + $token = $chk_acc_token_val[0]['token']; + $tokendata['token'] = $token; + } else { + $token = generateNewToken(); + $tokendata['token'] = $token; + $Zohobook_model->customUpdate($tokendata, 1, 'zohobook_accesstoken'); + } + + $result = getheringInvoiceDetails($date_today, $date_yesterday, $token);//refer zohobook helper + + $headers_new = $result['headers_new']; + $res = json_decode($result['data'], true); + if(isset($res['invoices']) && !empty($res['invoices'])){ $inv_array = $res['invoices']; - + // echo json_encode($inv_array);die; + }else{ + $inv_array = array(); + log_message('ERROR', $res['message']); + echo "An Error Occur ==> " .$res['message']." \n
"; + throw new \Exception($res['message']); + } + + + if(!empty($inv_array)){ foreach ($inv_array as $inv) { - $invoice_id = $inv['invoice_id']; - - + + //filter only einvoice status pushed invoices only + //&& isset($inv['einvoice_details']) && isset($inv['einvoice_details']['status']) && ($inv['einvoice_details']['status'] == 'pushed') if ($invoice_id !== "") { - - $url2 = 'https://books.zoho.com/api/v3/invoices/' . $invoice_id . '?organization_id=' . $organization_id; - - curl_setopt($ch, CURLOPT_URL, $url2); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers_new); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $body2 = '{}'; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body2); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result2 = curl_exec($ch); - + // $organization_id = '655654572'; + $organization_id = '776847408'; + $result2 = getheringInvoiceSubDetails($invoice_id, $organization_id, $headers_new);// refer Zohobook helper $resall = json_decode($result2, true); $res2[] = $resall['invoice']; } } - + $insert_count = 0; $update_count = 0; + // echo json_encode($res2);die(); foreach ($res2 as $rs) { - - $gst_no = $rs['gst_no']; - $sku = $rs['line_items'][0]['sku']; $invoice_number = $rs['invoice_number']; $invoice_date = $rs['date']; + $status = $rs['status']; $due_date = $rs['due_date']; - $item_price = $rs['line_items'][0]['rate']; - $item_order = $rs['line_items'][0]['item_order']; - $item_product_unit = $rs['line_items'][0]['unit']; - $item_name = $rs['line_items'][0]['name']; - $item_description = $rs['line_items'][0]['description']; - $item_quantity = $rs['line_items'][0]['quantity']; - // $batch_no = $rs['custom_fields'][5]['value']; - $batch_no = ""; $invoice_time = $rs['created_time']; $time_array = explode("T", $invoice_time); $time_array = explode("+", $time_array[1]); $invoice_time = $time_array[0]; - $status = $rs['status']; - - //$vehicle_number = $rs['custom_field_hash']['cf_vehicle_number']; - //$transport_mode =$rs['custom_field_hash']['cf_transport_mode']; - //$purchase_order_date = $rs['custom_field_hash']['cf_purchase_order_date']; - $driver = $rs['custom_field_hash']['cf_driver']; - $place_of_supply = $rs['custom_field_hash']['cf_place_of_supply']; - - - $cgst = $rs['taxes'][0]['tax_name']; - $sgst = $rs['taxes'][1]['tax_name']; - $cgst = $cgst[4]; - $sgst = $sgst[4]; - $cgst = $cgst . '.000'; - $getcgsttax = "SELECT * FROM ip_tax_rates WHERE tax_rate_percent='$cgst'"; - $res_cgsttax = $con->query($getcgsttax); - $rw_cgsttax = $res_cgsttax->fetch_assoc(); - $cgsttaxid = $rw_cgsttax['tax_rate_id']; - - $sgst = $sgst . '.000'; - $getsgsttax = "SELECT * FROM ip_tax_rates WHERE tax_rate_percent='$sgst'"; - $res_sgsttax = $con->query($getsgsttax); - $rw_sgsttax = $res_sgsttax->fetch_assoc(); - $sgsttaxid = $rw_sgsttax['tax_rate_id']; - - - - $item_subtotal = $rs['line_items'][0]['item_total']; - $item_tax_total = $rs['tax_total']; - $item_total = $rs['total']; - $item_sgst_amt = $rs['taxes'][1]['tax_amount']; - $item_cgst_amt = $rs['taxes'][0]['tax_amount']; - - $item_discount = 0.00; - $item_igst_amt = 0.00; - - - if ($batch_no == "") { - - $batch_no = ""; - } - - $gst_sql = "SELECT * FROM ip_clients WHERE client_tax_code='$gst_no'"; - $res_gst = $con->query($gst_sql); - // $r_gst[] = $res_gst->fetch_assoc()['client_id']; - $client_id = $res_gst->fetch_assoc()['client_id']; - - - $sku_sql = "SELECT * FROM ip_products WHERE sku='$sku'"; - $res_sku = $con->query($sku_sql); - // $r_sku[] = $res_sku->fetch_assoc()['product_id']; - $product_id = $res_sku->fetch_assoc()['product_id']; - - $sql_invoice_chk = "SELECT * FROM ip_invoices WHERE invoice_number='$invoice_number' AND invoice_date_created='$invoice_date'"; - $res_invoice = $con->query($sql_invoice_chk); - - - - if ($res_invoice->num_rows <= 0) { - - + $sql_invoice_chk = $Zohobook_model->ip_invoices($invoice_number, $invoice_date); + if ($sql_invoice_chk <= 0) { + $gst_sql = $Zohobook_model->ip_clients($gst_no); + if ($gst_sql) { + $client_id = $gst_sql[0]['client_id']; + log_message('error', 'Data fetch success DB : ip_clients , client_id : ' . $client_id); + } else { + log_message('error', 'No data => Data fetch failed DB : ip_clients ' . $gst_no); + $gst_no_data['client_tax_code'] = $gst_no; + $gst_sql = $Zohobook_model->customInsert($gst_no_data, 'ip_clients'); + $client_id = $gst_sql[0]['tax_rate_id']; + log_message('error', 'New Data Created : DB : ip_clients , client_id : ' . $client_id); + } $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < 16; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } - - - $url_key = $randomString; - - $sql_invoice_insert = "INSERT INTO ip_invoices(user_id,client_id,invoice_group_id,invoice_status_id,invoice_date_created,invoice_time_created,invoice_date_due,invoice_number,invoice_url_key,receivedstatus,crediT_Status)VALUES(1,'$client_id',6,2,'$invoice_date','$invoice_time','$due_date','$invoice_number','$url_key','ST066',0)"; - $result_invoice_insert = $con->query($sql_invoice_insert); - - $invoice_insert_id = $con->insert_id; - - $sql_invoiceitem_insert = "INSERT INTO ip_invoice_items(invoice_id,item_product_id,item_date_added,item_name,item_description,item_quantity,item_price,item_order,item_product_unit,Sgst_item_tax_rate_id,Cgst_item_tax_rate_id) - VALUES('$invoice_insert_id','$product_id','$invoice_date','$item_name','$item_description','$item_quantity','$item_price','$item_order','$item_product_unit','$sgsttaxid','$cgsttaxid')"; - $result_invoiceitem_insert = $con->query($sql_invoiceitem_insert); - - $item_insert_id = $con->insert_id; - - - //tax amount -- ip_invoice_item_amounts - table - - - $sql_tax_amount_insert = "INSERT INTO ip_invoice_item_amounts(item_id,item_subtotal,item_tax_total,item_total,item_sgst_amt,item_cgst_amt,item_discount,item_igst_amt)VALUES('$item_insert_id','$item_subtotal','$item_tax_total','$item_total','$item_sgst_amt','$item_cgst_amt','$item_discount','$item_igst_amt')"; - $result_tax_amount_insert = $con->query($sql_tax_amount_insert); - - - - - - - //custom fields insert - $sql_invoice_custom_insert = "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',62,'$batch_no')"; - $result_invoice_custom_insert = $con->query($sql_invoice_custom_insert); - - // $custom_vehicle = "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',8,'$vehicle_number')"; - // $res_vehicle = $con->query($custom_vehicle); - - // $custom_transport_mode = "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',7,'$transport_mode')"; - // $res_transport_mode= $con->query($custom_transport_mode); - - // $custom_purchase_order_date= "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',15,'$purchase_order_date')"; - // $res_purchase_order_date = $con->query($custom_purchase_order_date); - - $custom_driver = "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',58,'$driver')"; - $res_driver = $con->query($custom_driver); - - $custom_place = "INSERT INTO ip_invoice_custom(invoice_id,invoice_custom_fieldid,invoice_custom_fieldvalue)VALUES('$invoice_insert_id',10,'$place_of_supply')"; - $res_place = $con->query($custom_place); - $insert_count = $insert_count + 1; - echo "success"; + $ip_invoices['user_id'] = 1; + $ip_invoices['client_id'] = $client_id; + $ip_invoices['invoice_group_id'] = 6; + $ip_invoices['invoice_status_id'] = ($status == 'draft' ? 1 : (($status == 'sent' || $status == 'overdue') ? 2 : 5)); + $ip_invoices['invoice_date_created'] = $invoice_date; + $ip_invoices['invoice_time_created'] = $invoice_time; + $ip_invoices['invoice_date_due'] = $due_date; + $ip_invoices['invoice_number'] = $invoice_number; + $ip_invoices['invoice_url_key'] = $url_key; + $ip_invoices['receivedstatus'] = 'ST066'; + $ip_invoices['credit_status'] = 0; + $invoice_insert_id = $Zohobook_model->customInsert($ip_invoices, 'ip_invoices'); + if ($invoice_insert_id) { + log_message('error', 'Data insert success DB : ip_invoices client id :' . $client_id); + $insert_count = $insert_count + 1; + //start invoice level custom fields + //custom fields insert + $batch_no = isset($rs['custom_fields'][5]['value']) ? $rs['custom_fields'][5]['value'] : ""; + $vehicle_number = isset($rs['custom_field_hash']['cf_vehicle_number']) ? $rs['custom_field_hash']['cf_vehicle_number'] : ""; + $transport_mode = isset($rs['custom_field_hash']['cf_transport_mode']) ? $rs['custom_field_hash']['cf_transport_mode'] : ""; + $purchase_order_date = isset($rs['custom_field_hash']['cf_purchase_order_date']) ? $rs['custom_field_hash']['cf_purchase_order_date'] : ""; + $driver = isset($rs['custom_field_hash']['cf_driver'])?$rs['custom_field_hash']['cf_driver']:""; + $place_of_supply = isset($rs['custom_field_hash']['cf_place_of_supply'])?$rs['custom_field_hash']['cf_place_of_supply']:""; + // batch_no + if($batch_no){ + $ip_invoice_custom_b['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_b['invoice_custom_fieldid'] = 62; + $ip_invoice_custom_b['invoice_custom_fieldvalue'] = $batch_no; + $result_invoice_custom_insert = $Zohobook_model->customInsert($ip_invoice_custom_b, 'ip_invoice_custom'); + if ($result_invoice_custom_insert) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + // vehicle_number + if($vehicle_number){ + $ip_invoice_custom_v['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_v['invoice_custom_fieldid'] = 8; + $ip_invoice_custom_v['invoice_custom_fieldvalue'] = $vehicle_number; + $res_vehicle = $Zohobook_model->customInsert($ip_invoice_custom_v, 'ip_invoice_custom'); + if ($res_vehicle) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + // transport_mode + if($transport_mode){ + $ip_invoice_custom_t['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_t['invoice_custom_fieldid'] = 7; + $ip_invoice_custom_t['invoice_custom_fieldvalue'] = $transport_mode; + $res_transport_mode = $Zohobook_model->customInsert($ip_invoice_custom_t, 'ip_invoice_custom'); + if ($res_transport_mode) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + // purchase_order_date + if($purchase_order_date){ + $ip_invoice_custom_p['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_p['invoice_custom_fieldid'] = 15; + $ip_invoice_custom_p['invoice_custom_fieldvalue'] = $purchase_order_date; + $res_purchase_order_date = $Zohobook_model->customInsert($ip_invoice_custom_p, 'ip_invoice_custom'); + if ($res_purchase_order_date) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + // driver + if($driver){ + $ip_invoice_custom_d['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_d['invoice_custom_fieldid'] = 58; + $ip_invoice_custom_d['invoice_custom_fieldvalue'] = $driver; + $res_driver = $Zohobook_model->customInsert($ip_invoice_custom_d, 'ip_invoice_custom'); + if ($res_driver) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + // place_of_supply + if($place_of_supply){ + $ip_invoice_custom_d['invoice_id'] = $invoice_insert_id; + $ip_invoice_custom_d['invoice_custom_fieldid'] = 10; + $ip_invoice_custom_d['invoice_custom_fieldvalue'] = $place_of_supply; + $res_place = $Zohobook_model->customInsert($ip_invoice_custom_d, 'ip_invoice_custom'); + if ($res_place) + log_message('error', 'Data insert success DB : ip_invoice_custom '); + else + log_message('error', 'Data insert failed DB : ip_invoice_custom '); + } + //end invoice level custom fields + //if line items available + if (isset($rs['line_items']) && count($rs['line_items']) > 0) { + log_message('error', 'Processing line items' . count($rs['line_items'])); + for ($i = 0; $i < count($rs['line_items']); $i++) { //start insert line items + $sku = $rs['line_items'][$i]['sku']; + $item_price = $rs['line_items'][$i]['rate']; + $item_order = $rs['line_items'][$i]['item_order']; + $item_product_unit = $rs['line_items'][$i]['unit']; + $item_name = $rs['line_items'][$i]['name']; + $item_description = $rs['line_items'][$i]['description']; + $item_quantity = $rs['line_items'][$i]['quantity']; + $cgst = $rs['line_items'][$i]['line_item_taxes'][1]['tax_name']; + $sgst = $rs['line_items'][$i]['line_item_taxes'][0]['tax_name']; + $cgst = $cgst[4]; + $sgst = $sgst[4]; + $cgst = $cgst . '.000'; + $getcgsttax = $Zohobook_model->ip_tax_rates($cgst); + if ($getcgsttax) { + $cgsttaxid = $getcgsttax[0]['tax_rate_id']; + log_message('error', 'Data fetch success DB : ip_tax_rates cgst' . $cgst); + } else { + log_message('error', 'No data => Data fetch failed DB : ip_tax_rates ' . $cgst); + $cgst_data['tax_rate_percent'] = $cgst; + $getcgsttax = $Zohobook_model->customInsert($cgst_data, 'ip_tax_rates'); + $cgsttaxid = $getcgsttax[0]['tax_rate_id']; + log_message('error', 'New Data Created : DB : ip_tax_rates , tax_rate_id : ' . $cgsttaxid); + } + $sgst = $sgst . '.000'; + $getsgsttax = $Zohobook_model->ip_tax_rates($sgst); + if ($getsgsttax) { + $sgsttaxid = $getsgsttax[0]['tax_rate_id']; + log_message('error', 'Data fetch success DB : ip_tax_rates sgst' . $sgst); + } else { + log_message('error', 'No data => Data fetch failed DB : ip_tax_rates ' . $sgst); + $sgst_data['tax_rate_percent'] = $sgst; + $getsgsttax = $Zohobook_model->customInsert($sgst_data, 'ip_tax_rates'); + $sgsttaxid = $getsgsttax[0]['tax_rate_id']; + log_message('error', 'New Data Created : DB : ip_tax_rates , tax_rate_id : ' . $sgsttaxid); + } + $item_subtotal = $rs['line_items'][$i]['item_total']; + $item_sgst_amt = $rs['line_items'][$i]['line_item_taxes'][0]['tax_amount']; + $item_cgst_amt = $rs['line_items'][$i]['line_item_taxes'][1]['tax_amount']; + $item_tax_total = ($item_sgst_amt + $item_cgst_amt); + $item_total = ($item_subtotal + $item_tax_total); + $item_discount = 0.00; + $item_igst_amt = 0.00; + // if($batch_no==""){ $batch_no = "";} + $sku_sql = $Zohobook_model->ip_products($sku); + if ($sku_sql) { + $product_id = $sku_sql[0]['product_id']; + log_message('error', 'Data fetch success DB : ip_products , product_id : ' . $product_id); + } else { + log_message('error', 'No data => Data fetch failed DB : ip_products ' . $sku); + $sku_data['product_name'] = $item_name; + $sku_data['product_description'] = $item_description; + $sku_data['sku'] = $sku; + $sku_sql = $Zohobook_model->customInsert($sku_data, 'ip_products'); + $product_id = $sku_sql[0]['sku']; + log_message('error', 'sku' . $sku); + log_message('error', 'New Data Created : DB : product_id , product_id : ' . $product_id); + } + //#1 + $ip_invoice_items['invoice_id'] = $invoice_insert_id; + $ip_invoice_items['item_product_id'] = $product_id; + $ip_invoice_items['item_date_added'] = $invoice_date; + $ip_invoice_items['item_name'] = $item_name; + $ip_invoice_items['item_description'] = $item_description; + $ip_invoice_items['item_quantity'] = $item_quantity; + $ip_invoice_items['item_price'] = $item_price; + $ip_invoice_items['item_order'] = $item_order; + $ip_invoice_items['item_product_unit'] = $item_product_unit; + $ip_invoice_items['Sgst_item_tax_rate_id'] = $sgsttaxid; + $ip_invoice_items['Cgst_item_tax_rate_id'] = $cgsttaxid; + $item_insert_id = $Zohobook_model->customInsert($ip_invoice_items, 'ip_invoice_items'); + if ($item_insert_id) + log_message('error', 'Data insert success DB : ip_invoice_items => Sgst_item_tax_rate_id :' . $sgsttaxid); + else + log_message('error', 'Data insert failed DB : ip_invoice_items => Sgst_item_tax_rate_id :' . $sgsttaxid); + //tax amount -- ip_invoice_item_amounts - table + $ip_invoice_item_amounts['item_id'] = $item_insert_id; + $ip_invoice_item_amounts['item_subtotal'] = $item_subtotal; + $ip_invoice_item_amounts['item_tax_total'] = $item_tax_total; + $ip_invoice_item_amounts['item_total'] = $item_total; + $ip_invoice_item_amounts['item_sgst_amt'] = $item_sgst_amt; + $ip_invoice_item_amounts['item_cgst_amt'] = $item_cgst_amt; + $ip_invoice_item_amounts['item_discount'] = $item_discount; + $ip_invoice_item_amounts['item_igst_amt'] = $item_igst_amt; + $result_tax_amount_insert = $Zohobook_model->customInsert($ip_invoice_item_amounts, 'ip_invoice_item_amounts'); + if ($result_tax_amount_insert) + log_message('error', 'Data insert success DB : ip_invoice_item_amounts '); + else + log_message('error', 'Data insert failed DB : ip_invoice_item_amounts '); + } //end line items insert + } else { + log_message('error', 'Line Items not found in API result'); + } + } else { + log_message('error', 'Data insert failed DB : ip_invoice_items client id :' . $client_id); + } } else // update invoice status, especially for cancelled invoices { - - if ($status == "void") { - $sql_invoice_update = "UPDATE ip_invoices SET invoice_status_id = 5 WHERE invoice_number='$invoice_number' AND invoice_date_created='$invoice_date'"; - $sql_invoice_update = $con->query($sql_invoice_update); - echo "update-" . $sql_invoice_update; + if ($status == "void" || $status == "sent" || $status == "ovedue") { + $sql_invoice_update = array(); + $sql_invoice_update['invoice_status_id'] = (($status == "sent" || $status == "ovedue") ? 2 : 5); + // echo 'script' . $invoice_number. $status; + // print_r( $sql_invoice_update); + // echo '
'; + $sql_invoice_update = $Zohobook_model->sql_invoice_update($sql_invoice_update, $invoice_number, $invoice_date, 'ip_invoices'); + if ($sql_invoice_update) { + log_message('error', 'Data update success DB : ip_invoices '); + } else { + log_message('error', 'Data update failed DB : ip_invoices '); + } $update_count = $update_count + 1; } } } - echo 'new invoice inserted count- ' . $insert_count . '/' . 'cancelled status updated count - ' . $update_count; - } else { - - $invoice_id = $res->invoices[0]->invoice_id; - - if ($invoice_id !== "") { - - $url2 = 'https://books.zoho.com/api/v3/invoices/' . $invoice_id . '?organization_id=' . $organization_id; - - curl_setopt($ch, CURLOPT_URL, $url2); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_HEADER, 0); - - $body2 = '{}'; - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body2); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result2 = curl_exec($ch); - - $res2 = json_decode($result2); - - } + echo 'new invoice inserted count- ' . $insert_count . '/' . 'status updated count - ' . $update_count; + }else{ + $err = 'invoice details not founded ( from '.$date_yesterday.' into '.$date_today.' )'; + log_message('ERROR', $err); + echo $err; + throw new \Exception($err); } - curl_close($ch); + // curl_close($ch); + // } + } catch (Exception $e) { + $data['err'] = $e->getMessage(); + $data['last_query'] = $this->db->getLastQuery(); + $Zohobook_model->customInsert($data, 'zohobook_api_err'); + log_message('ERROR', "Data insertion failed : " . $e->getMessage()); } } - // END zoho API + // END zoho API } \ No newline at end of file diff --git a/app/Helpers/datetime_helper.php b/app/Helpers/datetime_helper.php index 20350485..3f781570 100755 --- a/app/Helpers/datetime_helper.php +++ b/app/Helpers/datetime_helper.php @@ -143,6 +143,28 @@ if (!function_exists('get_shorten_financial_year')) { } } +if (!function_exists('add_one_hour_date')) { + function add_one_hour_date($dateString) { + $date = new DateTime($dateString); + $date->add(new DateInterval('PT1H')); + return $date->format('Y-m-d H:i:s'); + } +} + +if (!function_exists('get_date_days_ago')) { + function get_date_days_ago($date = null, $format = 'Y-m-d', $days = '-2 days') { + + if (is_null($date)) { + $date = new \DateTime('now'); + } else { + $date = new \DateTime($date); + } + $timestamp = $date->getTimestamp(); + $newDate = date($format, strtotime($days, $timestamp)); + + return $newDate; + } +} if (!function_exists('generate_pos_number')) { function generate_pos_number($last_pono) { diff --git a/app/Helpers/zoho_helper.php b/app/Helpers/zohobook_helper.php similarity index 57% rename from app/Helpers/zoho_helper.php rename to app/Helpers/zohobook_helper.php index bf5bd60c..e0495d85 100644 --- a/app/Helpers/zoho_helper.php +++ b/app/Helpers/zohobook_helper.php @@ -108,3 +108,67 @@ if (! function_exists('getheringInvoiceSubDetails')) { } ?> + +function generateNewToken() +{ + $ch=curl_init(); + + $organization_id = '776847408'; + $client_id = '1000.0WMDLCXAZV5DR60IKE9P49YTYGVL6C'; + $refresh_token = '1000.0fcf314cc7b7b598df6e519461bbe9b8.f77688a2254137532ae33ad5e152a064'; + $client_secret = '99da3a05cfa13cf91eb6476a3c44cfa3e21b6106a8'; + $redirect_uri = 'https://resicoindustries.com/RIA/'; + $accesstoken = '1000.095b66fc95fc81874c1cfc7d15b0904e.10bc9956d9b9ec14cce1350ee0cf8254'; + + + $url_getauthtoken = 'https://accounts.zoho.com/oauth/v2/token?refresh_token='.$refresh_token.'&client_id='.$client_id.'&client_secret='.$client_secret.'&redirect_uri='.$redirect_uri.'&grant_type=refresh_token'; + $headers=array('Authorization:Zoho-oauthtoken '.$accesstoken,'Content-Type:application/json'); + curl_setopt($ch, CURLOPT_URL, $url_getauthtoken); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_HEADER, 0); + $body = '{}'; + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); + curl_setopt($ch, CURLOPT_POSTFIELDS,$body); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $res_token=curl_exec($ch); + $ress = json_decode($res_token); + return $ress->access_token; +} + + +function getheringInvoiceDetails($date_today , $date_yesterday , $accesstoken) +{ + $ch=curl_init(); + $organization_id = '776847408'; + $url_org ="https://books.zoho.com/api/v3/invoices?"; + $fields=array("usestate" => "true","organization_id" => $organization_id,"date_start" => $date_yesterday,"date_end" => $date_today); + $data_all = http_build_query($fields); + $headers=array('Authorization:Zoho-oauthtoken '.$accesstoken,'Content-Type:application/json'); + $data_access = $url_org.$data_all; + curl_setopt($ch, CURLOPT_URL, $url_org.$data_access); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_HEADER, 0); + $body = '{}'; + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($ch, CURLOPT_POSTFIELDS,$body); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $result=curl_exec($ch); + $data['headers_new'] = $headers; + $data['data'] = curl_exec($ch); + return $data; +} + + +function getheringInvoiceSubDetails($invoice_id , $organization_id , $headers) +{ + $ch=curl_init(); + $url2 = 'https://books.zoho.com/api/v3/invoices/'.$invoice_id.'?organization_id='.$organization_id; + curl_setopt($ch, CURLOPT_URL, $url2); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_HEADER, 0); + $body2 = '{}'; + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); + curl_setopt($ch, CURLOPT_POSTFIELDS,$body2); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + return curl_exec($ch); +} diff --git a/app/Views/serviceporeport.php b/app/Views/serviceporeport.php index 413e2099..69ab6179 100644 --- a/app/Views/serviceporeport.php +++ b/app/Views/serviceporeport.php @@ -39,7 +39,7 @@ $Adv='';
- + diff --git a/app/Views/supplierListing.php b/app/Views/supplierListing.php index 1d4dc686..84c0458c 100644 --- a/app/Views/supplierListing.php +++ b/app/Views/supplierListing.php @@ -44,7 +44,7 @@
SNO# PONO#
- + diff --git a/app/Views/userListing.php b/app/Views/userListing.php index 1c9348f5..ab347e3c 100644 --- a/app/Views/userListing.php +++ b/app/Views/userListing.php @@ -42,7 +42,7 @@
Supplier ID Supplier Name
- + diff --git a/app/Views/viewfullpurchaseorder.php b/app/Views/viewfullpurchaseorder.php index e7bee22c..41827d3e 100644 --- a/app/Views/viewfullpurchaseorder.php +++ b/app/Views/viewfullpurchaseorder.php @@ -19,7 +19,7 @@
User Id User Name
- + diff --git a/public/assets/images/spinner.gif b/public/assets/images/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..06c091d7f8a426da564bb528e3c687d391ef3b80 GIT binary patch literal 17380 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 literal 0 HcmV?d00001 diff --git a/public/uploads/spinner.gif b/public/uploads/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..06c091d7f8a426da564bb528e3c687d391ef3b80 GIT binary patch literal 17380 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 literal 0 HcmV?d00001
# PONO#