<?php defined('BASEPATH') OR exit('No direct script access allowed');

require_once APPPATH . 'processors/Base_processor.php';

class ActivityTracerProcessor extends Base_processor
{
	protected $oldData = array();

	protected $newData = array();

	public function pre_save(&$data)
	{
		if (empty($data["transId"]) && !empty($data["id"]))
		{
			$data["transId"] = $data["id"];
		}

		if (empty($data["transId"]))
		{
			return NULL;
		}

		$this->oldData = $this->getTrans($data["transId"]);
	}

	public function post_save(&$data, &$result)
	{
		$ci =& get_instance();

		$this->newData = $this->getTrans($data["transId"]);

		$this->compare($data);
	}

	protected function compare($data)
	{
		if (empty($data["transId"]))
		{
			return FALSE;
		}

		require_once(APPPATH . "/processors/TransCompare.php");
		$diff = TransCompare::Compare($this->oldData, $this->newData, $data["transId"]);
		if(!empty($diff)){
			$this->updateTransLog(json_encode($diff, JSON_UNESCAPED_SLASHES), $data["transId"]);
		}
	}

	private $statusList = array(
		"B" => "Billed",
		"C" => "Confirmed",
		"D" => "Draft",
		"E" => "Expired",
		"H" => "On Hold",
		"I" => "Invoiced",
		"L" => "Delivered",
		"O" => "Overdue",
		"P" => "Paid",
		"R" => "Partial",
		"S" => "Open",
		"V" => "Rejected",
		"Z" => "Revised",
	);

	private $returnStatus = array(
		"N" => "Not Filed",
		"F" => "Filed",
	);

	private function getTransDetail($transId)
	{
		$this->db->select("t.id, t.tType, t.tNo, t.seriesNo, t.tDate as TransactionDate, t.ref as ReferenceNo, t.conName as Contact, t.conTaxNo, t.status, t.conTaxScheme, t.dueDate, t.roundAmount, t.totAmount as TotalAmount, t.categoryCode, t.categorySubCode, t.returnStatus, t.isComposition, if(t.includeTax = 1,'True','False') as isInclusiveTax, t.tdsPercentage, t.tdsAmount, t.classCode, t.recAmt as RecievedAmount, t.source, t.isLocked, t.info, t.isReverse");//t.conLocCode as LocationCode,
		$this->db->select("ifnull(pl.name,'') as PriceListName");
		$this->db->select("ifnull(c.name,'') as saleRepName");
		$this->db->select("IF(tad.conAddrId !=0, ca.location,'') AS location");
		$this->db->select("tn.notes, tn.terms");
		$this->db->select("b.bankName");
		$this->db->select("tr.relDate, tr.relNumber");
		$this->db->select("IFNULL(cb.name,'') as projectContact");
		$this->db->select("ifnull(st1.name,'') as contactSupply");
		$this->db->select("ifnull(st2.name,'') as DestionOfSupply");
		$this->db->select("IFNULL(te.shipBillNo,'') as shipBillNo, IFNULL(te.shipBillDate,'') as shipBillDate, IFNULL(te.shipPortCode,'') as shipPortCode, IFNULL(te.expCurrencyCode,'') as exportCurrencyCode, IFNULL(te.excRate,'') as exchangeRate, IFNULL(te.totForexAmt,'') as totForexAmount");
		$this->db->select("if(t.tType!='SR', ta.dueAmount, 0) AS dueAmount");
		// $this->db->select("");
		// $this->db->select("");

		$this->db->from('trans AS t');

		$this->db->join('trans_addr as tad','tad.transId = t.id AND tad.addrType IN ("A","S") AND tad.conAddrId != 0', 'left');
		$this->db->join('contacts_address as ca','t.conId = ca.conId AND ca.id = tad.conAddrId', 'left');
		$this->db->join('trans_notes as tn','tn.transId = t.id AND tn.cId = t.cId', 'left');
		$this->db->join('trans_rel as tr','tr.transId = t.id AND tr.cId = t.cId', 'left');
		$this->db->join('trans_ref as tf','tf.transId = t.id AND tf.cId = t.cId', 'left');
		$this->db->join('trans_billable as tb','tb.transId=t.id and t.cId = t.cId', 'left');
		$this->db->join('trans_export AS te', 'te.transId=t.id and te.cId = t.cId', 'left');
		$this->db->join('trans_acc as ta','ta.transId = t.id  AND ta.cId = t.cId', 'left');
		$this->db->join('states AS st1', 'st1.id = t.conStateId', 'left');
		$this->db->join('states AS st2', 'st2.id = t.dstStateId', 'left');
		$this->db->join('price_list AS pl','pl.id = t.plId and  pl.cId = t.cId', 'left');
		$this->db->join('contacts AS cb', 'cb.id = tb.prjconId', 'left');
		$this->db->join('bank as b','b.accId = tn.bankAccId', 'left');
		$this->db->join('contacts as c','c.id = t.sRepId', 'left');

		$this->db->where(array(
			"t.cId" => $this->cId,
			"t.id" => $transId
		));

		// echo $this->db->get_compiled_select();

		$result = $this->db->get()->row_array();

		return $result;
	}

	private function replaceRelativeData(&$trans)
	{
		switch($trans["tType"])
		{
			case SALINV:
			case SALRETAIL:
			case CRNOTE:
			case DBNOTE:
			case EST:
			case SALORD:
			case DELCHALLAN:
			case ADVRPT:
			case 'JOBORD':
				$trans['BuyerOrderNumber'] = $trans['relNumber'];
				$trans['BuyerOrderDate'] = $trans['relDate'];
				$trans['placeOfSupply']  = $trans['contactSupply'];
			break;
			case SALPMT:
			case PURINV:
			case EXPRETAIL:
			case PURORD:
			case PURPMT:
				$trans['SupplierInvoiceNumber'] = $trans['relNumber'];
				$trans['SupplierInvoiceDate'] = $trans['relDate'];
				$trans['sourceOfSupply']  = $trans['contactSupply'];
			break;
			case PURCRNOTE:
				$trans['SupplierCreditNoteNo'] = $trans['relNumber'];
				$trans['SupplierCreditNoteDate'] = $trans['relDate'];
				$trans['sourceOfSupply']  = $trans['contactSupply'];
			break;
			case PURDBNOTE:
				$trans['SupplierDebitNoteNo'] = $trans['relNumber'];
				$trans['SupplierDebitNoteDate'] = $trans['relDate'];
				$trans['sourceOfSupply']  = $trans['contactSupply'];
			break;
			case 'GR':
				$trans['SupplierDeliveryChalanNo'] = $trans['relNumber'];
				$trans['SupplierDeliveryChalanDate'] = $trans['relDate'];
				$trans['placeOfSupply']  = $trans['contactSupply'];
			break;
			case PUREST:
				$trans['SupplierQuotationNo'] = $trans['relNumber'];
				$trans['SupplierQuotationDate'] = $trans['relDate'];
				$trans['sourceOfSupply']  = $trans['contactSupply'];
			break;
			default:
				$trans['sourceOfSupply']  = $trans['contactSupply'];
			break;
		}

		unset($trans['relNumber']);
		unset($trans['relDate']);
		unset($trans['contactSupply']);
	}

	private function getTransItems($transId)
	{
		$this->db->select('ti.id, ti.itemName as ItemName, ti.itemDesc,ti.itemType, ti.itemHS, ti.qty, ti.freeQty, ti.unit, ti.rate, ti.mrp, ti.discPercentage, ti.discAmount, ti.taxName,ti.itc, ti.itemAttrId, ti.locId,ti.chargesAmount,ti.currencyCode, ifnull(ias.serialNo,"") as serialNo,ti.itemTotal as Amount');
		$this->db->from('trans_items as ti');
		$this->db->join('trans_serial AS ts', ' ts.tsItemId=ti.id and ts.tsType = "T"', 'left');
		$this->db->join('item_attr_serial AS ias', 'ias.id=ts.asId and ias.itemAttrId=ti.itemAttrId', 'left');

		$this->db->where(array(
			"ti.cId" => $this->cId,
			"ti.transId" => $transId
		));

		// echo $this->db->get_compiled_select();
		$transItems = $this->db->get()->result_array();

		return $transItems;

	}

	private function getAttachments($transId)
	{
		$this->db->select('fileName');
		$this->db->from('trans_attachments');
		$this->db->where(array(
			"cId" => $this->cId,
			"transId" => $transId
		));
		return $this->db->get()->result_array();
	}

	private function getCustomFields($transId=0, $tType="", $isPrint=false)
	{
		$this->db->select('cf.id AS fId, cf.fType, cf.fOptions, cf.tType, cf.isRequired, cf.isPrint, cf.isTotCol, cf.isGrid, cf.isActive, cf.classCode, cf.fCode');
		$this->db->select('if(tf.fName!="", tf.fName, cf.fName) AS fName');

		if (!empty($transId))
		{
			$this->db->select('tf.fValue');
		}
		else
		{
			$this->db->select('if(tf.fValue!="", tf.fValue, cf.fValue) AS fValue');
		}

		$this->db->from('compfields AS cf');
		$this->db->join('trans_fields AS tf', 'tf.fId=cf.Id AND tf.transId=' . $transId, 'left');
		$this->db->order_by("cf.orderId", "ASC");
		$where = array(
			'cf.cId' => $this->cId
		);

		if ($isPrint)
		{
			$where['cf.isPrint'] = 1;
		}

		$this->db->where($where);

		$this->db->where_in("cf.tType", array($tType, "ALL"));

		$this->db->group_start();
		$this->db->where('cf.isActive >', 0);
		$this->db->or_where('tf.fValue !=', '');
		$this->db->group_end();

		$this->db->order_by('cf.Id', 'ASC');

		$fields = $this->db->get()->result_array();

		return $fields;
	}

	private function transAddr($transId)
	{
		$this->db->select('name , addrType, address1, address2, city, stateName, zip, country, phone, extraCont as extraContent');
		$this->db->from('trans_addr');
		$this->db->where(array(
			"cId" => $this->cId,
			"transId" => $transId
		));
		$this->db->order_by('addrType', 'asc');

		$transAddr = $this->db->get()->result_array();

		return $transAddr;
	}

	private function get_item_attributes($transId=null, $isStock=false, $isPrint=false,$itm_attr_ids=array())
	{
		if (empty($transId) && empty($itm_attr_ids))
		{
			return false;
		}

		$this->db->select('ita.itemAttrId, ita.sku, ita.saleRate, a.attrId, a.attrGrpId, a.name AS text, ag.name, ag.grpCode, ag.fldType, ag.isPrint, ag.sortNo, ag.format');
		$this->db->where("ti.cId", $this->cId);

		$tsType = "T";
		if ($isStock == 2)
		{
			$this->db->from("bom_items as ti");
		}
		else if ($isStock)
		{
			$tsType = "S";
			$this->db->from("stock_items as ti");

			if (!empty($transId))
			{
				if (is_array($transId))
				{
					$this->db->where_in('ti.sId', $transId);
				}
				else
				{
					$this->db->where('ti.sId', $transId);
				}
			}
		}
		else
		{
			$tsType = "T";
			$this->db->from("trans_items as ti");
			if (!empty($transId))
			{
				$this->db->where('ti.transId', $transId);
			}
		}

		if ($itm_attr_ids)
		{
			$this->db->where_in('ti.itemAttrId', $itm_attr_ids);
		}

		$this->db->where('ti.itemAttrId !=', 0);

		$this->db->join("item_attr as ita", "ita.itemAttrId=ti.itemAttrId", "left");
		$this->db->join("item_attr_link as ial", "ial.itemAttrId=ti.itemAttrId", "left");
		$this->db->join("attributes as a", "a.attrId=ial.attrId", "left");
		$this->db->join("attributes_group as ag", "ag.attrGrpId=a.attrGrpId", "left");

		$this->db->group_by("a.attrId, ti.itemAttrId");
		$this->db->order_by("ag.sortNo");

		$attr_values = $this->db->get()->result_array();
		return $attr_values;
	}

	private function getTax($transId)
	{
		$this->db->select('tt.*,st.taxName');
		$this->db->from('trans_tax as tt');
		$this->db->where(array(
			"cId" => $this->cId,
			"transId" => $transId
		));
		$this->db->join("systaxtype AS st", "st.countryCode='" . get_company("countryCode") . "' AND st.taxTypeCode=tt.taxTypeCode");
		$this->db->order_by("tt.transItemID", "ASC");
		$this->db->get()->result_array();
	}

	private function getPaymentModes($transId)
	{
		$this->db->select("tp.pAccId as accId, pm.name AS Mode , a.name AS AccountName,ifnull(c.name,'') as Contact,tp.pAmount as Amount");
		$this->db->from("trans_pay AS tp");
		$this->db->join("paymentmode AS pm", "tp.pMode != 0 AND pm.id=tp.pMode", "left");
		$this->db->join("contacts AS c", "tp.pMode = 0 AND tp.pConId != 0 AND c.id=tp.pConId", "left");
		$this->db->join("account AS a", "a.id=tp.pAccId", "left");
		$this->db->where(array(
			"tp.cId" => $this->cId,
			"tp.transId" => $transId
		));
		//echo $this->db->get_compiled_select();
		$payModes = $this->db->get()->result_array();

		return $payModes;
	}

	private $tTypeName = array(
		"SE" => "Estimate",
		"SO" => "Sales Order",
		"JO" => "Job Order",
		"SI" => "Invoice",
		"SR" => "Cash Invoice",
		"SC" => "Credit Note",
		"SD" => "Debit Note",
		"SA" => "Advance Receipt",
		"SH" => "Delivery Challan",
		"SP" => "Receipt",
		"PP" => "Payment",
		"PD" => "Sup.Debit Note",
		"PO" => "Purchase Order",
		"PI" => "Purchase Bill",
		"PE" => "Expense",
		"PC" => "Sup.Credit Note",
		"GR" => "Goods Receipt",
		"JV" => "Journal",
		"JC" => "Contra",
		"AO" => "Opening balance",
		"PQ" => "Purchase Quote",
	);

	private function getPayments($transId, $tType)
	{
		

		if ($tType != SALPMT && $tType != PURPMT)
		{
			$this->db->select(' tp.allotAmt as AllottedAmount, tp.tdsAmt,t.tDate,t.tType,t.tNo, tp.writeOff,ifnull( tpx.forexAmount,"") as forexAmount,ifnull( tpx.excRate,"") as exchangeRate, ifnull(tpx.forexGL,"") as forexGL ,ifnull( tpx.forexWriteOff,"" ) as forexWriteOff');
			$this->db->from('trans_payment AS tp');
			$this->db->join('trans AS t', 't.id=tp.transId');
			$this->db->join('trans_payment_ex AS tpx', 'tpx.transId=tp.transId AND tpx.allotTransId=tp.allotTransId', 'left');
			$where = array(
				'tp.cId' => $this->cId,
				'tp.allotTransId' => $transId
			);

		}
		else
		{
			$this->db->select(' tp.allotAmt as AllottedAmount, tp.tdsAmt, tp.writeOff,t.tDate,t.tType,t.tNo,ifnull( tpx.forexAmount,"") as forexAmount,ifnull( tpx.excRate,"") as exchangeRate, ifnull(tpx.forexGL,"") as forexGL ,ifnull( tpx.forexWriteOff,"" ) as forExWriteOff,ifnull(tx.totForexAmt,0) as totalForExAmt,ifnull(tx.excRate,0) as ExportExchangeRate');
			$this->db->from('trans_payment AS tp');
			$this->db->join('trans AS t', 't.id=tp.allotTransId');
			$this->db->join('trans_payment_ex AS tpx', 'tpx.transId=tp.transId AND tpx.allotTransId=tp.allotTransId', 'left');
			$this->db->join('trans_export AS tx', 'tx.transId=tp.allotTransId','left');
			$where = array(
				'tp.cId' => $this->cId,
				'tp.transId' => $transId
			);
		}
		$this->db->where($where);

		$payment =  $this->db->get()->result_array();

		foreach($payment as $key=>$val)
		{
			if (!empty($this->tTypeName[$val['tType']]))
			{
				$payment[$key]['TransactionDesc'] =	format_date($val['tDate']) . ' ' . $this->tTypeName[$val['tType']] . ' ' . $val['tNo'];
				unset($payment[$key]['tDate']);
				unset($payment[$key]['tType']);
			}
		}

		return $payment;
	}

	private function get_journal_details( $transId)
	{
		$config = get_company('config');
		$main_branch = !empty($config['mainBranch']) ? $config['mainBranch'] : "";
		$this->db->select('ta.id,ta.accCode,ta.desc,ta.debit,ta.credit,ifnull(c.name,"") AS Contact,if(a.accCode="BL",if(c.id,c.name,"'.$main_branch.'"),a.name) as accName',false);
		$this->db->from('trans_acc AS ta');
		$this->db->join('account AS a','a.id=ta.accId');

		if (sal_mod_active(BRANCH_MOD))
		{
			$this->db->select("if(jtp.accId,jtp.accCode,ta.accCode) as accCode",false);//if(jtp.accId,jtp.accId,ta.accId) as accId
			$this->db->join('(select tp.transId,tpa.id as accId,tpa.accCode from ob_trans_pay as tp join ob_account as tpa on tpa.id=tp.pAccId where tp.transId='.$transId.') as jtp','jtp.transId=ta.transId and a.accCode="BL"','left');
		}

		$this->db->join('contacts AS c','c.id=ta.conId','left');
		$this->db->join('account_loc as al', 'al.accId=a.id','left');
		$where = array(
			'ta.transId' => $transId,
			'ta.cId' => $this->cId					
		);
		$this->db->where($where);
		$this->db->group_by('ta.id');
		$this->db->order_by('ta.debit desc, ta.id asc');
		//echo $this->db->get_compiled_select();

		$journal = $this->db->get()->result_array();

		return $journal;
	}

	private function getExpenses($transId)
	{
		$this->db->select('if(ta.desc!="",concat(ac.name,"-",ta.desc), ac.name) as id,  ac.name AS itemName , ta.desc AS itemDesc, c.name AS Contact');
		$this->db->select('"" AS itemType,ta.credit,ta.debit, if(ta.credit>0,ta.credit, ta.debit) AS TotalAmount, ac.name AS accName');
		$this->db->from('trans_acc AS ta');
		$this->db->join('account AS ac', 'ac.id=ta.accId');
		$this->db->join('contacts as c', 'c.id=ta.conId', 'left');
		$this->db->order_by("ta.id", "ASC");

		$this->db->where(array(
			//'ta.accId !='	=> $result['paymentAccId'],
			'ta.transId' => $transId,
			'ta.cId'	 => $this->cId,
			'ta.debit >' => 0
		));
		//echo $this->db->get_compiled_select();
		$expenses = $this->db->get()->result_array();
		return $expenses;
	}

	public function getTrans($transId)
	{
		$result = array();

		$result["trans"] = $this->getTransDetail($transId);

		$tType = $result['trans']['tType'];

		$this->replaceRelativeData($result['trans']);

		if (!empty($this->statusList[$result['trans']['status']]))
		{
			$result['trans']['status'] = $this->statusList[$result['trans']['status']];
		}

		if (!empty($result['trans']['returnStatus']))
		{
			if (!empty($this->returnStatus[$result['trans']['returnStatus']]))
			{
				$result['trans']['returnStatus'] = $this->returnStatus[$result['trans']['returnStatus']];
			}
		}
		else
		{
			unset($result['trans']['returnStatus']);
		}

		$result["transItems"] = $this->getTransItems($transId);

		$transItemIndex = array();
		foreach($result["transItems"] as $tkey => $tvalue) // serial No attribute assign
		{
			// $transItemIndex[$tvalue['id']] = $tvalue;
			$transItemIndex[$tvalue['id']] = array(
				'tindex' => $tkey,
				'serialNo' => $tvalue['serialNo'],
				'itemAttrId' => $tvalue['itemAttrId']
			);

			if (!empty($tvalue['serialNo']))
			{
				unset($tvalue['serialNo']);
			}

			$result['transItems'][] = $tvalue;
		}

		$result["attachments"] = $this->getAttachments($transId);

		/* Trans Fields */
		$transFields = $this->getCustomFields($transId, $tType);

	//	print_r($transFields);
		if (!empty($transFields))
		{
			foreach($transFields as $key => $value)
			{
				if (!empty($value['isGrid']) && !empty($value['fValue']))
				{
					$arrItemCustomFields = json_decode($value['fValue'], TRUE);
					if (!empty($arrItemCustomFields))
					{
						foreach($arrItemCustomFields as $ikey => $ivalue)
						{
							$result['transItems'][ $transItemIndex[$ikey]['tindex']][$value['fName']] = $ivalue ;
						}
					}
				}
				else
				{
					$result['transFields'][] =  array('fName'=>$value['fName'],'fValue'=>$value['fValue']);
				}
			}
		}

		$result['transAddr'] = $this->transAddr($transId);

		/*Attributes*/
		$itemAttr =  $this->get_item_attributes($transId);
		if(!empty($itemAttr))
		{
			foreach($itemAttr as $key=>$val)
			{
				if($val['fldType']=='E')
				{
					foreach($transItemIndex as $tkey=>$tval)
					{
						if($tval['itemAttrId'] == $val['itemAttrId'])
						{
							$result['itemAttr'][$val['itemAttrId']][$val['name']] =$tval['serialNo'];
						}
					}
				}
				else
				{
					$result['itemAttr'][$val['itemAttrId']][$val['name']] =$val['text'];
				}
			}
		}

		// $result['tax'] = $this->getTax($transId)

		$result['payModes'] = $this->getPaymentModes($transId);

		$result['payment'] = $this->getPayments($transId, $tType);

		if (!empty($tType) && ($tType =='JC'|| $tType =='JV'))
		{
			$result['journal'] = $this->get_journal_details( $transId);
		}

		if ($tType == EXPRETAIL && $result['trans']['classCode'] == 'XPNG')
		{
			$result['expenses'] = $this->getExpenses($transId);
		}

		return $result;
	}

	private function updateTransLog($data, $transId, $Action='E')
	{
		$where = array(
			'tId' => $transId,
			'cId' => $this->cId,
			'aEvent' => $Action					
		);

		$this->db->select('id');
		$this->db->from('trans_log');
		$this->db->where($where);
		$this->db->order_by('id desc');
		$this->db->limit(1);

		$resData = $this->db->get()->row_array();

		if (!$resData)
		{
			$insertData = array(
				'cId' => $this->cId,
				'aEvent' => $Action,
				'aUserName' => get_user_data("name"),
				'aUserId' => $this->cId,
				'aRelValue' => '0',
				'tId' => $transId,
				'aValue' => '',
				'updatedLog' => $data
			);

			$this->db->insert('trans_log', $insertData);
			
		}
		else
		{
			$where['id'] = $resData['id'];
			$this->db->where($where)->update('trans_log', array(
				"updatedLog" => $data
			)); 
		}

		return true;
	}
}
