Replaces Enterprise's documents_account with a Fusion-native bridge. When a PDF/image lands in the Documents app, users can convert it into a draft vendor bill via a wizard that copies the document's binary onto the new account.move and posts a chatter note linking back to the source document. Adds: - documents.document.move_id (Many2one to the linked invoice) - documents.document.is_invoice_candidate (computed; True for unlinked PDF/image binaries) - documents.document.action_create_invoice() opens the wizard - account.move.source_document_ids reverse linkage + statinfo button - fusion.create.invoice.from.document.wizard (TransientModel + form) - ir.actions.server bound to documents.document so the workflow appears in the kanban/list Actions menu (the Documents app has no regular form view to inherit from in v19) The wizard: - defaults to the company's first purchase journal - supports vendor bill or vendor credit note - copies the source attachment onto the new move - posts a chatter note linking back - marks the document linked so it stops appearing as a candidate Auto-installs when documents + fusion_accounting_core are both present. 8 unit tests cover the candidate flag, wizard happy path, attachment copy, reverse linkage, already-linked guard, non-PDF guard, and credit-note creation. Made-with: Cursor
72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
"""Bridge documents.document to accounting moves.
|
|
|
|
Adds a Many2one link to the created invoice/move, a computed
|
|
``is_invoice_candidate`` flag for PDFs/images that have not yet been
|
|
turned into a vendor bill, and the ``action_create_invoice`` entry
|
|
point used by both the form button and the server action.
|
|
"""
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
INVOICE_CANDIDATE_MIMETYPES = (
|
|
'application/pdf',
|
|
'image/png',
|
|
'image/jpeg',
|
|
'image/jpg',
|
|
)
|
|
|
|
|
|
class DocumentsDocument(models.Model):
|
|
_inherit = 'documents.document'
|
|
|
|
move_id = fields.Many2one(
|
|
'account.move',
|
|
string='Linked Invoice/Move',
|
|
copy=False,
|
|
ondelete='set null',
|
|
help="The accounting move this document was used to create.",
|
|
)
|
|
is_invoice_candidate = fields.Boolean(
|
|
string='Is Invoice Candidate',
|
|
compute='_compute_is_invoice_candidate',
|
|
store=True,
|
|
help="True when this document looks like a vendor bill "
|
|
"(PDF/image binary) and has not yet been linked to a move.",
|
|
)
|
|
|
|
@api.depends('mimetype', 'type', 'move_id')
|
|
def _compute_is_invoice_candidate(self):
|
|
for d in self:
|
|
d.is_invoice_candidate = (
|
|
d.type == 'binary'
|
|
and (d.mimetype or '') in INVOICE_CANDIDATE_MIMETYPES
|
|
and not d.move_id
|
|
)
|
|
|
|
def action_create_invoice(self):
|
|
"""Open the wizard to create a vendor invoice from this document."""
|
|
self.ensure_one()
|
|
if self.move_id:
|
|
raise UserError(_(
|
|
"This document is already linked to invoice %s.",
|
|
self.move_id.display_name,
|
|
))
|
|
if self.type == 'folder':
|
|
raise UserError(_(
|
|
"Folders cannot be turned into invoices."
|
|
))
|
|
if (self.mimetype or '') not in INVOICE_CANDIDATE_MIMETYPES:
|
|
raise UserError(_(
|
|
"Only PDF or image documents can be turned into invoices."
|
|
))
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'name': _('Create Invoice from Document'),
|
|
'res_model': 'fusion.create.invoice.from.document.wizard',
|
|
'view_mode': 'form',
|
|
'target': 'new',
|
|
'context': {'default_document_id': self.id},
|
|
}
|