account_debit_note.py 4.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. # -*- coding: utf-8 -*-
  2. from odoo import models, fields, api
  3. from odoo.tools.translate import _
  4. from odoo.exceptions import UserError
  5. class AccountDebitNote(models.TransientModel):
  6. """
  7. Add Debit Note wizard: when you want to correct an invoice with a positive amount.
  8. Opposite of a Credit Note, but different from a regular invoice as you need the link to the original invoice.
  9. In some cases, also used to cancel Credit Notes
  10. """
  11. _name = 'account.debit.note'
  12. _description = 'Add Debit Note wizard'
  13. move_ids = fields.Many2many('account.move', 'account_move_debit_move', 'debit_id', 'move_id',
  14. domain=[('state', '=', 'posted')])
  15. date = fields.Date(string='Debit Note Date', default=fields.Date.context_today, required=True)
  16. reason = fields.Char(string='Reason')
  17. journal_id = fields.Many2one('account.journal', string='Use Specific Journal',
  18. help='If empty, uses the journal of the journal entry to be debited.')
  19. copy_lines = fields.Boolean("Copy Lines",
  20. help="In case you need to do corrections for every line, it can be in handy to copy them. "
  21. "We won't copy them for debit notes from credit notes. ")
  22. # computed fields
  23. move_type = fields.Char(compute="_compute_from_moves")
  24. journal_type = fields.Char(compute="_compute_from_moves")
  25. country_code = fields.Char(related='move_ids.company_id.country_id.code')
  26. @api.model
  27. def default_get(self, fields):
  28. res = super(AccountDebitNote, self).default_get(fields)
  29. move_ids = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.env['account.move']
  30. if any(move.state != "posted" for move in move_ids):
  31. raise UserError(_('You can only debit posted moves.'))
  32. res['move_ids'] = [(6, 0, move_ids.ids)]
  33. return res
  34. @api.depends('move_ids')
  35. def _compute_from_moves(self):
  36. for record in self:
  37. move_ids = record.move_ids
  38. record.move_type = move_ids[0].move_type if len(move_ids) == 1 or not any(m.move_type != move_ids[0].move_type for m in move_ids) else False
  39. record.journal_type = record.move_type in ['in_refund', 'in_invoice'] and 'purchase' or 'sale'
  40. def _prepare_default_values(self, move):
  41. if move.move_type in ('in_refund', 'out_refund'):
  42. type = 'in_invoice' if move.move_type == 'in_refund' else 'out_invoice'
  43. else:
  44. type = move.move_type
  45. default_values = {
  46. 'ref': '%s, %s' % (move.name, self.reason) if self.reason else move.name,
  47. 'date': self.date or move.date,
  48. 'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False,
  49. 'journal_id': self.journal_id and self.journal_id.id or move.journal_id.id,
  50. 'invoice_payment_term_id': None,
  51. 'debit_origin_id': move.id,
  52. 'move_type': type,
  53. }
  54. if not self.copy_lines or move.move_type in [('in_refund', 'out_refund')]:
  55. default_values['line_ids'] = [(5, 0, 0)]
  56. return default_values
  57. def create_debit(self):
  58. self.ensure_one()
  59. new_moves = self.env['account.move']
  60. for move in self.move_ids.with_context(include_business_fields=True): #copy sale/purchase links
  61. default_values = self._prepare_default_values(move)
  62. new_move = move.copy(default=default_values)
  63. move_msg = _(
  64. "This debit note was created from: %s",
  65. move._get_html_link(),
  66. )
  67. new_move.message_post(body=move_msg)
  68. new_moves |= new_move
  69. action = {
  70. 'name': _('Debit Notes'),
  71. 'type': 'ir.actions.act_window',
  72. 'res_model': 'account.move',
  73. 'context': {'default_move_type': default_values['move_type']},
  74. }
  75. if len(new_moves) == 1:
  76. action.update({
  77. 'view_mode': 'form',
  78. 'res_id': new_moves.id,
  79. })
  80. else:
  81. action.update({
  82. 'view_mode': 'tree,form',
  83. 'domain': [('id', 'in', new_moves.ids)],
  84. })
  85. return action