# -*- coding: utf-8 -*-
# 项目: jdg-hd-node-farm
# Copyright 2018 JDG <www.yunside.com>
# Created by LLH <lianghua.liu@yunside.com> at 2018/8/9

from odoo import models, fields, api
from odoo.exceptions import ValidationError
import logging

_logger = logging.getLogger(__name__)

BRANCH_ORDER = [
    'hd.fin.finance.invoice',
    'hd.fin.balance.tran.customer',
    'hd.fin.balance.allocate.customer',
    'hd.fin.account.type.tran.customer',
    'hd.sal.customer.rebate.record',
    'hd.sal.customer.rebate',

    'hd.bd.fin.finance.invoice',
    'hd.bd.mrk.rebate.provision.customer',
    'hd.bd.mrk.rebate.customer',
    'hd.bd.mrk.rebate.provision.supplier',
    'hd.bd.mrk.rebate.supplier',
]


class VoucherRecord(models.Model):
    """
    凭证记录
    每一次有效凭证对应一条凭证记录
    """
    _name = 'jd.int.voucher.record'
    _description = u'凭证推送记录'

    number = fields.Char(string=u'编码', required=True, default='/', help=u'自动编码')
    date = fields.Date(string=u'日期', default=fields.Date.context_today)
    uid_push = fields.Many2one('res.users', string=u'推送人')
    line_ids = fields.One2many('jd.int.voucher.record.line', 'record_id', string=u'凭证推送明细')
    data_line_ids = fields.One2many('jd.int.voucher.record.data', 'parent_id',
                                    string=u'凭证明细', readonly=True)
    note = fields.Text(string=u'备注')
    res_order = fields.Reference(string=u'来源单据', selection='_reference_models', readonly=True)
    name = fields.Char(string=u'来源单据名称', readonly=True)
    voucher_code = fields.Char(string=u'凭证编号', related='data_line_ids.voucher_code')
    voucher_revoke_code = fields.Char(string=u'撤销凭证编号', related='data_line_ids.voucher_revoke_code')

    @api.model
    def _reference_models(self):
        models = self.env['ir.model'].search([('state', '!=', 'manual')])
        return [(model.model, model.name)
                for model in models
                if not model.model.startswith('ir.')]

    @api.multi
    def name_get(self):
        result = []
        for o in self:
            result.append((o.id, "%s(%s)" % (o.voucher_id.name, o.number)))
        return result

    @api.model
    def create(self, values):
        """
        获取自动单号
        :param values:
        :return:
        """
        if values.get('number', '/') == '/':
            values.update({
                'number': self.env['ir.sequence'].next_by_code(self._name)
            })
        return super(VoucherRecord, self).create(values)

    @api.model
    def order_search(self, res_order):
        """
        根据传入的voucher_id和res_order
        判断该voucher_id和res_order是否已有凭证记录
        :param res_order: model_name,id
        :return: record or False
        """
        if not res_order:
            return False
        cr = self.env.cr
        sql = '''
        SELECT vr.id AS record_id
        FROM jd_int_voucher_record vr
        WHERE vr.res_order = %(res_order)s
        ORDER BY vr.id DESC
        LIMIT 1
        '''
        cr.execute(sql, {'res_order': res_order})
        rec = cr.dictfetchone()
        if rec and rec.get('record_id'):
            record_rec = self.browse(int(rec.get('record_id')))
            return record_rec
        else:
            return False

    @api.multi
    def create_data_line(self, bkpf_data, bseg_data):
        self.ensure_one()
        item = self[0]
        # 增加凭证推送数据明细
        data_ids = []
        for bkpf in bkpf_data:
            data_line_ids = {
                'recordKey': bkpf['recordKey'],
                'bukrs': bkpf['bukrs'],
                'bldat': bkpf['bldat'],
                'budat': bkpf['budat'],
                'blart': bkpf['blart'],
                'waers': bkpf['waers'],
                'bktxt': bkpf['bktxt'],
                'xref1_hd': bkpf['xref1_hd'],
                'xref2_hd': bkpf['xref2_hd'],
                'numpg': bkpf['numpg'],
                'xnegp': bkpf['xnegp'],
                'monat': bkpf['monat'],
                'wwert': bkpf['wwert'],
                'kursf': bkpf['kursf'],
                'state': 'draft'
            }
            data_line_line_ids = []
            for bseg in bseg_data:
                if bseg['recordKey'] == bkpf['recordKey']:
                    hkont_name = self.env['jd.int.sap.account.item'].sudo().search(
                        [('number', '=', bseg['hkont'])]).name
                    data_line_line_ids.append((0, 0, {
                        'recordKey': bseg['recordKey'],
                        # 'bschl': bseg['bschl'],
                        'hkont': bseg['hkont'] if bseg['hkont'] else bseg.get('jdg_hkont', ''),
                        'hkont_name': hkont_name,
                        'wrbtr': bseg['wrbtr'],
                        'dmbtr': bseg['dmbtr'],
                        'lifnr': bseg['lifnr'],
                        'prctr': bseg['prctr'],
                        'fkber': bseg['fkber'],
                        'umskz': bseg['umskz'],
                        'rstgr': bseg['rstgr'],
                        'zfbdt': bseg['zfbdt'],
                        'kunnr': bseg['kunnr'],
                        'kostl': bseg['kostl'],
                        'zuonr': bseg['zuonr'],
                        'docln': bseg['docln'],
                        'koart': bseg['koart'],
                        'drcrk': bseg['drcrk'],
                        'sgtxt': bseg['sgtxt'],
                        'zz_item3': bseg['zz_item3'],
                        'rbusa': bseg['rbusa'],
                        'aufur': bseg.get('aufur'),
                        'mwskz': bseg['mwskz'],
                        'rassc': bseg['rassc'],
                        'zz_item1': bseg['zz_item1'],
                        'zz_item2': bseg['zz_item2'],
                        'xnegp': bseg['xnegp'],
                    }))
            data_line_ids.update({
                'line_ids': data_line_line_ids
            })
            data_ids.append((0, 0, data_line_ids))
        item.write({
            'data_line_ids': data_ids
        })
        max_line = None
        for line in item.data_line_ids:
            if not max_line or line.id > max_line.id:
                max_line = line
        return max_line


class VoucherRecordLine(models.Model):
    """
    凭证记录 凭证明细
    仅一条有效凭证明细
    """
    _name = 'jd.int.voucher.record.line'
    _description = u'凭证推送记录凭证明细'

    voucher_id = fields.Many2one('jd.int.voucher', string=u'凭证定义', required=True)
    record_id = fields.Many2one('jd.int.voucher.record', string=u'凭证记录', ondelete='cascade')
    voucher_code = fields.Char(string=u'凭证编码', required=True)
    time_push = fields.Datetime(string=u'推送时间', required=True)
    time_revoke = fields.Datetime(string=u'撤销时间')
    revoke_code = fields.Char(string=u'撤销凭证编码')
    bukrs = fields.Char(string=u'公司代码', required=True)
    gjahr = fields.Char(string=u'会计年度', required=True)
    item = fields.Char(string=u'行号', required=True)
    state = fields.Selection([('active', u'有效'),
                              ('revoked', u'已撤销')], string=u'状态')
    note = fields.Text(string=u'备注')


class VoucherRecordData(models.Model):
    _name = 'jd.int.voucher.record.data'
    _description = u'凭证推送记录数据明细'

    parent_id = fields.Many2one('jd.int.voucher.record', string=u'凭证推送记录', ondelete='cascade')
    state = fields.Selection([('draft', u'尚未推送'),
                              ('success', u'推送成功'),
                              ('failed', u'推送失败'),
                              ('revoked', u'已撤销')], string=u'推送状态', readonly=True)
    failed_reason = fields.Char(string=u'凭证失败原因', readonly=True)
    voucher_code = fields.Char(string=u'凭证编号', readonly=True)
    voucher_revoke_code = fields.Char(string=u'撤销凭证编号', readonly=True)
    voucher_bukrs = fields.Char(string=u'凭证公司代码', readonly=True)
    voucher_gjahr = fields.Char(string=u'凭证会计年度', readonly=True)
    time_revoke = fields.Datetime(string=u'撤销时间', readonly=True)
    # 凭证抬头
    recordKey = fields.Char(string=u'recordKey', readonly=True)
    bukrs = fields.Char(string=u'公司代码', readonly=True)
    bldat = fields.Char(string=u'记账日期', readonly=True)
    budat = fields.Char(string=u'凭证日期', readonly=True)
    blart = fields.Char(string=u'凭证类型', readonly=True)
    waers = fields.Char(string=u'币种', readonly=True)
    bktxt = fields.Char(string=u'凭证抬头文本', readonly=True)
    xref1_hd = fields.Char(string=u'凭证标题的内部参考码1', readonly=True)
    xref2_hd = fields.Char(string=u'凭证标题的内部参考码2', readonly=True)
    numpg = fields.Char(string=u'附件数', readonly=True)
    xnegp = fields.Char(string=u'反记账', readonly=True)
    monat = fields.Char(string=u'期间', readonly=True)
    wwert = fields.Char(string=u'换算日期', readonly=True)
    kursf = fields.Char(string=u'汇率', readonly=True)
    line_ids = fields.One2many('jd.int.voucher.record.data.line', 'parent_id', string=u'数据行项目明细')

    @api.model
    def search_recordKey(self, recordKey):
        cr = self.env.cr
        sql = """
        SELECT vd.id AS record_id
        FROM jd_int_voucher_record_data vd
        WHERE vd."recordKey" = %(recordKey)s
        ORDER BY vd.id DESC
        LIMIT 1
        """
        params = {
            'recordKey': recordKey
        }
        cr.execute(sql, params)
        rec = cr.dictfetchone()
        if rec and rec.get('record_id'):
            record = self.browse(int(rec.get('record_id')))
            return record
        else:
            return None

    @api.model
    def search_voucher_code(self, voucher_code, bukrs):
        cr = self.env.cr
        sql = """
            SELECT vd.id AS record_id
            FROM jd_int_voucher_record_data vd
            WHERE vd.voucher_code = %(voucher_code)s
              AND vd.bukrs = %(bukrs)s
            ORDER BY vd.id DESC
            LIMIT 1
            """
        params = {
            'voucher_code': str(voucher_code),
            'bukrs': str(bukrs)
        }
        cr.execute(sql, params)
        rec = cr.dictfetchone()
        if rec and rec.get('record_id'):
            record = self.browse(int(rec.get('record_id')))
            return record
        else:
            return None

    @api.model
    def get_assist_account_by_number(self, number):
        """
        根据辅助核算信息，需在业务层重写获取逻辑
        :param number:
        :return:
        """
        assist_account = None
        return assist_account

    @api.multi
    def push_balance_io(self):
        """
        创建凭证科目明细账
        :return:
        """
        for item in self:
            if item.state == 'success':
                res_order = item.parent_id.res_order
                company_id = self.env.user.company_id
                if res_order:
                    if res_order._name in BRANCH_ORDER:
                        if hasattr(res_order, 'svc_org_id') and res_order.svc_org_id:
                            company_id = res_order.svc_org_id.sudo().org_unit_id
                        if hasattr(res_order, 'breeding_farm_id') and res_order.breeding_farm_id:
                            company_id = res_order.breeding_farm_id.sudo().org_unit_id
                    else:
                        company_id = res_order.company_id
                if company_id.org_type == 'branch':
                    _logger.error(u'单据【%s】生成凭证科目明细账时，获取到的组织【%s】是分公司！' %
                                  (res_order, company_id.name))
                    continue
                date = res_order.date if res_order else fields.Date.context_today(self)
                for line in item.line_ids:
                    amount = round(float(line.wrbtr or 0), 2)
                    if not amount:
                        continue
                    account_item_id = self.env['jd.int.sap.account.item'].sudo().search_account_item(line.hkont)
                    if not account_item_id:
                        raise ValidationError(u'未查找到编码为【%s】的凭证科目' % line.hkont)
                    # 根据客户号或供应商号获取 辅助编码
                    number_assist = line.kunnr or line.lifnr
                    assist_type = ''
                    if line.kunnr:
                        assist_type = '客户'
                    elif line.lifnr:
                        assist_type = '供应商'
                    assist_account = self.get_assist_account_by_number(number_assist, assist_type)
                    params = {
                        'company_id': company_id,
                        'date': date,
                        'account_item_id': account_item_id,
                        'direction': 'debit' if line.drcrk == 'S' else 'credit',
                        'origin': '%s,%s' % (item.parent_id._name, item.parent_id.id),
                        'amount': amount,
                        'voucher_code': item.voucher_code,
                        'number_assist': number_assist,
                        'assist_account': assist_account,
                    }
                    self.env['jd.init.balance.io.account.item'].jdg_sudo().make_a_deal(params)

    @api.multi
    def revoke_balance_io(self):
        """
        撤销凭证科目明细账
        :return:
        """
        for item in self:
            if item.state == 'revoked':
                res_order = item.parent_id.res_order
                company_id = self.env.user.company_id
                if res_order:
                    if res_order._name in BRANCH_ORDER:
                        if hasattr(res_order, 'svc_org_id') and res_order.svc_org_id:
                            company_id = res_order.svc_org_id.sudo().org_unit_id
                        if hasattr(res_order, 'breeding_farm_id') and res_order.breeding_farm_id:
                            company_id = res_order.breeding_farm_id.sudo().org_unit_id
                    else:
                        company_id = res_order.company_id
                if company_id.org_type == 'branch':
                    _logger.error(u'单据【%s】生成凭证科目明细账时，获取到的组织【%s】是分公司！' %
                                  (res_order, company_id.name))
                    continue
                date = res_order.date if res_order else fields.Date.context_today(self)
                for line in item.line_ids:
                    amount = round(float(line.wrbtr or 0), 2)
                    if not amount:
                        continue
                    account_item_id = self.env['jd.int.sap.account.item'].sudo().search_account_item(line.hkont)
                    if not account_item_id:
                        raise ValidationError(u'未查找到编码为【%s】的凭证科目' % line.hkont)
                    # 根据客户号或供应商号获取 辅助编码
                    number_assist = line.kunnr or line.lifnr
                    assist_type = ''
                    if line.kunnr:
                        assist_type = '客户'
                    elif line.lifnr:
                        assist_type = '供应商'
                    assist_account = self.get_assist_account_by_number(number_assist, assist_type)
                    params = {
                        'company_id': company_id,
                        'date': date,
                        'account_item_id': account_item_id,
                        'direction': 'debit' if line.drcrk == 'H' else 'credit',  # 撤销的借贷方向要相反
                        'origin': '%s,%s' % (item.parent_id._name, item.parent_id.id),
                        'amount': amount,
                        'voucher_code': item.voucher_revoke_code,  # 撤销凭证时，凭证编号为当前撤销的凭证编号
                        'voucher_revoke_code': item.voucher_code,  # 撤销凭证时，冲销凭证编号为 来源的凭证编号
                        'number_assist': number_assist,
                        'assist_account': assist_account,
                    }
                    self.env['jd.init.balance.io.account.item'].jdg_sudo().make_a_deal(params)


class VoucherRecordDataLine(models.Model):
    _name = 'jd.int.voucher.record.data.line'
    _description = u'凭证推送记录数据行项目明细'

    parent_id = fields.Many2one('jd.int.voucher.record.data', string=u'凭证推送记录数据明细', ondelete='cascade')
    # 凭证行项目明细
    recordKey = fields.Char(string=u'recordKey', readonly=True)
    docln = fields.Char(string=u'行项目号', readonly=True)
    koart = fields.Char(string=u'账户类型', readonly=True)
    drcrk = fields.Char(string=u'借贷', readonly=True)
    lifnr = fields.Char(string=u'供应商号', readonly=True)
    kunnr = fields.Char(string=u'客户号', readonly=True)
    hkont = fields.Char(string=u'总账科目', readonly=True)
    hkont_name = fields.Char(string=u'总账科目长文本', readonly=True)
    umskz = fields.Char(string=u'特别总账标示', readonly=True)
    wrbtr = fields.Char(string=u'金额', readonly=True)
    dmbtr = fields.Char(string=u'金额', readonly=True)
    zuonr = fields.Char(string=u'分配', readonly=True)
    sgtxt = fields.Char(string=u'行项目文本', readonly=True)
    zz_item3 = fields.Char(string=u'账号助记码', readonly=True)
    rbusa = fields.Char(string=u'业务范围', readonly=True)
    kostl = fields.Char(string=u'成本中心', readonly=True)
    aufur = fields.Char(string=u'内部订单', readonly=True)
    prctr = fields.Char(string=u'利润中心', readonly=True)
    mwskz = fields.Char(string=u'税码', readonly=True)
    zfbdt = fields.Char(string=u'基准日期', readonly=True)
    rstgr = fields.Char(string=u'付款原因代码', readonly=True)
    rassc = fields.Char(string=u'贸易伙伴', readonly=True)
    fkber = fields.Char(string=u'功能范围', readonly=True)
    zz_item1 = fields.Char(string=u'费用项目', readonly=True)
    zz_item2 = fields.Char(string=u'保证金类别', readonly=True)
    xnegp = fields.Char(string=u'反记账', readonly=True)
