|  | # Copyright 2016 上海开阖软件有限公司 (http://www.osbzr.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
from odoo.exceptions import UserError
class MoneyInvoice(models.Model):
    _inherit = 'money.invoice'
    voucher_id = fields.Many2one(
        'voucher',
        '对应凭证',
        readonly=True,
        ondelete='restrict',
        copy=False,
        help='结算单确认时生成的对应凭证')
    cogs_voucher_id = fields.Many2one(
        'voucher',
        '成本凭证',
        readonly=True,
        ondelete='set null',
        copy=False,
        help='结算单确认时生成的成本凭证')
    def money_invoice_draft(self):
        """
        撤销确认结算单时,撤销确认凭证
        """
        res = super(MoneyInvoice, self).money_invoice_draft()
        for invoice in self:
            voucher, invoice.voucher_id = invoice.voucher_id, False
            if voucher.state == 'done':
                voucher.voucher_draft()
            # 始初化单反审核只删除明细行:生成初始化凭证时,不生成往来单位对方的科目,所以要删除相关明细行
            if invoice.is_init:
                vouch_obj = self.env['voucher'].search(
                    [('id', '=', voucher.id)])
                vouch_obj_lines = self.env['voucher.line'].search([
                    ('voucher_id', '=', vouch_obj.id),
                    ('partner_id', '=', invoice.partner_id.id),
                    ('init_obj', '=', 'money_invoice'), ])
                for vouch_obj_line in vouch_obj_lines:
                    vouch_obj_line.unlink()
            else:   # 非初始化单反审核时删除凭证
                voucher.unlink()
            # 删除发出成本凭证
            cogs_voucher = self.env['voucher'].search(
                [('ref', '=', '%s,%s' % (self._name, invoice.id))])
            if cogs_voucher:
                if cogs_voucher.state == 'done':
                    cogs_voucher.voucher_draft()
                cogs_voucher.unlink()
        return res
    def money_invoice_done(self):
        """
        确认结算单时,创建凭证并确认
        """
        res = super(MoneyInvoice, self).money_invoice_done()
        vals = {}
        # 初始化单的话,先找是否有初始化凭证,没有则新建一个
        for invoice in self:
            if invoice.is_init:
                vouch_obj = self.env['voucher'].search(
                    [('is_init', '=', True)])
                if not vouch_obj:
                    vouch_obj = self.env['voucher'].create(
                        {'date': invoice.date,
                         'is_init': True,
                         'ref': '%s,%s' % (self._name, self.id)})
                invoice.write({'voucher_id': vouch_obj.id})
            else:
                vouch_obj = self.env['voucher'].create({
                    'date': invoice.invoice_date or
                    fields.Date.context_today(self),
                    'ref': '%s,%s' % (self._name, self.id)})
                invoice.write({'voucher_id': vouch_obj.id})
            if not invoice.category_id.account_id:
                raise UserError('请配置%s的会计科目' % (invoice.category_id.name))
            partner_cat = invoice.category_id.type == 'income' \
                and invoice.partner_id.c_category_id \
                or invoice.partner_id.s_category_id
            partner_account_id = partner_cat.account_id.id
            if not partner_account_id:
                raise UserError('请配置%s的会计科目' % (partner_cat.name))
            if invoice.category_id.type == 'income':
                vals.update({
                    'vouch_obj_id': vouch_obj.id,
                    'partner_credit': invoice.partner_id.id,
                    'name': invoice.name,
                    'string': invoice.note or '',
                    'amount': invoice.amount,
                    'credit_account_id': invoice.category_id.account_id.id,
                    'partner_debit': invoice.partner_id.id,
                    'debit_account_id': partner_account_id,
                    'sell_tax_amount': invoice.tax_amount or 0,
                    'credit_auxiliary_id': invoice.auxiliary_id.id,
                    'currency_id': invoice.currency_id.id or '',
                    'rate_silent': self.env['res.currency'].get_rate_silent(
                        self.date, invoice.currency_id.id) or 0,
                             })
                # 找到发票对应发货单的凭证,复制修改, 结转主营业务成本
                send_voucher = False
                if self.env['ir.module.module'].sudo().search(
                        [('name', '=', 'sell'), ('state', '=', 'installed')]):
                    delivery = self.env['sell.delivery'].search(
                        [('name', '=', invoice.name)])
                    send_voucher = delivery.voucher_id
                # 该公司不是月末一次性结转发出成本
                if send_voucher:
                    cost_voucher_data = send_voucher.copy_data()
                    out_account_id = self.env.ref(
                        'finance.categ_sell_goods').account_id.id
                    cogs_account_id = self.env.company.cogs_account.id
                    # 如果发货单没有直接结转成本
                    if out_account_id != cogs_account_id:
                        for vl in cost_voucher_data[0]['line_ids']:
                            if vl[2]['account_id'] != out_account_id:
                                vl[2].update({'account_id': cogs_account_id})
                            vl[2].update({
                                'debit': vl[2]['credit'],
                                'credit': vl[2]['debit'],
                                'voucher_id': False})
                        cost_voucher_data[0].update(
                            {'ref': '%s,%s' % (self._name, self.id)})
                        if invoice.invoice_date:
                            cost_voucher_data[0].update(
                                {'date': invoice.invoice_date})
                        cogs_voucher = self.env['voucher'].create(
                            cost_voucher_data)
                        cogs_voucher.voucher_done()
                        invoice.cogs_voucher_id = cogs_voucher.id
            else:
                vals.update({
                    'vouch_obj_id': vouch_obj.id,
                    'name': invoice.name,
                    'string': invoice.note or '',
                    'amount': invoice.amount,
                    'credit_account_id': partner_account_id,
                    'debit_account_id': invoice.category_id.account_id.id,
                    'partner_debit': invoice.partner_id.id,
                    'partner_credit': invoice.partner_id.id,
                    'buy_tax_amount': invoice.tax_amount or 0,
                    'debit_auxiliary_id': invoice.auxiliary_id.id,
                    'currency_id': invoice.currency_id.id or '',
                    'rate_silent': self.env['res.currency'].get_rate_silent(
                        self.date, invoice.currency_id.id) or 0,
                    })
            if invoice.is_init:
                vals.update({'init_obj': 'money_invoice', })
            invoice.create_voucher_line(vals)
            # 删除初始非需要的凭证明细行,不确认凭证
            if invoice.is_init:
                vouch_line_ids = self.env['voucher.line'].search([
                    ('account_id', '=', invoice.category_id.account_id.id),
                    ('init_obj', '=', 'money_invoice')])
                # 删除凭证明细行之前先确保凭证是草稿状态
                if invoice.voucher_id.state == 'done':
                    invoice.voucher_id.voucher_draft()
                for vouch_line_id in vouch_line_ids:
                    vouch_line_id.unlink()
            else:
                vouch_obj.voucher_done()
        return res
    def create_voucher_line(self, vals):
        if vals.get('currency_id') == self.env.user.company_id.currency_id.id \
                or not vals.get('rate_silent'):
            debit = credit = vals.get('amount')
            sell_tax_amount = vals.get('sell_tax_amount')
        else:
            # 外币免税
            debit = credit = vals.get('amount') * vals.get('rate_silent')
        # 把税从金额中减去
        if vals.get('buy_tax_amount'):  # 如果传入了进项税
            debit = vals.get('amount') - vals.get('buy_tax_amount')
        if vals.get('sell_tax_amount'):  # 如果传入了销项税
            credit = vals.get('amount') - sell_tax_amount
        # 借方行
        currency_id = vals.get(
            'currency_id') or self.env.user.company_id.currency_id.id
        if currency_id != self.env.user.company_id.currency_id.id:  # 结算单上是外币
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'account_id': vals.get('debit_account_id'),
                'debit': debit,
                'voucher_id': vals.get('vouch_obj_id'),
                'partner_id': vals.get('partner_debit', ''),
                'auxiliary_id': vals.get('debit_auxiliary_id', False),
                'currency_id': vals.get('currency_id'),
                'currency_amount': vals.get('amount'),
                'rate_silent': vals.get('rate_silent'),
                'init_obj': vals.get('init_obj', False),
            })
        else:   # 结算单上是本位币
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'account_id': vals.get('debit_account_id'),
                'debit': debit,
                'voucher_id': vals.get('vouch_obj_id'),
                'partner_id': vals.get('partner_debit', ''),
                'auxiliary_id': vals.get('debit_auxiliary_id', False),
                'init_obj': vals.get('init_obj', False),
            })
        # 进项税行
        if vals.get('buy_tax_amount'):
            if not self.env.user.company_id.import_tax_account:
                raise UserError('请通过"配置-->高级配置-->公司"菜单来设置进项税科目')
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'account_id': self.env.user.company_id.import_tax_account.id,
                'debit': vals.get('buy_tax_amount'),
                'voucher_id': vals.get('vouch_obj_id'),
            })
        # 贷方行
        currency_id = vals.get(
            'currency_id') or self.env.user.company_id.currency_id.id
        if currency_id != self.env.user.company_id.currency_id.id:
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'partner_id': vals.get('partner_credit', ''),
                'account_id': vals.get('credit_account_id'),
                'credit': credit,
                'voucher_id': vals.get('vouch_obj_id'),
                'auxiliary_id': vals.get('credit_auxiliary_id', False),
                'currency_amount': vals.get('amount'),
                'rate_silent': vals.get('rate_silent'),
                'currency_id': vals.get('currency_id'),
                'init_obj': vals.get('init_obj', False),
            })
        else:
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'partner_id': vals.get('partner_credit', ''),
                'account_id': vals.get('credit_account_id'),
                'credit': credit,
                'voucher_id': vals.get('vouch_obj_id'),
                'auxiliary_id': vals.get('credit_auxiliary_id', False),
                'init_obj': vals.get('init_obj', False),
            })
        # 销项税行
        if vals.get('sell_tax_amount'):
            if not self.env.user.company_id.output_tax_account:
                raise UserError(
                    '您还没有配置公司的销项税科目。\n请通过"配置-->高级配置-->公司"菜单来设置销项税科目!')
            self.env['voucher.line'].create({
                'name': "%s %s" % (vals.get('name'), vals.get('string')),
                'account_id': self.env.user.company_id.output_tax_account.id,
                'credit': sell_tax_amount,
                'voucher_id': vals.get('vouch_obj_id'),
            })
        return True
 |