package cn.superdesk.uniorder.pattern.state.invoice.customer.invoiceApply.makeInvoiceStatus.state.concrete;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import cn.superdesk.uniorder.common.numerical.AnStringUtils;
import cn.superdesk.uniorder.common.security.dto.LoginSysUser;
import cn.superdesk.uniorder.common.spring.SpringContextHolder;
import cn.superdesk.uniorder.dao.entity.invoice.common.InvoiceBankInfo;
import cn.superdesk.uniorder.dao.entity.invoice.customer.InvoiceApply;
import cn.superdesk.uniorder.dao.entity.sys.notify.SysNotify;
import cn.superdesk.uniorder.dto._constant.ResourceConstant;
import cn.superdesk.uniorder.dto.param.invoice.customer.InvoiceApplyCustomerQueryCriteria;
import cn.superdesk.uniorder.dto.param.organisation.SysEnterpriseExtInvoiceParam;
import cn.superdesk.uniorder.dto.param.thirdpart.szhtxx.common.singleBilling.SzhtxxInvoiceFptxxOpSingleBillingForm;
import cn.superdesk.uniorder.dto.vo.invoice.customer.ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequest;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContent;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContentFptxxVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.request.SingleBillingRequestBodyKpContentXmxxItemVo;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.dto.response.SingleBillingResponse;
import cn.superdesk.uniorder.openapicall.thirdpart.szhtxx.electronicInvoice.service.SingleBillingCallService;
import cn.superdesk.uniorder.pattern.state.invoice.customer.invoiceApply.makeInvoiceStatus.context.InvoiceApplyFieldMakeInvoiceStatusContext;
import cn.superdesk.uniorder.pattern.state.invoice.customer.invoiceApply.makeInvoiceStatus.state.InvoiceApplyFieldMakeInvoiceStatusState;
import cn.superdesk.uniorder.service.invoice.common.InvoiceBankInfoService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerExportExcelService;
import cn.superdesk.uniorder.service.invoice.customer.InvoiceApplyCustomerService;
import cn.superdesk.uniorder.service.invoice.customer.state.InvoiceApplyCustomerFieldMakeInvoiceStatusService;
import cn.superdesk.uniorder.service.invoice.customer.impl.InvoiceApplyCustomerExportExcelFocusScoreDimCreditStruct;
import cn.superdesk.uniorder.service.invoice.supplier.InvoiceApplySupplierXGoodsService;
import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 简易状态机 星型结构
 * @Author: linjinyu
 * @CreateDate: 9/23/20 2:00 PM
 * @UpdateUser: linjinyu
 * @UpdateDate: 9/23/20 2:00 PM
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@ToString
@AllArgsConstructor
public class InvoiceApplyFieldMakeInvoiceStatusConcreteState_0_待开票 implements InvoiceApplyFieldMakeInvoiceStatusState {


	/****************************************** service start ******************************************/

	private InvoiceApplyCustomerService                       invoiceApplyCustomerService;
	private InvoiceApplyCustomerFieldMakeInvoiceStatusService invoiceApplyFieldInvoiceProgressingStatusService;

	private InvoiceApplySupplierXGoodsService invoiceApplySupplierXGoodsService;


	private InvoiceApplyCustomerExportExcelService invoiceApplyCustomerExportExcelService;

	private InvoiceBankInfoService invoiceBankInfoService;

	private SingleBillingCallService singleBillingCallService;

	private ResourceConstant resourceConstant;

	/****************************************** context start ******************************************/

	private InvoiceApplyFieldMakeInvoiceStatusContext context;

	public InvoiceApplyFieldMakeInvoiceStatusConcreteState_0_待开票(InvoiceApplyFieldMakeInvoiceStatusContext context) {

		this.context = context;

		this.invoiceApplyCustomerService = (InvoiceApplyCustomerService) SpringContextHolder.getBean(InvoiceApplyCustomerService.class);
		this.invoiceApplyFieldInvoiceProgressingStatusService = (InvoiceApplyCustomerFieldMakeInvoiceStatusService) SpringContextHolder.getBean(InvoiceApplyCustomerFieldMakeInvoiceStatusService.class);

		this.invoiceApplySupplierXGoodsService = (InvoiceApplySupplierXGoodsService) SpringContextHolder.getBean(InvoiceApplySupplierXGoodsService.class);

		this.invoiceApplyCustomerExportExcelService = (InvoiceApplyCustomerExportExcelService) SpringContextHolder.getBean(InvoiceApplyCustomerExportExcelService.class);

		this.invoiceBankInfoService = (InvoiceBankInfoService) SpringContextHolder.getBean(InvoiceBankInfoService.class);

		this.singleBillingCallService = (SingleBillingCallService) SpringContextHolder.getBean(SingleBillingCallService.class);

		this.resourceConstant = (ResourceConstant) SpringContextHolder.getBean(ResourceConstant.class);
	}

	// 财务-待开票 -> 状态 ->
	public SysNotify opInit() {

		log.info("财务-待开票 -> 状态 -> {} -> 待开票(0, \"待开票\")", getClass().getName());

		InvoiceApply entity       = context.getEntity();
		LoginSysUser loginSysUser = context.getLoginSysUser();

		return invoiceApplyFieldInvoiceProgressingStatusService.opInitByStateMachine(entity, loginSysUser);
	}

	// 财务-作废票 -> 状态 -> 已作废(2, "已作废")
	public SysNotify opBecomeInvalid() {

		log.info("财务-作废票 -> 状态 -> {} -> 已作废(2, \"已作废\")", getClass().getName());

		InvoiceApply entity       = context.getEntity();
		LoginSysUser loginSysUser = context.getLoginSysUser();

		return invoiceApplyFieldInvoiceProgressingStatusService.opBecomeInvalidByStateMachine(entity, loginSysUser);
	}

	// 财务-发起开票 -> 状态 -> 开票中(10, "开票中")
	public SysNotify opOngoing() {

		log.info("\n财务-发起开票 -> 状态 -> {} -> 开票中(10, \"开票中\")", getClass().getName());

		SzhtxxInvoiceFptxxOpSingleBillingForm form         = context.getForm();
		InvoiceApply                                    entity       = context.getEntity();
		LoginSysUser                                    loginSysUser = context.getLoginSysUser();

//		opOngoingByStateMachineHook(entity, loginSysUser);

		return invoiceApplyFieldInvoiceProgressingStatusService.opOngoingByStateMachine(form, entity, loginSysUser);
	}

	//	财务-发起开票 -> 状态 -> 待开票(0, "待开票") -> 开票中(10, "开票中") 操作为 op发起开票
	public void opOngoingByStateMachineHook(InvoiceApply invoiceApplyCustomer, LoginSysUser loginSysUser) {

		log.info("\n财务-发起开票 -> 状态 -> {} -> 开票中(10, \"开票中\")\n{}\n{}", getClass().getName(), JSONUtil.toJsonPrettyStr(invoiceApplyCustomer), JSONUtil.toJsonPrettyStr(loginSysUser));

		List<Long> queryInvoiceApplyIds = new ArrayList<>();

		queryInvoiceApplyIds.add(invoiceApplyCustomer.getId());

		// 三步走 mark by linjinyu at 20210317
		// 1. 数据
		// 2. 生成excel
		// 3. 通知
//		List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultList = invoiceApplySupplierXGoodsService.getInvoiceApplySupplierDetailInnerGoodsList(
//				InvoiceApplySupplierOpDetailInnerGoodsListQueryCriteria
//						.builder()
//						.invoiceApplyIdSelect(queryInvoiceApplyIds)
//						.build()
//		);

		List<ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo> resultList = invoiceApplyCustomerService.findInvoiceApplyFocusScoreDimCredit(
				InvoiceApplyCustomerQueryCriteria.builder()
						.invoiceApplyIdsSelected(queryInvoiceApplyIds)
						.build()
		);

		Map<String, InvoiceApplyCustomerExportExcelFocusScoreDimCreditStruct> resultMap = invoiceApplyCustomerExportExcelService.mergeResultByExcelDebugAndCreateWorkbook(3, resultList);


		for (Map.Entry<String, InvoiceApplyCustomerExportExcelFocusScoreDimCreditStruct> _entry : resultMap.entrySet()) {

//			log.info("\n财务-发起开票 -> 状态 -> {} -> 开票中(10, \"开票中\")\n{}\n{}", getClass().getName(), _entry.getKey(), JSONUtil.toJsonPrettyStr(_entry.getValue()));

			String purchaseVirtName = AnStringUtils.stringListConvertToString(_entry.getValue()
					.getTransferListBySheet()
					.stream()
					.map(ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo::getEnterpriseName)
					.distinct()
					.collect(Collectors.toList())
			);
			String invoiceApplySn = _entry.getKey();
			String accountingOrderSn = AnStringUtils.stringListConvertToString(_entry.getValue()
					.getTransferListBySheet()
					.stream()
					.map(ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo::getAccountingOrderSn)
					.distinct()
					.collect(Collectors.toList())
			);

			/****************************************** 侨城汇需求 20210922 start ******************************************/
			invoiceApplyCustomerExportExcelService.qchNeed20210922(_entry.getValue().getTransferListBySheetMerge());
			/****************************************** 侨城汇需求 20210922   end ******************************************/


//			ExcelExportModeEasyExcelUtils.createSheetByWorkbook(
//					_entry.getValue().getTransferListBySheetMerge(),
//					mapperHeadMerge.get(3),
//					mapperValueMerge.get(3),
//					excelWriter,
//					sheetNo,
//					_entry.getKey() + "_合并"
//			);

			/****************************************** 面单 start ******************************************/


			/****************************************** 销方信息 start ******************************************/

			InvoiceBankInfo invoiceBankInfoEntity = invoiceBankInfoService.getByDefault();


			/****************************************** 购方信息 start ******************************************/

			SysEnterpriseExtInvoiceParam sysEnterpriseExtInvoiceParam = null;

			if (invoiceApplyCustomer.getSysEnterpriseExtInvoiceId().compareTo(0L) != 0) {
				sysEnterpriseExtInvoiceParam = AnJsonUtils.toObject(invoiceApplyCustomer.getSysEnterpriseExtInvoiceSnapshot(), SysEnterpriseExtInvoiceParam.class);

				sysEnterpriseExtInvoiceParam.setTaxpayersIDCode("1111111111");
			} else {
				sysEnterpriseExtInvoiceParam = new SysEnterpriseExtInvoiceParam();
			}


			BigDecimal taxRateHundred = new BigDecimal(invoiceApplyCustomer.getTaxRate());
			BigDecimal taxRateOne     = taxRateHundred.divide(new BigDecimal(100L), 2, BigDecimal.ROUND_HALF_UP);
//			BigDecimal taxRateOneSurplus = new BigDecimal(1L).subtract(taxRateOne);
			BigDecimal taxRateOneSurplus = new BigDecimal(1L).add(taxRateOne); // 1+税率

			BigDecimal invoiceApplyAmountIncludeTax = invoiceApplyCustomer.getInvoiceApplyAmount();
//			BigDecimal invoiceApplyTaxAmount        = invoiceApplyAmountIncludeTax.multiply(taxRateOne); // 税额
//			BigDecimal invoiceApplyAmountWithOutTax = invoiceApplyAmountIncludeTax.subtract(invoiceApplyTaxAmount);
			BigDecimal invoiceApplyAmountWithOutTax = invoiceApplyAmountIncludeTax.divide(taxRateOneSurplus, 2, BigDecimal.ROUND_HALF_UP);
			BigDecimal invoiceApplyTaxAmount        = invoiceApplyAmountIncludeTax.subtract(invoiceApplyAmountWithOutTax); // 税额


			BigDecimal invoiceApplyTaxAmountCount = BigDecimal.ZERO;

			List<BigDecimal> invoiceApplyTaxAmountList = new ArrayList<>();


			SingleBillingRequestBodyKpContentFptxxVo fptxx = SingleBillingRequestBodyKpContentFptxxVo.builder()
					.fpqqlsh(invoiceApplyCustomer.getInvoiceApplySn()) // 发票请求唯一流水号;

					.kpxm("办公用品") // 开票项目名称; 主要开票商品,或 者第一条 商品,取项目信息中第一条 数据的项目名称(或传递大 类例 如:办公用品)
					.dkbz("0") // 代开标志; 0:自开 1:代开 默认:0
					.fjh("") // 分机号; 为空时随机获取分机盘开 票,不为空是指定分机盘开 具(A9 暂时不支持,C48 支 持)

					.xhfmc(invoiceBankInfoEntity.getCompanyName()) // 销货方名称;
					.xhfNsrsbh(invoiceBankInfoEntity.getTaxpayersIDCode()) // 销货方纳税人识别号;

					.xhfYhzh(StrUtil.format("{}{}", invoiceBankInfoEntity.getBankName(), invoiceBankInfoEntity.getBankAccount())) // 销货方银行账号;
					.xhfDzdh(StrUtil.format("{}{}", invoiceBankInfoEntity.getAddress(), invoiceBankInfoEntity.getTel())) // 销货方地址电话;

					.ghfmc(sysEnterpriseExtInvoiceParam.getCompanyName()) // 购货方名称;
					.ghfNsrsbh(sysEnterpriseExtInvoiceParam.getTaxpayersIDCode()) // 购货方纳税人识别号;

					.ghfYhzh(StrUtil.format("{}{}", sysEnterpriseExtInvoiceParam.getInvoiceBank(), sysEnterpriseExtInvoiceParam.getInvoiceAccount())) // 购货方银行账号;
					.ghfDzdh(StrUtil.format("{}{}", sysEnterpriseExtInvoiceParam.getInvoiceAddress(), sysEnterpriseExtInvoiceParam.getInvoicePhone())) // 购货方地址电话;

					.ghfqylx("01") // 购货方企业类型; 购货方企业类型 01 02 代表企 业,两者没区别,03 代表个 人

					// .ghfSj(sysEnterpriseExtInvoiceParam.getInvoicePhone()) // 购货方手机(发票交付手机号);
					.ghfSj("") // 购货方手机(发票交付手机号); mark by linjinyu at 20220614 按道理是设置为不交付的，这个设置没作用？按这样说，这个手机就是不能填充罗 【【结算中心-测试环境】积分结算-发票申请管理-【深圳航信电子发票】不用交付手机号】https://www.tapd.cn/33003868/bugtrace/bugs/view?bug_id=1133003868001005367
					.ghfEmail(sysEnterpriseExtInvoiceParam.getInvoiceEmail()) // 购货方邮箱(发票交付邮箱); // sysEnterpriseExtInvoiceParam.getInvoiceEmail()

					.kpy("张三") // 开票人;
					.sky("李四") // 收款人;
					.fhr("王五") // 复核人;

					.billSentSign("1") // 交付标志; 0:不交付, 1:交付邮箱, 2 交付手机, 3:手机邮箱都交付 默认:0 // 产品说 默认交付为 1:交付邮箱

					.qdBz("0") // 清单标志;
					// 0-普通电子发票
					// 1-普通电子发票(清单)
					// 2-收购电子发票 3-收购电子发票(清单)
					// 4-成品油电子发票(成品油无 清单)
					// 备注:默认为 0
					// 1、3 清单是指强制清单
					// 0、2 如果超出 8 行自动打印 清单。
					// 4 成品油,则商品明细行不能 有其他商品,一个商品是成 品油,另一个不是成品油, 开不出来票。并且成品油的 发票的商品行中,单价、数 量、单位必填,其中单位为 升或者吨
					.qdxmmc("") // 清单项目名称; 清单标志为 1 时必填

					.kplx("1") // 开票类型; 开票类型(1 是蓝票,2 是红 票,10 特殊冲红)

					.yfpDm("") // 原发票代码; 开红票时必填
					.yfpHm("") // 原发票号码; 开红票时必填

					.kphjje(NumberUtil.roundStr(invoiceApplyAmountIncludeTax.doubleValue(), 2)) // 价税合计; 小数点后 2 位,以 元为单位 精确到分
					.hjbhsje(NumberUtil.roundStr(invoiceApplyAmountWithOutTax.doubleValue(), 2)) // 合计不含税金额; 小数点后 2 位,以 元为单位 精确到分 (单行商品金额之 和)。
					.hjse(NumberUtil.roundStr(invoiceApplyTaxAmount.doubleValue(), 2)) // 合计税额; 小数点后 2 位,以 元为单位 精确到分 (单行商品税额之 和)

					.bz("") // 备注" 增值税发票红字发票开具时,备注要求: 开具负数发票,必须在备注中注明"对应正数发票代码:XXXXXXXXX 号码:YYYYYYYY"字 样,其中"X"为 发票代码,"Y"为发票号码。

					.callBackUrl("") // pdf 生成回调标志;

					.build();

			/****************************************** 明细 start ******************************************/

			List<SingleBillingRequestBodyKpContentXmxxItemVo> xmxx = new ArrayList<>();

//			_entry.getValue().getTransferListBySheetMerge().forEach(item -> {
			int i    = 0;
			int size = _entry.getValue().getTransferListBySheetMerge().size();
			for (ExportExcelInvoiceApplyCustomerForceScoreDimCreditVo item : _entry.getValue().getTransferListBySheetMerge()) {

				i++;
//				BigDecimal taxRateItemHundred    = item.getOperationTaxRate();
//				BigDecimal taxRateItemOne        = taxRateItemHundred.divide(new BigDecimal(100L), 2, BigDecimal.ROUND_HALF_UP);

				BigDecimal taxRateItemHundred    = item.getOperationTaxRate();
				BigDecimal taxRateItemOne        = item.getOperationTaxRate();
				BigDecimal taxRateItemOneSurplus = new BigDecimal(1L).add(taxRateItemOne);//


				/****************************************** ?? start ******************************************/
//				BigDecimal goodsItemAmount           = item.getPrice().multiply(new BigDecimal(item.getQuantity())); // 正项额
//				BigDecimal goodsItemTaxAmount        = goodsItemAmount.multiply(taxRateItemOne); // 正项额 税额
//				BigDecimal goodsItemAmountWithOutTax = goodsItemAmount.subtract(goodsItemTaxAmount); // 正项额 不包含 税
//
//
//				BigDecimal goodsItemDiffAmount           = goodsItemAmount.subtract(item.getBalance());// 扣除额
//				BigDecimal goodsItemDiffTaxAmount        = goodsItemDiffAmount.multiply(taxRateItemOne);// 扣除额 税额
//				BigDecimal goodsItemDiffAmountWithOutTax = goodsItemDiffAmount.subtract(goodsItemDiffTaxAmount);// 扣除额 不包含 税
//
//				BigDecimal goodsItemDiffAmountMinus           = goodsItemDiffAmount.multiply(new BigDecimal(-1L)); // 扣除额 转换成 -扣除额
//				BigDecimal goodsItemDiffTaxAmountMinus        = goodsItemDiffTaxAmount.multiply(new BigDecimal(-1L));// -扣除额 税额
//				BigDecimal goodsItemDiffAmountWithOutTaxMinus = goodsItemDiffAmountWithOutTax.multiply(new BigDecimal(-1L));// -扣除额 不包含 税
				/****************************************** ?? start ******************************************/

				BigDecimal goodsItemAmount           = item.getPrice().multiply(new BigDecimal(item.getQuantity()));                            // 正项额
				BigDecimal goodsItemAmountWithOutTax = goodsItemAmount.divide(taxRateItemOneSurplus, 2, BigDecimal.ROUND_HALF_UP);          // 正项额 不含税
				BigDecimal goodsItemTaxAmount        = goodsItemAmount.subtract(goodsItemAmountWithOutTax);                                       // 正项额 税额


				BigDecimal goodsItemDiffAmount           = goodsItemAmount.subtract(item.getBalance());// 扣除额
				BigDecimal goodsItemDiffAmountWithOutTax = goodsItemDiffAmount.divide(taxRateItemOneSurplus, 2, BigDecimal.ROUND_HALF_UP);// 扣除额 不含税
				BigDecimal goodsItemDiffTaxAmount        = goodsItemDiffAmount.subtract(goodsItemDiffAmountWithOutTax);// 扣除额 税额


				BigDecimal goodsItemDiffAmountMinus           = goodsItemDiffAmount.multiply(new BigDecimal(-1L)); // 扣除额 转换成 -扣除额
				BigDecimal goodsItemDiffAmountWithOutTaxMinus = goodsItemDiffAmountWithOutTax.multiply(new BigDecimal(-1L));// -扣除额 不包含 税
				BigDecimal goodsItemDiffTaxAmountMinus        = goodsItemDiffTaxAmount.multiply(new BigDecimal(-1L));// -扣除额 税额

				// 最后一次
				if (size == i) {

					// 最后一项有扣减项
					if (goodsItemDiffAmount.compareTo(BigDecimal.ZERO) != 0) {
						goodsItemTaxAmount = invoiceApplyTaxAmount.subtract(invoiceApplyTaxAmountCount).subtract(goodsItemDiffTaxAmount);
					} else {
						goodsItemTaxAmount = invoiceApplyTaxAmount.subtract(invoiceApplyTaxAmountCount);
					}
				} else {
					invoiceApplyTaxAmountCount = invoiceApplyTaxAmountCount.add(goodsItemTaxAmount).add(goodsItemDiffTaxAmountMinus);

				}


//				log.info("平台税率 {} {}", item.getOperationTaxRate(), item.getOperationTaxCode());

				log.info("\n{} {} {} \n{} {} {} \n{}", goodsItemAmount, taxRateItemOne, goodsItemTaxAmount, goodsItemDiffAmountMinus, taxRateItemOne, goodsItemDiffTaxAmountMinus, invoiceApplyTaxAmountCount);

//				plus-minus

				SingleBillingRequestBodyKpContentXmxxItemVo plus  = null;
				SingleBillingRequestBodyKpContentXmxxItemVo minus = null;

				plus = SingleBillingRequestBodyKpContentXmxxItemVo.builder()
						.xmmc(item.getGoodsName()) // 商品名称; 如 FPHXZ=1,则此商 品行为 折扣行,此 版本折扣行不允 许 多行折扣,折扣行 必须紧 邻被折扣 行,项目名称必须 与被折扣行一致。
						.xmdw(item.getUnit()) // 单位; 项目单位
//						.ggxh(item.getSelfOption()) // 型号; 规格型号 // 第13行:GGXH  非通行费发票 字符串长度小于等于40" // 单价 数量 规格型号 计量单位这些可以不传

						.hsbz("1") // 含税标志;表示项目单价和项 目金额是 否含税。0 表示都不含税,1 表 示都含税。 item.getFlagTaxIncluded()
						.yhzcbs("0") // 优惠政策标识;0:不使用,1:使 用 item.getFlagTaxIncentives()

						.fphxz("0") // 发票行性质;0正常行、1折扣行、 2被折扣行

						.lslbs("") // 零税率标识;空:非零税率, 1: 免税, 2:不征税, 3 普通零税率
						.zzstsgl("") // 增值税特殊管理;当 YHZCBS(优惠政策标识) 为 1 时必 填

						.xmsl(item.getQuantity()) // 数量; 小数点后 8 位, 小 数点后都是 0 时, PDF 上只显示整数 (特殊情况:如果不传单价, 数量。则含税标志选 0,项目 金额传不含税)
						.xmdj(item.getPrice()) // 单价; 小数点后 8 位小数 点后都是 0 时,PDF 上只显 示2 位小数; 否则只显示至 最后 一位不为0 的数字 (特殊情况:如果不传,需同时 不传单价和数量)

//						.kce(NumberUtil.roundStr(goodsItemDiffAmount.doubleValue(), 2)) // 扣除额;小数点 2 位小数,不能大于不 含税金额 说明如下: 1、差额征税的发票如果没有折扣的话,只能允许一条商 品行。 2、具体差额征税发票的计算 方法如下: 不含税差额 = 不含税金额 - 扣 除额; 税额 = 不含税差额 * 税率;
						.xmje(NumberUtil.roundStr(goodsItemAmount.doubleValue(), 2)) // 项目金额;小数点后 2 位,以 元为单位 精确到 分。 等于=单价*数 量, 根据含税标志,确 定此 金额是否为含 税金额。
						.se(NumberUtil.roundStr(goodsItemTaxAmount.doubleValue(), 2)) // 税额;小数点后 2 位,以 元为单位 精确到分

						.spbm(item.getOperationTaxCode()) // 税收分类编码;商品编码?
						.sl(item.getOperationTaxRate().toString()) // 税率;如果税率为 0,表示免税
						.build();


				invoiceApplyTaxAmountList.add(goodsItemTaxAmount);

				xmxx.add(plus);

				if (goodsItemDiffAmount.compareTo(BigDecimal.ZERO) != 0) {

					plus.setFphxz("2");

					minus = SingleBillingRequestBodyKpContentXmxxItemVo.builder()
							.xmmc(item.getGoodsName()) // 商品名称; 如 FPHXZ=1,则此商 品行为 折扣行,此 版本折扣行不允 许 多行折扣,折扣行 必须紧 邻被折扣 行,项目名称必须 与被折扣行一致。
							.xmdw("") // item.getUnit() // 单位; 项目单位
//							.ggxh(item.getSelfOption()) // 型号; 规格型号 // 第13行:GGXH  非通行费发票 字符串长度小于等于40" // 单价 数量 规格型号 计量单位这些可以不传


							.yhzcbs("0") // 优惠政策标识;0:不使用,1:使 用 item.getFlagTaxIncentives()

							.fphxz("1") // 发票行性质;0正常行、1折扣行、 2被折扣行

							.lslbs("") // 零税率标识;空:非零税率, 1: 免税, 2:不征税, 3 普通零税率
							.zzstsgl("") // 增值税特殊管理;当 YHZCBS(优惠政策标识) 为 1 时必 填


							// (特殊情况:如果不传单价, 数量。则含税标志选 0,项目 金额传不含税)
							.xmsl(null) // item.getQuantity() 数量; 小数点后 8 位, 小 数点后都是 0 时, PDF 上只显示整数 (特殊情况:如果不传单价, 数量。则含税标志选 0,项目 金额传不含税)
							.xmdj(null) // item.getPrice() 单价; 小数点后 8 位小数 点后都是 0 时,PDF 上只显 示2 位小数; 否则只显示至 最后 一位不为0 的数字 (特殊情况:如果不传,需同时 不传单价和数量)

							.hsbz("1") // 含税标志;表示项目单价和项 目金额是 否含税。0 表示都不含税,1 表 示都含税。 item.getFlagTaxIncluded()
//							.xmje(NumberUtil.roundStr(goodsItemDiffAmountWithOutTaxMinus.doubleValue(), 2))

//							.kce("0.00") // 扣除额;小数点 2 位小数,不能大于不 含税金额 说明如下: 1、差额征税的发票如果没有折扣的话,只能允许一条商 品行。 2、具体差额征税发票的计算 方法如下: 不含税差额 = 不含税金额 - 扣 除额; 税额 = 不含税差额 * 税率;
							.xmje(NumberUtil.roundStr(goodsItemDiffAmountMinus.doubleValue(), 2)) // 项目金额;小数点后 2 位,以 元为单位 精确到 分。 等于=单价*数 量, 根据含税标志,确 定此 金额是否为含 税金额。
							.se(NumberUtil.roundStr(goodsItemDiffTaxAmountMinus.doubleValue(), 2)) // 税额;小数点后 2 位,以 元为单位 精确到分

							.spbm(item.getOperationTaxCode()) // 税收分类编码;商品编码?
							.sl(item.getOperationTaxRate().toString()) // 税率;如果税率为 0,表示免税
							.build();

					invoiceApplyTaxAmountList.add(goodsItemDiffTaxAmountMinus);


					xmxx.add(minus);
				}

			}
//			});

			log.info("\n税额1 {}\n税额2 {}\n税额1(#.##) {}\n税额2(#.##) {} \n{}",
					invoiceApplyTaxAmount, invoiceApplyTaxAmountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add),
					NumberUtil.roundStr(invoiceApplyTaxAmount.doubleValue(), 2), NumberUtil.roundStr(invoiceApplyTaxAmountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue(), 2),
					JSONUtil.toJsonStr(invoiceApplyTaxAmountList));

//			fptxx.hjse = xmxx.se 累加

			SingleBillingRequest request = SingleBillingRequest
					.builder()
					.kpContent(SingleBillingRequestBodyKpContent
							.builder()
							.fptxx(fptxx)
							.xmxx(xmxx)
							.build()
					)
					.build();


//			String excelExportPathRoot             = excelExportConstant.getPathRoot();
//			String excelExportRelativePathTemplate = excelExportConstant.getPathTemplate();
//			String excelExportRelativePathStorage  = excelExportConstant.getPathStorage();
//
//			String relativePath = File.separator + "thirdpart" + File.separator + "szhtxx" + File.separator + "electronicInvoice" + File.separator;
//
////		String templateRelativePath = excelExportPathRoot + excelExportRelativePathTemplate + relativePath;
////		String templateFullPath;
//
//			String targetFullPath          = excelExportPathRoot + excelExportRelativePathStorage;
//			String targetFileName          = StrUtil.format("SingleBilling_{}.json", DateUtil.now());
//			String targetWriteFileFullPath = targetFullPath + relativePath + targetFileName;
//
//			FileUtil.touch(targetWriteFileFullPath);
//			FileUtil.writeUtf8String(JSONUtil.toJsonPrettyStr(request), targetWriteFileFullPath);// CharsetUtil.CHARSET_UTF_8


			SingleBillingResponse response = singleBillingCallService.callSingleBillingApi(request);


		}


	}

	// 财务-确认开票 -> 状态 -> 已开票(11, "已开票")
	public SysNotify opComplete() {

		log.info("财务-确认开票 -> 状态 -> {} -> 已开票(11, \"已开票\")", getClass().getName());

		InvoiceApply entity       = context.getEntity();
		LoginSysUser loginSysUser = context.getLoginSysUser();

		return invoiceApplyFieldInvoiceProgressingStatusService.opCompleteByStateMachine(entity, loginSysUser);
	}

}
