package com.dk.mdm.service.mac;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.dk.common.exception.BaseBusinessException;
import com.dk.common.infrastructure.annotaiton.Pagination;
import com.dk.common.infrastructure.constant.Constant;
import com.dk.common.infrastructure.enums.ErrorCodeEnum;
import com.dk.common.response.ResponseCodeEnum;
import com.dk.common.response.ResponseResultUtil;
import com.dk.common.response.ResponseResultVO;
import com.dk.mdm.mapper.ivt.InboundMapper;
import com.dk.mdm.mapper.ivt.OutboundMapper;
import com.dk.mdm.mapper.mac.*;
import com.dk.mdm.mapper.mst.MoneyAccountItemMapper;
import com.dk.mdm.mapper.mst.MoneyAccountMapper;
import com.dk.mdm.mapper.sale.OrderMapper;
import com.dk.mdm.model.pojo.ivt.Inbound;
import com.dk.mdm.model.pojo.ivt.Outbound;
import com.dk.mdm.model.pojo.mac.*;
import com.dk.common.service.BaseService;
import com.dk.common.mapper.BaseMapper;
import com.dk.mdm.model.pojo.mst.MoneyAccount;
import com.dk.mdm.model.pojo.sale.Order;
import com.dk.mdm.model.query.mac.AccountItemQuery;
import com.dk.mdm.model.response.mac.AccountItemResponse;
import com.dk.mdm.model.response.mac.AccountResponse;
import com.dk.mdm.service.common.CommonService;
import com.dk.mdm.service.mst.MoneyAccountService;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

@Service
@Transactional
public class AccountService extends BaseService<Account> {

    @Override
    public String getPrimaryKey() {
        return "object_id";
    }

    @Override
    public BaseMapper<Account> getRepository() {
        return accountMapper;
    }

    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    private AccountItemService accountItemService;

    @Autowired
    private AccountItemMapper accountItemMapper;

    @Autowired
    private MoneyAccountService moneyAccountService;

    @Autowired
    private MoneyAccountMapper moneyAccountMapper;

    @Autowired
    private MoneyAccountItemMapper moneyAccountItemMapper;

    @Autowired
    private OutboundMapper outboundMapper;

    @Autowired
    private InboundMapper inboundMapper;

    @Autowired
    private OtherReceivableMapper otherReceivableMapper;

    @Autowired
    private OtherPayableMapper otherPayableMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RecPayMapper recPayMapper;

    @Autowired
    private ReceiptService receiptService;

    @Autowired
    private RecPayItemMapper recPayItemMapper;

    @Autowired
    private RecPayHandleItemMapper recPayHandleItemMapper;

    @Autowired
    private CommonService commonService;

    /**
     * @desc : 查看来源单据,总单加明细
     * @author : 姜永辉
     * @date : 2024/3/6 10:36
     */
    public ResponseResultVO selectById(String id) {
        //根据id查询
        AccountResponse accountResponse = accountMapper.selectById(id);
        List<AccountItemResponse> accountItemResponses = accountItemMapper.getReceivableAccountItem(new AccountItemQuery().setObjectId(id));
        accountResponse.setList(accountItemResponses);
        return ResponseResultUtil.success(accountResponse);
    }

    /**
     * @desc : 只查询总单, 不包含总单加明细
     * @author : 姜永辉
     * @date : 2024/3/6 10:36
     */
    public ResponseResultVO selectAccountById(String id) {
        //根据id查询
        AccountResponse accountResponse = accountMapper.selectById(id);
        return ResponseResultUtil.success(accountResponse);
    }

    /**
     * @desc : 查询明细的总数量
     * @author : 姜永辉
     * @date : 2024/3/6 10:36
     */
    public ResponseResultVO countByCond(AccountItemQuery accountItemQuery) {
        //根据id查询
        Long aLong = accountItemMapper.countByCond(accountItemQuery);
        return ResponseResultUtil.success(aLong);
    }

    /**
     * @desc : 查询应收账款明细
     * @author : 付斌
     * @date : 2024-02-28 13:25
     */
    @Pagination
    public ResponseResultVO<?> getReceivableAccountItem(AccountItemQuery accountItemQuery) {
        List<AccountItemResponse> accountItemResponse = accountItemMapper.getReceivableAccountItem(accountItemQuery);
        return ResponseResultUtil.success(accountItemResponse);
    }

    /**
     * @desc : 查询应付账款明细
     * @author : 付斌
     * @date : 2024-02-28 13:25
     */
    @Pagination
    public ResponseResultVO<?> getPayableAccountItem(AccountItemQuery accountItemQuery) {
        List<AccountItemResponse> accountItemResponse = accountItemMapper.getPayableAccountItem(accountItemQuery);
        return ResponseResultUtil.success(accountItemResponse);
    }


    /*********************  账款部分共通方法 begin **********************/
    /**
     * @desc : 获取账款总表，没有则新建(客户)
     * @author : 付斌
     * @date : 2024-03-23 16:32
     */
    public Account getCusAccountForUpdate(String objectId) {
        return getAccountForUpdate(objectId, Constant.ObjectType.CUS.getName());
    }

    /**
     * @desc : 获取账款总表，没有则新建(供应商)
     * @author : 付斌
     * @date : 2024-03-23 16:32
     */
    public Account getSupAccountForUpdate(String objectId) {
        return getAccountForUpdate(objectId, Constant.ObjectType.SUP.getName());
    }

    /**
     * @desc : 更新总帐上收款类字段
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updateReceipt(String objectId) {
        Account accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
        Map<String, Object> mapSumAmtRecPay = accountItemMapper.getSumAmtRec(objectId);
        BigDecimal sumAmtRec = new BigDecimal(mapSumAmtRecPay.get("sumAmtRec").toString());
        // 可退金额 = 总收款额-应收应款额+优惠金额
        BigDecimal sumReceiptResidue = sumAmtRec.subtract(accountForUpdate.getReceivableHandle()).add(accountForUpdate.getReceivableWaive());

        // 如果可退金额小于0 ，则提示余额不足
        if (sumReceiptResidue.compareTo(BigDecimal.ZERO) == -1) {
            throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.RESIDUE_NO_LESS.getMessage());
        }

        // 更新账款总表上的收款总额和可用金额
        Account accountUpdate = new Account();
        accountUpdate.setReceipt(sumAmtRec).setReceiptResidue(sumReceiptResidue).setObjectId(objectId);
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 更新总帐上收款类字段
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updateReceiptLock(String objectId) {
        Account accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
        Map<String, Object> mapSumAmtRecPay = accountItemMapper.getSumAmtRecLock(objectId);
        BigDecimal sumAmtRecLock = new BigDecimal(mapSumAmtRecPay.get("sumAmtRecLock").toString());

        // 更新账款总表上的收款总额和可用金额
        Account accountUpdate = new Account();
        accountUpdate.setReceiptLock(sumAmtRecLock).setObjectId(accountForUpdate.getObjectId());
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 更新总帐上付款类字段
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updatePayment(String objectId) {
        Account accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
        Map<String, Object> mapSumAmtRecPay = accountItemMapper.getSumAmtPay(objectId);
        BigDecimal sumAmtPay = new BigDecimal(mapSumAmtRecPay.get("sumAmtPay").toString());
        // 可退金额 = 总收款额-应收应款额+优惠金额
        BigDecimal sumPaymentResidue = sumAmtPay.subtract(accountForUpdate.getPayableHandle()).add(accountForUpdate.getPayableWaive());

        // 如果可退金额小于0 ，则提示余额不足
        if (sumPaymentResidue.compareTo(BigDecimal.ZERO) == -1) {
            throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.RESIDUE_NO_LESS.getMessage());
        }

        // 更新账款总表上的收款总额和可用金额
        Account accountUpdate = new Account();
        accountUpdate.setPayment(sumAmtPay).setPaymentResidue(sumPaymentResidue).setObjectId(objectId);
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 更新资金账户余额
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updateMac(String macId) {
        if (macId == null) {
            return;
        }
        // 查询当前账户流水合计
        Map<String, Object> mapSumAmtInflow = moneyAccountItemMapper.getSumAmtInflow(macId);
        BigDecimal sumAmtInflow = new BigDecimal(mapSumAmtInflow.get("sumAmtInflow").toString());

        // 更新资金账户
        MoneyAccount moneyAccountForUpdate = moneyAccountMapper.selectByIdForUpdate(macId);
        // 如果账户不允许为负数
        if (!moneyAccountForUpdate.getFlgNegative()) {
            // 如果余额小于0 ，则提示余额不足
            if (sumAmtInflow.compareTo(BigDecimal.ZERO) == -1) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.MAC_BALANCE_NO_LESS.getMessage());
            }
        }

        // 更新账款总表上的收款总额和可用金额
        MoneyAccount moneyAccountUpdate = new MoneyAccount();
        moneyAccountUpdate.setBalance(sumAmtInflow).setMacId(macId);
        moneyAccountService.updateByUuid(moneyAccountUpdate);
    }

    /**
     * @desc : 更新合同资产
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updateContractAssets(String objectId) {
        if (objectId == null) {
            return;
        }
        // 更新账款总表上的总应收账款和总剩余应收
        Account accountForUpdate = getCusAccountForUpdate(objectId);

        // 查询订单出库金额
        Map<String, Object> mapSumAmtOrder = accountItemMapper.getSumAmtOrder(objectId);
        BigDecimal sumAmtOrder = new BigDecimal(mapSumAmtOrder.get("sumAmtOrder").toString());

        // 更新账款总表上的收款总额和可用金额
        Account accountUpdate = new Account();
        accountUpdate.setContractAssets(sumAmtOrder).setObjectId(accountForUpdate.getObjectId());
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 更新采购暂估
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void updatePurEstimate(String objectId) {
        if (objectId == null) {
            return;
        }
        // 更新账款总表上的总应收账款和总剩余应收
        Account accountForUpdate = getSupAccountForUpdate(objectId);

        // 查询订单出库金额
        Map<String, Object> mapSumAmtPur = accountItemMapper.getSumAmtPur(objectId);
        BigDecimal sumAmtPur = new BigDecimal(mapSumAmtPur.get("sumAmtPur").toString());

        // 更新账款总表上的收款总额和可用金额
        Account accountUpdate = new Account();
        accountUpdate.setPurEstimate(sumAmtPur).setObjectId(accountForUpdate.getObjectId());
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 应收记账
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void accReceivable(String invoiceId, String biznisType) {
        // 账款明细
        AccountItem accountItemInsert = new AccountItem();
        // 账务对象Id
        String objectId = null;

        if ("t_psi_outbound".equals(biznisType)) {
            Outbound outbound = outboundMapper.selectByIdForUpdate(invoiceId);
            objectId = outbound.getCusId();

            // 当前单据已经记账
            if (outbound.getReceivableId() != null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISACC.getMessage());
            }
            // 账务日期不能为空
            if (outbound.getOutDate() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.ACC_DATE_ISNULL.getMessage());
            }
            // 插入账款明细
            accountItemInsert.setAccItemType(Constant.accItemType.YING_SHOU.getName())
                    .setObjectId(objectId).setOrgId(outbound.getOrgId()).setStaffId(outbound.getStaffId())
                    .setAccDate(outbound.getOutDate()).setRecStatus(Constant.recStatuse.QUE_DING.getName())
                    .setAmtShould(outbound.getOutAmt()).setAmtResidue(outbound.getOutAmt())
                    .setBiznisType(biznisType).setBiznisId(outbound.getOutId()).setBiznisNo(outbound.getOutNo())
                    .setMakeStaff(outbound.getMakeStaff()).setCpId(outbound.getCpId());
            accountItemMapper.insert(accountItemInsert);

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<Outbound> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(Outbound::getReceivableId, UUID.fromString(accountItemInsert.getItemId())).eq(Outbound::getOutId, UUID.fromString(invoiceId));
            outboundMapper.update(null, updateWrapper);

            // 更新账款总表上的总应收账款和总剩余应收
            Account accountForUpdate = getCusAccountForUpdate(objectId);
            Account accountUpdate = new Account();
            accountUpdate.setReceivable(accountForUpdate.getReceivable().add(accountItemInsert.getAmtShould()))
                    .setReceivableResidue(accountForUpdate.getReceivableResidue().add(accountItemInsert.getAmtShould()))
                    .setObjectId(objectId);
            super.updateByUuid(accountUpdate);

            // 如果当前出库单对应的订单全部出库了，并且订单有收款（锁定金额），则自动做应收核销
            // 如果是销售出库
            if (outbound.getOutType().equals(Constant.OutType.SALE.getName())) {
                Order orderForUpdate = orderMapper.selectByIdForUpdate(outbound.getFromId());
                // 如果当前订单已经全部出库
                if (orderForUpdate != null && orderForUpdate.getOutQty().compareTo(orderForUpdate.getSumQuantity()) == 0) {
                    RecPay recPayForUpdate = recPayMapper.selectByBiznisIdForUpdate(orderForUpdate.getOrderId(),false);
                    if (recPayForUpdate != null && recPayForUpdate.getFlgLock()) {
                        // 先把收款单解锁
                        RecPay recPayUpdate = new RecPay();
                        recPayUpdate.setFlgLock(false).setRpId(recPayForUpdate.getRpId());
                        receiptService.updateByUuid(recPayUpdate);

                        // 账款明细解锁
                        List<RecPayItem> recPayItemList = recPayItemMapper.selectByZIdForUpdate(recPayForUpdate.getRpId());
                        for (RecPayItem recPayItem : recPayItemList) {
                            AccountItem accountItemUpdate = new AccountItem();
                            accountItemUpdate.setFlgLock(false).setItemId(recPayItem.getAccItemId());
                            accountItemService.updateByUuid(accountItemUpdate);
                        }

                        // 钱进到现金池中
                        accountUpdate = new Account();
                        accountUpdate.setReceipt(accountForUpdate.getReceipt().add(recPayForUpdate.getSumAmtRec()))
                                .setReceiptResidue(accountForUpdate.getReceiptResidue().add(recPayForUpdate.getSumAmtRec()))
                                .setReceiptLock(accountForUpdate.getReceiptLock().subtract(recPayForUpdate.getSumAmtRec()))
                                .setObjectId(objectId);
                        super.updateByUuid(accountUpdate);

                        // 查出当前订单需要核销的应收单据
                        List<AccountItemResponse> accountItemResponseList = accountItemMapper.getReceivableAccountItemForUpdate(
                                new AccountItemQuery().setObjectId(objectId).setOrderId(orderForUpdate.getOrderId()));

                        if (accountItemResponseList.size() > 0) {
                            // 生成核销总单
                            RecPay recPayHandle = new RecPay();
                            // 获取单号
                            Map<String, Object> codeMap = commonService.getUniqueNoteCode(Constant.docNameConstant.RECPAY.getName(), false);
                            recPayHandle.setRpId(codeMap.get("outId").toString()).setRpNo(codeMap.get("outNote").toString())
                                    .setRpType(Constant.RpType.SHOU_KUAN.getName()).setObjectId(objectId)
                                    .setOrgId(recPayForUpdate.getOrgId()).setStaffId(recPayForUpdate.getStaffId()).setAccDate(LocalDate.now())
                                    .setBiznisType(Constant.InventoryDocCode.ORDER.getTableName()).setBiznisId(recPayForUpdate.getBiznisId()).setBiznisNo(recPayForUpdate.getBiznisNo())
                                    .setMakeStaff(recPayForUpdate.getMakeStaff()).setCpId(recPayForUpdate.getCpId()).setFlgOrderHandle(true);
                            recPayMapper.insert(recPayHandle);

                            // 记录核销了哪些应收账
                            List<RecPayHandleItem> receivableList = new ArrayList<>();

                            // 锁定金额
                            BigDecimal lockAmt = recPayForUpdate.getSumAmtRec();

                            for (AccountItemResponse accountItemResponse : accountItemResponseList) {
                                RecPayHandleItem recPayHandleItem = new RecPayHandleItem();
                                recPayHandleItem.setRpId(recPayHandle.getRpId()).setCpId(recPayHandle.getCpId()).setAccDate(recPayHandle.getAccDate())
                                        .setAccItemId(accountItemResponse.getAccItemId());
                                // 如果定金比应收金额大
                                if (lockAmt.compareTo(accountItemResponse.getAmtResidue()) == 1) {
                                    recPayHandleItem.setAmtReceivableHandle(accountItemResponse.getAmtResidue());
                                    lockAmt = lockAmt.subtract(accountItemResponse.getAmtResidue());
                                } else {
                                    recPayHandleItem.setAmtReceivableHandle(lockAmt);
                                    lockAmt = BigDecimal.ZERO;
                                }
                                recPayHandleItemMapper.insert(recPayHandleItem);
                                receivableList.add(recPayHandleItem);

                                // 账款明细的核销金额和优惠金额
                                AccountItem accountItemForUpdate = accountItemMapper.selectByIdForUpdate(recPayHandleItem.getAccItemId());
                                AccountItem accountItemUpdate = new AccountItem();
                                // 核销金额，超出剩余应收金额
                                if (accountItemForUpdate.getAmtResidue().compareTo(recPayHandleItem.getAmtReceivableHandle()) == -1) {
                                    throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.AMT_HANDLE_NO_LESS_AMT_SHOULD.getMessage());
                                }
                                accountItemUpdate.setAmtHandle(accountItemForUpdate.getAmtHandle().add(recPayHandleItem.getAmtReceivableHandle()))
                                        .setItemId(recPayHandleItem.getAccItemId());
                                // 剩余金额 = 应收金额-应收收款金额
                                accountItemUpdate.setAmtResidue(accountItemForUpdate.getAmtShould().subtract(accountItemUpdate.getAmtHandle()));
                                accountItemService.updateByUuid(accountItemUpdate);

                                // 如果定金都用完了，跳出循环
                                if (lockAmt.compareTo(BigDecimal.ZERO) == 0) {
                                    break;
                                }
                            }

                            // 计算明细的核销金额，优惠金额合计
                            RecPayHandleItem recPayHandleItem = receivableList.stream().reduce((x, y) -> {
                                RecPayHandleItem item = new RecPayHandleItem();
                                item.setAmtReceivableHandle(x.getAmtReceivableHandle().add(y.getAmtReceivableHandle()));
                                return item;
                            }).get();

                            // 更新收款单
                            recPayUpdate = new RecPay();
                            recPayUpdate.setSumAmtReceivableHandle(recPayHandleItem.getAmtReceivableHandle())
                                    .setSumShouldHandle(recPayHandleItem.getAmtReceivableHandle())
                                    .setRpId(recPayHandle.getRpId());
                            receiptService.updateByUuid(recPayUpdate);

                            // 更新总账上
                            accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
                            accountUpdate = new Account();
                            accountUpdate.setReceivableHandle(accountForUpdate.getReceivableHandle().add(recPayHandleItem.getAmtReceivableHandle()))// 总应收收款金额
                                    .setObjectId(accountForUpdate.getObjectId());
                            // 剩余应收 = 总应收账款-总应收收款金额
                            accountUpdate.setReceivableResidue(accountForUpdate.getReceivable().subtract(accountUpdate.getReceivableHandle()));
                            // 可退金额 = 总收款金额-总应收收款金额+总应收优惠金额
                            accountUpdate.setReceiptResidue(accountForUpdate.getReceipt().subtract(accountUpdate.getReceivableHandle()));

                            // 可用金额为负数，则不能保存
                            if (accountUpdate.getReceiptResidue().compareTo(BigDecimal.ZERO) == -1) {
                                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.RESIDUE_NO_LESS.getMessage());
                            }
                            super.updateByUuid(accountUpdate);
                        }
                    }
                }
            }
        }
        // 其他收入单
        else if ("t_mac_other_receivable".equals(biznisType)) {
            OtherReceivable otherReceivable = otherReceivableMapper.selectByIdForUpdate(invoiceId);
            objectId = otherReceivable.getObjectId();

            // 当前单据已经记账
            if (otherReceivable.getAccItemId() != null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISACC.getMessage());
            }
            // 账务日期不能为空
            if (otherReceivable.getAccDate() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.ACC_DATE_ISNULL.getMessage());
            }

            // 插入账款明细
            accountItemInsert.setAccItemType(Constant.accItemType.YING_SHOU.getName())
                    .setObjectId(objectId).setOrgId(otherReceivable.getOrgId()).setStaffId(otherReceivable.getStaffId())
                    .setAccDate(otherReceivable.getAccDate()).setRecStatus(Constant.recStatuse.QUE_DING.getName())
                    .setAmtShould(otherReceivable.getSumAmtReceivable()).setAmtResidue(otherReceivable.getSumAmtReceivable())
                    .setBiznisType(biznisType).setBiznisId(otherReceivable.getReceivableId()).setBiznisNo(otherReceivable.getReceivableNo())
                    .setMakeStaff(otherReceivable.getMakeStaff()).setCpId(otherReceivable.getCpId());
            accountItemMapper.insert(accountItemInsert);

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<OtherReceivable> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(OtherReceivable::getAccItemId, UUID.fromString(accountItemInsert.getItemId())).eq(OtherReceivable::getReceivableId, UUID.fromString(invoiceId));
            otherReceivableMapper.update(null, updateWrapper);

            // 更新账款总表上的总应收账款和总剩余应收
            Account accountForUpdate = getCusAccountForUpdate(objectId);
            Account accountUpdate = new Account();
            accountUpdate.setReceivable(accountForUpdate.getReceivable().add(accountItemInsert.getAmtShould()))
                    .setReceivableResidue(accountForUpdate.getReceivableResidue().add(accountItemInsert.getAmtShould()))
                    .setObjectId(objectId);
            super.updateByUuid(accountUpdate);
        }
    }

    /**
     * @desc : 应收反记账
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void reverseReceivable(String invoiceId, String biznisType) {
        // 更新账款明细应收收款
        AccountItem accountItemForUpdate;
        // 账务对象Id
        String objectId;

        if ("t_psi_outbound".equals(biznisType)) {
            Outbound outbound = outboundMapper.selectByIdForUpdate(invoiceId);
            objectId = outbound.getCusId();

            // 当前单据已经记账
            if (outbound.getReceivableId() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISREVERSE.getMessage());
            }

            Account accountForUpdate;
            Account accountUpdate;
            // 如果当前出库单对应的订单做了应收收款，则自动作废应收核销，并且锁定金额订单收款（锁定金额）
            // 如果是销售出库
            if (outbound.getOutType().equals(Constant.OutType.SALE.getName())) {
                RecPay recPayForUpdate = recPayMapper.selectByBiznisIdForUpdate(outbound.getFromId(),false);        // 款
                RecPay recPayHandleForUpdate = recPayMapper.selectByBiznisIdForUpdate(outbound.getFromId(),true);   // 账
                if (recPayForUpdate != null && recPayHandleForUpdate != null) {
                    // 查出并锁定所有应收核销明细
                    List<RecPayHandleItem> recPayHandleItemForUpdateList = recPayHandleItemMapper.selectByZIdForUpdate(recPayHandleForUpdate.getRpId());
                    if (recPayHandleItemForUpdateList.size() > 0) {
                        for (RecPayHandleItem recPayHandleItemForUpdate : recPayHandleItemForUpdateList) {
                            // 更新账款明细应收收款
                            accountItemForUpdate = accountItemMapper.selectByIdForUpdate(recPayHandleItemForUpdate.getAccItemId());
                            AccountItem accountItemUpdate = new AccountItem();
                            accountItemUpdate.setAmtHandle(accountItemForUpdate.getAmtHandle().subtract(recPayHandleItemForUpdate.getAmtReceivableHandle()))
                                    .setItemId(recPayHandleItemForUpdate.getAccItemId());
                            accountItemUpdate.setAmtResidue(accountItemForUpdate.getAmtShould().subtract(accountItemUpdate.getAmtHandle()));
                            accountItemService.updateByUuid(accountItemUpdate);

                            // 删掉核销明细
                            recPayHandleItemMapper.deleteById(recPayHandleItemForUpdate.getItemId());
                        }

                        // 把总帐上的钱加回来
                        accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
                        accountUpdate = new Account();
                        accountUpdate.setReceivableHandle(accountForUpdate.getReceivableHandle().subtract(recPayHandleForUpdate.getSumAmtReceivableHandle()))// 总应收收款金额
                                .setObjectId(objectId);
                        // 剩余应收 = 总应收账款-总应收收款金额
                        accountUpdate.setReceivableResidue(accountForUpdate.getReceivable().subtract(accountUpdate.getReceivableHandle()));
                        // 可退金额 = 总收款金额-总应收收款金额+总应收优惠金额
                        accountUpdate.setReceiptResidue(accountForUpdate.getReceipt().subtract(accountUpdate.getReceivableHandle()));

                        // 更新前的最后校验
                        // 可用金额为负数，则不能保存
                        if (accountUpdate.getReceiptResidue().compareTo(BigDecimal.ZERO) == -1) {
                            throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.RESIDUE_NO_LESS.getMessage());
                        }
                        super.updateByUuid(accountUpdate);

                        // 删掉收款核销单
                        recPayMapper.deleteById(recPayHandleForUpdate.getRpId());

                        // 先把收款单锁定
                        RecPay recPayUpdate = new RecPay();
                        recPayUpdate.setFlgLock(true).setRpId(recPayForUpdate.getRpId());
                        receiptService.updateByUuid(recPayUpdate);

                        // 账款明细解锁
                        List<RecPayItem> recPayItemList = recPayItemMapper.selectByZIdForUpdate(recPayForUpdate.getRpId());
                        for (RecPayItem recPayItem : recPayItemList) {
                            AccountItem accountItemUpdate = new AccountItem();
                            accountItemUpdate.setFlgLock(true).setItemId(recPayItem.getAccItemId());
                            accountItemService.updateByUuid(accountItemUpdate);
                        }

                        // 钱进到锁定金额中
                        accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
                        accountUpdate = new Account();
                        accountUpdate.setReceipt(accountForUpdate.getReceipt().subtract(recPayForUpdate.getSumAmtRec()))
                                .setReceiptResidue(accountForUpdate.getReceiptResidue().subtract(recPayForUpdate.getSumAmtRec()))
                                .setReceiptLock(accountForUpdate.getReceiptLock().add(recPayForUpdate.getSumAmtRec()))
                                .setObjectId(objectId);
                        super.updateByUuid(accountUpdate);
                    }
                }
            }

            accountItemForUpdate = accountItemMapper.selectByIdForUpdate(outbound.getReceivableId());
            // 如果核销金额不为0，说明当前单据已核销
            if (accountItemForUpdate.getAmtHandle().compareTo(BigDecimal.ZERO) != 0) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISHANDLE.getMessage());
            }

            // 将源单上的账款明细Id更为null
            LambdaUpdateWrapper<Outbound> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(Outbound::getReceivableId, null).eq(Outbound::getOutId, UUID.fromString(invoiceId));
            outboundMapper.update(null, updateWrapper);

            // 删除账款明细
            accountItemMapper.deleteById(accountItemForUpdate.getItemId());

            // 更新账款总表上的总应收账款和总剩余应收
            accountForUpdate = getCusAccountForUpdate(objectId);
            accountUpdate = new Account();
            accountUpdate.setReceivable(accountForUpdate.getReceivable().subtract(accountItemForUpdate.getAmtShould()))
                    .setReceivableResidue(accountForUpdate.getReceivableResidue().subtract(accountItemForUpdate.getAmtShould()))
                    .setObjectId(objectId);
            super.updateByUuid(accountUpdate);
        }
        // 其他收入单
        else if ("t_mac_other_receivable".equals(biznisType)) {
            OtherReceivable otherReceivable = otherReceivableMapper.selectByIdForUpdate(invoiceId);
            objectId = otherReceivable.getObjectId();

            // 当前单据已经记账
            if (otherReceivable.getAccItemId() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISREVERSE.getMessage());
            }

            accountItemForUpdate = accountItemMapper.selectByIdForUpdate(otherReceivable.getAccItemId());
            // 如果核销金额不为0，说明当前单据已核销
            if (accountItemForUpdate.getAmtHandle().compareTo(BigDecimal.ZERO) != 0) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISHANDLE.getMessage());
            }

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<OtherReceivable> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(OtherReceivable::getAccItemId, null).eq(OtherReceivable::getReceivableId, UUID.fromString(invoiceId));
            otherReceivableMapper.update(null, updateWrapper);

            // 删除账款明细
            accountItemMapper.deleteById(accountItemForUpdate.getItemId());

            // 更新账款总表上的总应收账款和总剩余应收
            Account accountForUpdate = getCusAccountForUpdate(objectId);
            Account accountUpdate = new Account();
            accountUpdate.setReceivable(accountForUpdate.getReceivable().subtract(accountItemForUpdate.getAmtShould()))
                    .setReceivableResidue(accountForUpdate.getReceivableResidue().subtract(accountItemForUpdate.getAmtShould()))
                    .setObjectId(objectId);
            super.updateByUuid(accountUpdate);
        }
    }

    /**
     * @desc : 应付记账
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void accPayable(String invoiceId, String biznisType) {
        // 账款明细
        AccountItem accountItemInsert = new AccountItem();
        // 账务对象Id
        String objectId = null;

        if ("t_psi_inbound".equals(biznisType)) {
            Inbound inbound = inboundMapper.selectByIdForUpdate(invoiceId);
            objectId = inbound.getSupId();

            // 当前单据已经记账
            if (inbound.getReceivableId() != null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISACC.getMessage());
            }
            // 账务日期不能为空
            if (inbound.getIntoDate() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.ACC_DATE_ISNULL.getMessage());
            }
            // 插入账款明细
            accountItemInsert.setAccItemType(Constant.accItemType.YING_FU.getName())
                    .setObjectId(objectId).setOrgId(inbound.getOrgId()).setStaffId(inbound.getStaffId())
                    .setAccDate(inbound.getIntoDate()).setRecStatus(Constant.recStatuse.QUE_DING.getName())
                    .setAmtShould(inbound.getIntoAmt()).setAmtResidue(inbound.getIntoAmt())
                    .setBiznisType(biznisType).setBiznisId(inbound.getIntoId()).setBiznisNo(inbound.getIntoNo())
                    .setMakeStaff(inbound.getMakeStaff()).setCpId(inbound.getCpId());
            accountItemMapper.insert(accountItemInsert);

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<Inbound> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(Inbound::getReceivableId, UUID.fromString(accountItemInsert.getItemId())).eq(Inbound::getIntoId, UUID.fromString(invoiceId));
            inboundMapper.update(null, updateWrapper);
        }
        // 其他支出单
        else if ("t_mac_other_payable".equals(biznisType)) {
            OtherPayable otherPayable = otherPayableMapper.selectByIdForUpdate(invoiceId);
            objectId = otherPayable.getObjectId();

            // 当前单据已经记账
            if (otherPayable.getAccItemId() != null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISACC.getMessage());
            }
            // 账务日期不能为空
            if (otherPayable.getAccDate() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.ACC_DATE_ISNULL.getMessage());
            }

            // 插入账款明细
            accountItemInsert.setAccItemType(Constant.accItemType.YING_SHOU.getName())
                    .setObjectId(objectId).setOrgId(otherPayable.getOrgId()).setStaffId(otherPayable.getStaffId())
                    .setAccDate(otherPayable.getAccDate()).setRecStatus(Constant.recStatuse.QUE_DING.getName())
                    .setAmtShould(otherPayable.getSumAmtPayable()).setAmtResidue(otherPayable.getSumAmtPayable())
                    .setBiznisType(biznisType).setBiznisId(otherPayable.getPayableId()).setBiznisNo(otherPayable.getPayableNo())
                    .setMakeStaff(otherPayable.getMakeStaff()).setCpId(otherPayable.getCpId());
            accountItemMapper.insert(accountItemInsert);

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<OtherPayable> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(OtherPayable::getAccItemId, UUID.fromString(accountItemInsert.getItemId())).eq(OtherPayable::getPayableId, UUID.fromString(invoiceId));
            otherPayableMapper.update(null, updateWrapper);
        }

        // 更新账款总表上的总应收账款和总剩余应收
        Account accountForUpdate = getSupAccountForUpdate(objectId);
        Account accountUpdate = new Account();
        accountUpdate.setPayable(accountForUpdate.getPayable().add(accountItemInsert.getAmtShould()))
                .setPayableResidue(accountForUpdate.getPayableResidue().add(accountItemInsert.getAmtShould()))
                .setObjectId(objectId);
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 应付反记账
     * @author : 付斌
     * @date : 2024-03-22 11:08
     */
    public void reversePayable(String invoiceId, String biznisType) {
        // 更新账款明细应收收款
        AccountItem accountItemForUpdate = null;
        // 账务对象Id
        String objectId = null;

        if ("t_psi_inbound".equals(biznisType)) {
            Inbound inbound = inboundMapper.selectByIdForUpdate(invoiceId);
            objectId = inbound.getSupId();

            // 当前单据已经记账
            if (inbound.getReceivableId() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISREVERSE.getMessage());
            }

            accountItemForUpdate = accountItemMapper.selectByIdForUpdate(inbound.getReceivableId());
            // 如果核销金额不为0，说明当前单据已核销
            if (accountItemForUpdate.getAmtHandle().compareTo(BigDecimal.ZERO) != 0) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISHANDLE.getMessage());
            }

            // 将入库单上的账款明细Id更为null
            LambdaUpdateWrapper<Inbound> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(Inbound::getReceivableId, null).eq(Inbound::getIntoId, UUID.fromString(invoiceId));
            inboundMapper.update(null, updateWrapper);
        }
        // 其他支出单
        else if ("t_mac_other_payable".equals(biznisType)) {
            OtherPayable otherPayable = otherPayableMapper.selectByIdForUpdate(invoiceId);
            objectId = otherPayable.getObjectId();

            // 当前单据已经记账
            if (otherPayable.getAccItemId() == null) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISREVERSE.getMessage());
            }

            accountItemForUpdate = accountItemMapper.selectByIdForUpdate(otherPayable.getAccItemId());
            // 如果核销金额不为0，说明当前单据已核销
            if (accountItemForUpdate.getAmtHandle().compareTo(BigDecimal.ZERO) != 0) {
                throw new BaseBusinessException(ResponseCodeEnum.OPERATE_FAIL.getCode(), ErrorCodeEnum.CURRENT_INVOICE_ISHANDLE.getMessage());
            }

            // 更新源单上的账款明细Id
            LambdaUpdateWrapper<OtherPayable> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(OtherPayable::getAccItemId, null).eq(OtherPayable::getPayableId, UUID.fromString(invoiceId));
            otherPayableMapper.update(null, updateWrapper);
        }

        // 删除账款明细
        accountItemMapper.deleteById(accountItemForUpdate.getItemId());

        // 更新账款总表上的总应收账款和总剩余应收
        Account accountForUpdate = getSupAccountForUpdate(objectId);
        Account accountUpdate = new Account();
        accountUpdate.setPayable(accountForUpdate.getPayable().subtract(accountItemForUpdate.getAmtShould()))
                .setPayableResidue(accountForUpdate.getPayableResidue().subtract(accountItemForUpdate.getAmtShould()))
                .setObjectId(objectId);
        super.updateByUuid(accountUpdate);
    }

    /**
     * @desc : 获取应收，收款汇总（制单员权限）
     * @author : 周兴
     * @date : 2024-04-03 16:32
     */
    public ResponseResultVO<?> getReceivableAccountSum(AccountItemQuery accountItemQuery) {
        Map<String, Object> receivableAccountMap = accountItemMapper.getReceivableAccountSum(accountItemQuery);
        return ResponseResultUtil.success(receivableAccountMap);
    }

    /*********************  账款部分共通方法 end **********************/


    /*********************  账款部分私有方法 begin **********************/
    /**
     * @desc : 获取账款总表，没有则新建(私有方法)
     * @author : 付斌
     * @date : 2024-03-23 16:32
     */
    private Account getAccountForUpdate(String objectId, String objectType) {
        // 查询账款总表
        Account accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
        // 没有账款对象，需要新建
        if (accountForUpdate == null) {
            accountForUpdate = new Account();
            accountForUpdate.setObjectId(objectId).setObjectType(objectType);
            accountMapper.insert(accountForUpdate);
            accountForUpdate = accountMapper.selectByIdForUpdate(objectId);
        }
        return accountForUpdate;
    }
    /*********************  账款部分私有方法 end **********************/
}
