package nccloud.impl.fbm.gather.excel;

import java.util.Collection;
import java.util.HashMap;

import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.sec.esapi.NCESAPI;
import nc.itf.bd.bankdoc.IBankdocQueryService;
import nc.itf.bd.pub.IBDMetaDataIDConst;
import nc.md.persist.framework.IMDPersistenceQueryService;
import nc.pubitf.bd.accessor.GeneralAccessorFactory;
import nc.pubitf.bd.accessor.IGeneralAccessor;
import nc.vo.bd.accessor.IBDData;
import nc.vo.bd.accessor.bankaccsub.BankaccSubAccessorFactory;
import nc.vo.bd.accessor.bankaccsub.BankaccSubGeneralAccessor;
import nc.vo.bd.bankaccount.BankAccbasVO;
import nc.vo.bd.bankdoc.BankdocVO;
import nc.vo.bd.cust.CustSupplierVersionVO;
import nc.vo.fbm.pub.action.ActionVO;
import nc.vo.fbm.pub.constant.ActionConstant;
import nc.vo.fbm.pub.constant.RegisterStatusConstant;
import nc.vo.fbm.pub.util.FbmCommonTools;
import nc.vo.fbm.pub.util.FbmPublicUtil;
import nc.vo.fbm.register.AggRegisterVO;
import nc.vo.fbm.register.RegisterVO;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDateTime;
import nc.vo.pub.lang.UFDouble;
import nc.vo.tmpub.util.StringUtil;
import nc.vo.tmpub.util.TMCustSupUtil;
import nc.vo.tmpub.validator.ExcelImportUtil;
import nc.vo.trade.pub.HYBillVO;
import nc.vo.uap.pf.PFBatchExceptionInfo;
import nc.vo.uap.pf.PfProcessBatchRetObject;
import nccloud.bs.excel.IXChangeContext;
import nccloud.bs.excel.plugin.AbstractImportProceeWithContext;
import nccloud.itf.fbm.gather.GatherConstant;
import nccloud.pubitf.riart.pflow.CloudPFlowContext;
import nccloud.pubitf.riart.pflow.ICloudScriptPFlowService;

/**
 * 收票登记 导入
 * 
 * @author zhangjp6 2019年5月21日
 *
 */
public class GatherExcelImport4NCCImpl extends AbstractImportProceeWithContext {

	@Override
	protected void processBillWithContext(Object vo, IXChangeContext changcontext) throws BusinessException {
		CircularlyAccessibleValueObject regvo = ((HYBillVO) vo).getParentVO();
		AggRegisterVO aggvo = new AggRegisterVO();
		aggvo.setParentVO(regvo);
		// 保存前处理
		check(aggvo);
		// 执行保存逻辑
		Object[] results = doSave(aggvo);
		for (Object obj : results) {
			if (obj instanceof PfProcessBatchRetObject) {
				PfProcessBatchRetObject batchObj = (PfProcessBatchRetObject) obj;
				PFBatchExceptionInfo exceptionInfo = batchObj.getExceptionInfo();
				throw new BusinessException(exceptionInfo.getErrorMessage());
			}
		}

	}
	
	/**
	 * 调用动作脚本 执行保存
	 *
	 * @param aggVO
	 * @return
	 * @throws BusinessException
	 */
	private Object[] doSave(AggRegisterVO aggVO) throws BusinessException {

		doBeforeSave(aggVO);

		CloudPFlowContext context = new CloudPFlowContext();
		context.setActionName(ActionConstant.SAVEBASE);
		context.setBillType(GatherConstant.BILL_TYPE);
		context.setBillVos(new AggRegisterVO[] { aggVO });
		Object[] objects = NCLocator.getInstance().lookup(ICloudScriptPFlowService.class).exeScriptPFlow(context);

		return objects;
	}

	/**
	 * 保存前事件
	 *
	 * @param aggvo
	 * @throws BusinessException
	 */
	private void doBeforeSave(AggRegisterVO aggvo) throws BusinessException {

		RegisterVO pvo = aggvo.getparentVO();
		UFDateTime businessTime = new UFDateTime(InvocationInfoProxy.getInstance().getBizDateTime());
		// 集团
		pvo.setPk_group(InvocationInfoProxy.getInstance().getGroupId());
		// 制单人
		pvo.setBillmaker(InvocationInfoProxy.getInstance().getUserId());
		// 创建日期
		pvo.setCreationtime(businessTime);
		// 制单日期
		pvo.setDoperatedate(new UFDate(InvocationInfoProxy.getInstance().getBizDateTime()));
		// 创建时间
		pvo.setCreationtime(businessTime);
		// 创建人
		pvo.setCreator(InvocationInfoProxy.getInstance().getUserId());
		// 单据类型
		pvo.setPk_billtypecode(GatherConstant.BILL_TYPE);
		// 来源类型= 收票录入
		pvo.setGathertype("input");
		// 期初
		UFBoolean initflag = pvo.getInitflag();
		if (StringUtil.isNull(initflag)) {
			pvo.setInitflag(UFBoolean.FALSE);
		}
		// 已收付票标识
		pvo.setSfflag(UFBoolean.FALSE);
		// 票据状态 = 在收票
		pvo.setRegisterstatus(RegisterStatusConstant.ON_GATHER);
		// 单据状态 = 自由
		pvo.setVbillstatus(-1);
		// NCC-172798 默认赋值为N，否则会为null
		pvo.setRelatedrecbill(UFBoolean.FALSE);
		// 废票字段设置默认值N，否则导入的数据页签查询会有问题
		UFBoolean disableflag = pvo.getDisableflag();
		if (disableflag != null && disableflag.booleanValue()) {
			// 说明前台传的废票字段有值，是废票
		} else {
			pvo.setDisableflag(UFBoolean.FALSE);
		}
		pvo.setBookflag(UFBoolean.FALSE);
		pvo.setPlanflag(UFBoolean.FALSE);
		String pk_org = pvo.getPk_org();
		
		//电票签约账户不是空，设置签约账号开户行和银行类别
		if(StringUtil.isNotNull(pvo.getReceiveaccount())) {
			BankAccbasVO accbasVO = getBankAccbasVOByReceiveaccount(pvo);
			if(accbasVO.getEnablestate() != 2) {
				throw new BusinessException(pvo.getFbmbillno() + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
				.getStrByID("3618ncc_0", "03618ncc-0078")/* @res ":电票签约账号未启用！" */);
			}
			//zhangxinah 去掉银行账户是否电票签约账户的校验
//			if (accbasVO.getIsenableelecbill() == null || !accbasVO.getIsenableelecbill().booleanValue()) {
//				throw new BusinessException(pvo.getFbmbillno() + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
//				.getStrByID("3618ncc_0", "03618ncc-0079")/* @res ":电票签约账号电票不可用！" */);
//			}
			BankdocVO bankdoc = getBanktypeByReceiveaccount(pvo.getReceiveaccount());
			pvo.setPk_banktype(bankdoc.getPk_banktype());
			pvo.setReceiveaccountname(bankdoc.getName());
		}

		IGeneralAccessor bankdocAccessor = GeneralAccessorFactory.getAccessor(IBDMetaDataIDConst.BANKDOC);
		BankaccSubGeneralAccessor bankaccsubAccessor = (BankaccSubGeneralAccessor) new BankaccSubAccessorFactory()
				.getAccessor(IBDMetaDataIDConst.CUSTBANKACCSUB);
		IGeneralAccessor assLineNumAccessor = GeneralAccessorFactory.getAccessor(IBDMetaDataIDConst.ASSLINENUM);
		// 付票单位	vid会自动导入，需要根据vid查oid和文本赋值
		TMCustSupUtil.setCustSupPk(aggvo, RegisterVO.PAYBILLUNIT_V, RegisterVO.PAYBILLUNIT, RegisterVO.HIDEPAYBILLUNIT);
		// 出票人  根据出票人文本和收票日期赋值vid和oid
		if (StringUtil.isNotNull(pvo.getPayunit())) {
			CustSupplierVersionVO custSupVO = TMCustSupUtil.getCustSupplierVersionVOByNameAndDate(pvo.getPayunit(), pvo.getGatherdate());
			if(custSupVO!=null) {				
				pvo.setHidepayunit(custSupVO.getPk_cust_sup());
				pvo.setHidepayunit_v(custSupVO.getPk_cust_sup_v());
			}
		}
		// 收款人 根据收款人文本和收票日期赋值vid和oid
		if (StringUtil.isNotNull(pvo.getReceiveunit())) {
			CustSupplierVersionVO custSupVO = TMCustSupUtil.getCustSupplierVersionVOByNameAndDate(pvo.getReceiveunit(), pvo.getGatherdate());
			if(custSupVO!=null) {				
				pvo.setHidereceiveunit(custSupVO.getPk_cust_sup());
				pvo.setHidereceiveunit_v(custSupVO.getPk_cust_sup_v());
			}
		}
		// 收款人账户
		if (StringUtil.isNotNull(pvo.getReceivebankacc())) {
			IBDData cussup = bankaccsubAccessor.getDocByAccnum(pvo.getReceivebankacc(), pvo.getPk_curr());
			if (cussup != null) {
				pvo.setHidereceivebankacc(cussup.getPk());
			}
		}
		// 收款人银行
		if (StringUtil.isNotNull(pvo.getReceivebank())) {
			IBDData cussup = bankdocAccessor.getDocByNameWithMainLang(pk_org, pvo.getReceivebank());
			if (cussup != null) {
				pvo.setHidereceivebank(cussup.getPk());
			}
		}
		boolean busType = FbmPublicUtil.isBusType(pvo.getFbmbilltype());
		// 承兑人 1银承：银行档案； 银行参照：signagrbank；2商承：客商档案客商参照：pk_signagrbank；3文本：acceptorname
		if (busType) {
			if (StringUtil.isNotNull(pvo.getAcceptorname())) {
				CustSupplierVersionVO custSupVO = TMCustSupUtil.getCustSupplierVersionVOByNameAndDate(pvo.getAcceptorname(), pvo.getGatherdate());
				if(custSupVO!=null) {		
					pvo.setPk_signagrbank(custSupVO.getPk_cust_sup());
					pvo.setPk_signagrbank_v(custSupVO.getPk_cust_sup_v());
				}
			}
		} else {
			// 承兑人账户是否同行 银承勾选
			if (StringUtil.isNotNull(pvo.getAcceptorname())) {
				IBDData cussup = bankdocAccessor.getDocByNameWithMainLang(pk_org, pvo.getAcceptorname());
				if (cussup != null) {
					pvo.setSignagrbank(cussup.getPk());
				}
			}
		}
		// 承兑人开户行号: 手输+参照 人行联行信息 人行联行信息：acceptorbankaccount；文本：signagrbanknum
		if (StringUtil.isNotNull(pvo.getSignagrbanknum())) {
			IBDData cussup = assLineNumAccessor.getDocByCode(pk_org, pvo.getSignagrbanknum());
			if (cussup != null) {
				pvo.setAcceptorbankaccount(cussup.getPk());
			}
		}
		// 承兑人开户行名: 手输+参照 银行档案 银行档案：acceptorbank；文本：signagrbankname
		if (StringUtil.isNotNull(pvo.getSignagrbankname())) {
			IBDData cussup = bankdocAccessor.getDocByNameWithMainLang(pk_org, pvo.getSignagrbankname());
			if (cussup != null) {
				pvo.setAcceptorbank(cussup.getPk());
			}
		}
		
		//能否分包流转
		UFBoolean subcontractCirculation = pvo.getSubcontractcirculation();
		boolean ifBelongNewbillSys = FbmCommonTools.ifBelongNewBillSystem(pvo.getFbmbillno());
		if (ifBelongNewbillSys && subcontractCirculation != null && subcontractCirculation.booleanValue()) {
			pvo.setBillrange(pvo.getBillrangestart() + "-" + pvo.getBillrangeend());
		} else if(ifBelongNewbillSys){
			if(!"0".equals(pvo.getBillrangestart()) || !"0".equals(pvo.getBillrangeend())) {
				throw new BusinessException("票据[" + pvo.getFbmbillno() + "]为新一代票且不可分包流转，子票区间开始和结束应为0！");
			}
			pvo.setBillrange(String.valueOf("0"));
		} else {
			pvo.setBillrange(null);
		}
		
		// 设置票据所属系统
		pvo.setBillsystype(FbmCommonTools.getBillSysTypeByFbmBillNo(pvo.getFbmbillno()));
		
		//如果可用金额为空，则将可用金额默认设置为票据金额
		UFDouble availablemoney = pvo.getAvailablemoney();
		if(availablemoney == null) {
			pvo.setAvailablemoney(pvo.getMoney());
		}

		HashMap<String, String> voFieldsMap = new HashMap<String, String>();
		voFieldsMap.put(FbmPublicUtil.GROUP_FIELD, RegisterVO.PK_GROUP);
		voFieldsMap.put(FbmPublicUtil.ORG_FIELD, RegisterVO.PK_ORG);
		voFieldsMap.put(FbmPublicUtil.CURR_FIELD, RegisterVO.PK_CURR);
		voFieldsMap.put(FbmPublicUtil.RATE_FIELD, RegisterVO.OLCRATE);
		voFieldsMap.put(FbmPublicUtil.CUST_SUP_FIELD, RegisterVO.PAYBILLUNIT);
		voFieldsMap.put(FbmPublicUtil.DATE_FIELD, RegisterVO.GATHERDATE);
		FbmPublicUtil.setOlcRate4Import(aggvo, voFieldsMap);
		voFieldsMap.put(FbmPublicUtil.RATE_FIELD, RegisterVO.GLCRATE);
		FbmPublicUtil.setGlcRate4Import(aggvo, voFieldsMap);
		voFieldsMap.put(FbmPublicUtil.RATE_FIELD, RegisterVO.GLLCRATE);
		FbmPublicUtil.setGllcRate4Import(aggvo, voFieldsMap);
		
		// 重算
		GatherReCaculateMnyUtil.recaculate(false, new AggRegisterVO[] { aggvo });
		// 单据导入时校验汇率类型不能为期间、平均、计算汇率
		ExcelImportUtil.validateOlcratetype(pvo.getOlcratetype(),pvo.getOlcratecategory());
	}

	/**
	 * 保存前校验
	 *
	 * @param aggVO
	 * @throws BusinessException
	 */
	private void check(AggRegisterVO aggvo) throws BusinessException {
		RegisterVO registerVO = aggvo.getparentVO();
		String fbmbillno = registerVO.getFbmbillno();
		// 票据池网银校验
		UFBoolean cyberbankflag = registerVO.getCyberbankflag();// 票据池网银
		if (cyberbankflag != null && !cyberbankflag.booleanValue()) {
			String pk_bankdoc = registerVO.getPk_bankdoc();
			if (!StringUtil.isNull(pk_bankdoc)) {
				throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("3618ncc_0", "03618ncc-0042")/* @res ":未勾选票据池网银,登记银行必须为空!" */);
			}
		}

		// 收票日期和出票日期校验
		UFDate gatherdate = registerVO.getGatherdate();
		UFDate invoicedate = registerVO.getInvoicedate();
		if (gatherdate != null && invoicedate != null) {
			if (gatherdate.toStdString().compareTo(invoicedate.toStdString()) < 0) {
				throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("3618ncc_0", "03618ncc-0043")/* @res ":收票日期必须大于等于出票日期!" */);
			}
		}
		//校验金额
		UFDouble money = registerVO.getMoney();
		if(money!=null&&money.doubleValue()<0) {
			throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
			.getStrByID("3618ncc_0", "03618ncc-0080")/* @res ":票据金额必须大于零！" */);
		}
		
		// 到期日期和出票日期校验
		UFDate enddate = registerVO.getEnddate();
		if (enddate != null && invoicedate != null) {
			if (enddate.toStdString().compareTo(invoicedate.toStdString()) < 0) {
				throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("3618ncc_0", "03618ncc-0046")/* @res ":到期日期应大于出票日期！" */);
			}
		}

		// 收款和付款单位不能相同
//		String payunit = registerVO.getHidepayunit();
//		String receiveunit = registerVO.getHidereceiveunit();
//		if (!StringUtil.isNull(payunit) && !StringUtil.isNull(receiveunit)
//				&& payunit.equals(receiveunit)) {
//			throw new BusinessException(fbmbillno+nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("3618ncc_0","03618ncc-0044")/*@res ":票据基本信息的收款单位和付款单位不能相同!"*/);
//		}

		// 如果是电票的话 电票签约账号必须有值
		String fbmbilltype = registerVO.getFbmbilltype();
		String receiveaccount = registerVO.getReceiveaccount();
		// 判断是否为电票
		boolean isEbill = FbmCommonTools.isEBill(fbmbilltype);
		// 票据号码长度校验
//		FbmCommonTools.checkFbmbillnoByIsEbill(fbmbillno, isEbill);
		if (isEbill) {
			/*if (StringUtil.isNull(receiveaccount)) {
				throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("3618ncc_0", "03618ncc-0051")*//* @res ":票据类型为电票，电票签约账号不能为空!" *//*);
			}*/
		} else {
			// 非电票，网银不可勾选，如果导入的时候网银勾选了，弹出提示
			UFBoolean onlinebankflag = registerVO.getOnlinebankflag();
			if (onlinebankflag != null && onlinebankflag.booleanValue()) {
				throw new BusinessException(fbmbillno + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
						.getStrByID("3618ncc_0", "03618ncc-0072")/* @res ":非电票不允许勾选网银，请确认数据!" */);
			}
		}
		if (StringUtil.isNotNull(registerVO.getBillrangestart()) && StringUtil.isNotNull(registerVO.getBillrangeend())) {
			// 子票区间取消了长度校验，自动补齐
			registerVO.setBillrangestart(FbmCommonTools.autoFillRange(registerVO.getBillrangestart()));
			registerVO.setBillrangeend(FbmCommonTools.autoFillRange(registerVO.getBillrangeend()));
		}


		//校验子票区间信息
		FbmCommonTools.validBillRange(registerVO, isEbill);
		
		//检查票号
		FbmCommonTools.billNoValication(fbmbillno);

		// 校验是否是回头票
		checkIsReturnedBill(registerVO);
	}

	/**
	 * 
	 * 校验票据是否为回头票 场景一：对方开票，背书给企业
	 * 根据财务组织、票据号码、已收票字段在票据综合台账节点查询该组织是否已经存在相同号码且已收票为“是”的票，如果存在，则“回头票”字段自动标识为“Y”。
	 * 场景二：企业开出的票据，经过流转后又回到企业
	 * 根据财务组织、票据号码、票据状态在票据综合台账节点查询该组织是否已经存在相同号码且票据状态为“已付票”的票，如果存在，则“回头票”字段自动标识为“Y”。
	 * 
	 * @param registerVO 参数
	 * @throws BusinessException
	 *
	 */
	private void checkIsReturnedBill(RegisterVO registerVO) throws BusinessException {
		StringBuffer whereSql = new StringBuffer();
		whereSql.append(" pk_org = '").append(registerVO.getPk_org()).append("' ");
		whereSql.append(" and fbmbillno = '").append(registerVO.getFbmbillno()).append("' ");
		if(StringUtil.isNull(registerVO.getBillrangestart())) {
			whereSql.append(" and isnull(billrangestart, '0') = '0' ");
		}else {
			whereSql.append(" and billrangestart <= '").append(registerVO.getBillrangestart()).append("' ");
		}
		
		if(StringUtil.isNull(registerVO.getBillrangeend())) {
			whereSql.append(" and isnull(billrangeend, '0') = '0' ");
		}else {
			whereSql.append(" and billrangeend >= '").append(registerVO.getBillrangeend()).append("' ");
		}
		whereSql.append(" and ( endstatus = 'register' or endstatus = 'has_paybill' ) ");
		@SuppressWarnings("unchecked")
		Collection<ActionVO> actionVOs = NCLocator.getInstance().lookup(IMDPersistenceQueryService.class)
				.queryBillOfVOByCond(ActionVO.class, whereSql.toString(), false);
		boolean returnedBill = false;
		if (null != actionVOs && actionVOs.size() > 0) {
			returnedBill = true;
		}
		registerVO.setReturnedbill(UFBoolean.valueOf(returnedBill));
	}
	
	/**
	 * 根据电票签约账号查询客商银行账户信息
	 */
	private BankAccbasVO getBankAccbasVOByReceiveaccount(RegisterVO pvo) throws BusinessException {
		StringBuffer whereSql = new StringBuffer();
		whereSql.append(" pk_bankaccbas =  (select pk_bankaccbas from bd_bankaccsub where pk_bankaccsub = '");
		whereSql.append(NCESAPI.sqlEncode(pvo.getReceiveaccount()));
		whereSql.append("' ) ");
		IMDPersistenceQueryService service = NCLocator.getInstance().lookup(IMDPersistenceQueryService.class);
		@SuppressWarnings("unchecked")
		Collection<BankAccbasVO> accbasVOs = service.queryBillOfVOByCond(BankAccbasVO.class, whereSql.toString(), false);
		if (accbasVOs != null && accbasVOs.size() > 0 && accbasVOs.toArray(new BankAccbasVO[0])[0] != null) {
			return accbasVOs.toArray(new BankAccbasVO[0])[0];
		} else {
				throw new BusinessException(pvo.getFbmbillno() + nc.vo.ml.NCLangRes4VoTransl.getNCLangRes()
				.getStrByID("3618ncc_0", "03618ncc-0077")/* @res "查询电票签约账号对应账户信息异常!" */);
			
		}
	}
	
	/**
	 * 根据电票签约账号查询银行类别
	 */
	private BankdocVO getBanktypeByReceiveaccount(String receiveaccount) throws BusinessException {
		StringBuffer whereSql = new StringBuffer();
		whereSql.append(" pk_bankdoc = (select pk_bankdoc from bd_bankaccbas where pk_bankaccbas = ");
		whereSql.append("(select pk_bankaccbas from bd_bankaccsub where pk_bankaccsub = '");
		whereSql.append(NCESAPI.sqlEncode(receiveaccount));
		whereSql.append("') ) ");
		// 调银行档案接口根据收票账号(子户)查询对应的开户银行VO
		BankdocVO[] bankdocVO = NCLocator.getInstance().lookup(IBankdocQueryService.class)
				.queryBankdocVOsByCon(whereSql.toString());
		if (bankdocVO != null && bankdocVO.length != 0) {
			return bankdocVO[0];
		}
		return null;
	}

}
